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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use crate::layer;
use bevy::prelude::*;

/// Event used to update parallax
pub struct ParallaxMoveEvent {
    /// Speed to move camera (x direction)
    pub camera_move_speed: f32,
}

/// Resource for managing parallax
#[derive(Debug)]
pub struct ParallaxResource {
    /// Data to describe each layer of parallax
    pub layer_data: Vec<layer::LayerData>,
    /// Parallax layer entities
    pub layer_entities: Vec<Entity>,
    /// Dimensions of window
    pub window_size: Vec2,
}

impl Default for ParallaxResource {
    fn default() -> Self {
        Self {
            layer_data: vec![],
            layer_entities: vec![],
            window_size: Vec2::ZERO,
        }
    }
}

impl ParallaxResource {
    /// Create a new parallax resource
    pub fn new(layer_data: Vec<layer::LayerData>) -> Self {
        ParallaxResource {
            layer_data,
            layer_entities: vec![],
            window_size: Vec2::ZERO,
        }
    }

    /// Delete all layer entities in parallax resource and empty Vec
    pub fn despawn_layers(&mut self, commands: &mut Commands) {
        // Remove all layer entities
        for entity in self.layer_entities.iter() {
            commands.entity(*entity).despawn_recursive();
        }

        // Empty the layer entity vector
        self.layer_entities = vec![];
    }

    /// Create layers from layer data
    pub fn create_layers(
        &mut self,
        commands: &mut Commands,
        asset_server: &AssetServer,
        texture_atlases: &mut Assets<TextureAtlas>,
    ) {
        // Despawn any existing layers
        self.despawn_layers(commands);

        // Spawn new layers using layer_data
        for (i, layer) in self.layer_data.iter().enumerate() {
            // Setup texture
            let texture_handle = asset_server.load(&layer.path);
            let texture_atlas =
                TextureAtlas::from_grid(texture_handle, layer.tile_size, layer.cols, layer.rows);
            let texture_atlas_handle = texture_atlases.add(texture_atlas);
            let spritesheet_bundle = SpriteSheetBundle {
                texture_atlas: texture_atlas_handle,
                ..Default::default()
            };

            // Three textures always spawned
            let mut texture_count = 3.0;

            // Spawn parallax layer entity
            let mut entity_commands = commands.spawn();
            entity_commands
                .insert(Name::new(format!("Parallax Layer ({})", i)))
                .insert(Transform {
                    translation: Vec3::new(0.0, 0.0, layer.z),
                    scale: Vec3::new(layer.scale, layer.scale, 1.0),
                    ..Default::default()
                })
                .insert(GlobalTransform::default())
                .with_children(|parent| {
                    // Spawn center texture
                    parent.spawn_bundle(spritesheet_bundle.clone()).insert(
                        layer::LayerTextureComponent {
                            width: layer.tile_size.x,
                        },
                    );

                    let mut max_x = (layer.tile_size.x / 2.0) * layer.scale;
                    let mut adjusted_spritesheet_bundle = spritesheet_bundle.clone();

                    // Spawn right texture
                    adjusted_spritesheet_bundle.transform.translation.x += layer.tile_size.x;
                    max_x += layer.tile_size.x * layer.scale;
                    parent
                        .spawn_bundle(adjusted_spritesheet_bundle.clone())
                        .insert(layer::LayerTextureComponent {
                            width: layer.tile_size.x,
                        });

                    // Spawn left texture
                    parent
                        .spawn_bundle({
                            let mut bundle = adjusted_spritesheet_bundle.clone();
                            bundle.transform.translation.x *= -1.0;
                            bundle
                        })
                        .insert(layer::LayerTextureComponent {
                            width: layer.tile_size.x,
                        });

                    // Spawn additional textures to make 2 windows length of background textures
                    while max_x < self.window_size.x {
                        adjusted_spritesheet_bundle.transform.translation.x += layer.tile_size.x;
                        max_x += layer.tile_size.x * layer.scale;
                        parent
                            .spawn_bundle(adjusted_spritesheet_bundle.clone())
                            .insert(layer::LayerTextureComponent {
                                width: layer.tile_size.x,
                            });

                        parent
                            .spawn_bundle({
                                let mut bundle = adjusted_spritesheet_bundle.clone();
                                bundle.transform.translation.x *= -1.0;
                                bundle
                            })
                            .insert(layer::LayerTextureComponent {
                                width: layer.tile_size.x,
                            });

                        texture_count += 2.0;
                    }
                });

            // Add layer component to entity
            entity_commands.insert(layer::LayerComponent {
                speed: layer.speed,
                texture_count,
                transition_factor: layer.transition_factor,
            });

            // Push parallax layer entity to layer_entities
            self.layer_entities.push(entity_commands.id());
        }
    }
}

/// Attach to a single camera to be used with parallax
#[derive(Component)]
pub struct ParallaxCameraComponent;