1use crate::window_size::WindowSize;
2use bevy::{prelude::*, render::camera::Camera};
3
4#[derive(Default, Debug)]
5pub struct Layer {
6 pub speed: f32,
7}
8#[derive(Bundle, Default)]
9pub struct LayerComponents {
10 pub layer: Layer,
11 pub transform: Transform,
12 pub global: GlobalTransform,
13 pub children: Children,
14 pub material: Handle<ColorMaterial>,
15 pub sprite: Sprite,
16}
17
18fn sprite_scaled_width(sprite: &Sprite, transform: &Transform) -> f32 {
21 sprite.size[0] * transform.scale.x()
22}
23
24fn desired_children_count(window: &WindowSize, sprite: &Sprite, transform: &Transform) -> u32 {
26 let tex_width = sprite_scaled_width(sprite, transform) as u32;
27 if tex_width > 0 {
28 window.width.div_euclid(tex_width) + 2
29 } else {
30 0
31 }
32}
33
34fn camera_left_edge_offset(window: &WindowSize) -> f32 {
37 let left_side = 0.0 - window.width as f32 / 2.0;
38 left_side
39}
40
41fn camera_sprite_offset(
44 camera: &Vec3,
45 layer: &Layer,
46 sprite: &Sprite,
47 transform: &Transform,
48) -> f32 {
49 let sprite_width = sprite_scaled_width(sprite, transform);
50 -(camera.x() * layer.speed).rem_euclid(sprite_width)
51}
52
53fn move_layer_position(
57 window: &WindowSize,
58 camera: &Vec3,
59 sprite: &Sprite,
60 layer: &Layer,
61 transform: &mut Transform,
62) -> () {
63 let offset = camera_left_edge_offset(&window);
64 let camera_x = camera_sprite_offset(camera, layer, sprite, transform);
65 *transform.translation.x_mut() = offset + camera_x;
66}
67
68pub fn children_count_system(
71 mut commands: Commands,
72 cameras_query: Query<(&Camera, &WindowSize, &Children)>,
73 mut layer_query: Query<(
74 With<Layer, Entity>,
75 &Parent,
76 &Children,
77 &Sprite,
78 &Handle<ColorMaterial>,
79 &Transform,
80 )>,
81) -> () {
82 for (entity, parent, children, sprite, material, transform) in layer_query.iter_mut() {
83 if let Ok(window) = cameras_query.get_component(parent.0) {
84 let desired_children = desired_children_count(&window, &sprite, &transform);
85 let current_children = children.len();
86 let to_add = desired_children as usize - current_children;
87
88 for _ in 0..to_add {
89 let child = SpriteComponents {
90 material: material.clone(),
91 sprite: Sprite::default(),
92 ..Default::default()
93 };
94
95 commands.spawn(child).with(Parent(entity));
96 }
97
98 }
100 }
101}
102
103pub fn children_layout_system(
105 layers: Query<With<Layer, (&Sprite, &Children)>>,
106 mut sprites: Query<&mut Transform>,
107) {
108 for (sprite, children) in layers.iter() {
109 for (index, child) in children.iter().enumerate() {
110 if let Ok(mut transform) = sprites.get_component_mut::<Transform>(*child) {
111 *transform.translation.x_mut() =
112 index as f32 * sprite_scaled_width(sprite, &transform);
113 *transform.translation.z_mut() = -999.0;
114 }
115 }
116 }
117}
118
119pub fn layer_movement_system(
122 cameras: Query<With<Camera, (&Transform, &WindowSize, &Children)>>,
123 mut layers: Query<(&Layer, &Sprite, &mut Transform)>,
124) -> () {
125 for (transform, window, children) in cameras.iter() {
126 let camera = transform.translation;
127 for child in children.iter() {
128 if let Ok((layer, sprite, mut trans)) = layers.get_mut(*child) {
129 move_layer_position(window, &camera, sprite, layer, &mut trans);
130 }
131 }
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use rstest::rstest;
139
140 #[rstest(
141 width,
142 expected,
143 case(1024, -512.0),
144 case(1000, -500.0)
145 )]
146 fn test_left_edge(width: u32, expected: f32) {
147 let window = WindowSize {
148 height: 576,
149 width: width,
150 };
151 let result = camera_left_edge_offset(&window);
152 assert_eq!(expected, result);
153 }
154
155 #[rstest(
156 camera,
157 speed,
158 sprite,
159 expected,
160 case(0.0, 1.0,100.0, 0.0),
161 case(1.0, 1.0,100.0, -1.0),
162 case(101.0, 1.0, 100.0, -1.0),
163 case(200.0, 1.0, 100.0, 0.0),
164 case(220.0, 1.0, 100.0, -20.0)
165 ::trace
166 )]
167 fn test_layer_offset(camera: f32, speed: f32, sprite: f32, expected: f32) {
168 let camera = Vec3::new(camera, 0.0, 0.0);
169 let sprite = Sprite::new(Vec2::splat(sprite));
170 let transform = Transform::default();
171 let layer = Layer { speed };
172 let result = camera_sprite_offset(&camera, &layer, &sprite, &transform);
173 assert_eq!(expected, result);
174 }
175
176 #[rstest(
177 sprite,
178 scale,
179 expected,
180 case(100.0, 1.0, 100.0),
181 case(100.0, 2.0, 200.0),
182 case(100.0, 0.0, 0.0),
183 case(512.0, 1.0, 512.0)
184 ::trace
185 )]
186 fn test_scaled_width(sprite: f32, scale: f32, expected: f32) {
187 let transform = Transform {
188 scale: Vec3::splat(scale),
189 ..Default::default()
190 };
191 let sprite = Sprite::new(Vec2::splat(sprite));
192 let result = sprite_scaled_width(&sprite, &transform);
193 assert_eq!(expected, result);
194 }
195
196 #[rstest(
197 screen,
198 texture,
199 scale,
200 expected,
201 case(1024, 100, 1.0,12),
202 case(1024, 1025,1.0, 2),
203 case(1024, 800, 1.0,3),
204 case(1024, 0, 1.0,0)
205 ::trace
206 )]
207 fn test_desired_children_count(screen: u32, texture: u32, scale: f32, expected: u32) {
208 let window = WindowSize {
209 height: 576,
210 width: screen,
211 };
212
213 let transform = Transform {
214 scale: Vec3::splat(scale),
215 ..Default::default()
216 };
217
218 let texture = Sprite::new(Vec2::new(texture as f32, window.height as f32));
219 let result = desired_children_count(&window, &texture, &transform);
220 assert_eq!(expected, result);
221 }
222
223 #[rstest(
224 screen,camera,sprite,speed,expected,
225 case(1024,0.0, 512.0,0.0,-512.0),
226 case(1024,1.0, 512.0,0.0,-512.0),
227 case(1024,512.0, 512.0,1.0,-512.0),
228 case(1024,513.0, 512.0,1.0,-513.0),
229 case(1024,1.0, 512.0,1.0,-513.0),
230 case(1024,2.0, 512.0,0.5,-513.0),
231 case(1024,1024.0, 512.0,1.0,-512.0)
232 ::trace
233 )]
234 fn test_layer_translation(screen: u32, camera: f32, sprite: f32, speed: f32, expected: f32) {
235 let window_size = WindowSize {
236 height: 576,
237 width: screen,
238 };
239
240 let camera = Vec3::new(camera, 0.0, 0.0);
241 let speed = Layer { speed };
242 let sprite = Sprite::new(Vec2::new(sprite, window_size.height as f32));
243 let mut transform = Transform::default();
244 move_layer_position(&window_size, &camera, &sprite, &speed, &mut transform);
245 assert_eq!(expected, transform.translation.x());
246 }
247}