File size: 3,561 Bytes
48ca417
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use bevy::{
    asset::{ AssetServer, Assets, Handle },
    ecs::{ component::Component, system::Query },
    math::{ IVec2, Vec2 },
    render::texture::Image,
    sprite::TextureAtlasLayout,
    transform::components::Transform,
};
use bevy_ecs_ldtk::{
    ldtk::{ LayerInstance, TilesetDefinition },
    utils::ldtk_pixel_coords_to_translation_pivoted,
    EntityInstance,
    prelude::LdtkEntity,
    prelude::LdtkFields,
};
use bevy_rapier2d::dynamics::Velocity;

#[derive(Clone, PartialEq, Debug, Default, Component)]
pub struct PredefinedPath {
    pub points: Vec<Vec2>,
    pub index: usize,
    pub forward: bool,
}

impl LdtkEntity for PredefinedPath {
    fn bundle_entity(
        entity_instance: &EntityInstance,
        layer_instance: &LayerInstance,
        _: Option<&Handle<Image>>,
        _: Option<&TilesetDefinition>,
        _: &AssetServer,
        _: &mut Assets<TextureAtlasLayout>
    ) -> PredefinedPath {
        let mut points = Vec::new();
        points.push(
            ldtk_pixel_coords_to_translation_pivoted(
                entity_instance.px,
                layer_instance.c_hei * layer_instance.grid_size,
                IVec2::new(entity_instance.width, entity_instance.height),
                entity_instance.pivot
            )
        );

        let ldtk_path_points = entity_instance
            .iter_points_field("path")
            .expect("path field should be correctly typed");

        for ldtk_point in ldtk_path_points {
            // The +1 is necessary here due to the pivot of the entities in the sample
            // file.
            // The paths set up in the file look flat and grounded,
            // but technically they're not if you consider the pivot,
            // which is at the bottom-center for the skulls.
            let pixel_coords =
                (ldtk_point.as_vec2() + Vec2::new(0.5, 1.0)) *
                Vec2::splat(layer_instance.grid_size as f32);

            points.push(
                ldtk_pixel_coords_to_translation_pivoted(
                    pixel_coords.as_ivec2(),
                    layer_instance.c_hei * layer_instance.grid_size,
                    IVec2::new(entity_instance.width, entity_instance.height),
                    entity_instance.pivot
                )
            );
        }

        PredefinedPath {
            points,
            index: 1,
            forward: true,
        }
    }
}

pub fn move_on_path(mut query: Query<(&mut Transform, &mut Velocity, &mut PredefinedPath)>) {
    for (mut transform, mut velocity, mut path) in &mut query {
        if path.points.len() <= 1 {
            continue;
        }

        let mut new_velocity =
            (path.points[path.index] - transform.translation.truncate()).normalize() * 20.0;

        if new_velocity.dot(velocity.linvel) < 0.0 {
            if path.index == 0 {
                path.forward = true;
            } else if path.index == path.points.len() - 1 {
                path.forward = false;
            }

            transform.translation.x = path.points[path.index].x;
            transform.translation.y = path.points[path.index].y;

            if path.forward {
                path.index += 1;
            } else {
                path.index -= 1;
            }

            new_velocity =
                (path.points[path.index] - transform.translation.truncate()).normalize() * 20.0;
        }

        velocity.linvel = new_velocity;
    }
}