1use crate::layer;
2use bevy::{prelude::*, render::view::RenderLayers};
3
4#[cfg(feature = "bevy-inspector-egui")]
5use bevy_inspector_egui::prelude::*;
6
7#[derive(Event, Debug)]
9pub struct CreateParallaxEvent {
10 pub layers_data: Vec<layer::LayerData>,
11 pub camera: Entity,
12}
13
14impl CreateParallaxEvent {
15 pub fn create_layers(
17 &self,
18 commands: &mut Commands,
19 window_size: Vec2,
20 asset_server: &AssetServer,
21 texture_atlases: &mut Assets<TextureAtlasLayout>,
22 render_layer: u8,
23 ) {
24 for (i, layer) in self.layers_data.iter().enumerate() {
26 let texture: Handle<Image> = asset_server.load(&layer.path);
27 let texture_atlas = layer.create_texture_atlas_layout();
28 let texture_atlas_handle = texture_atlases.add(texture_atlas);
29
30 let sprite_bundle = SpriteBundle {
31 texture,
32 sprite: layer.create_sprite(),
33 ..default()
34 };
35
36 let max_length = window_size.length();
45
46 let y_max_index = match layer.repeat.has_vertical() {
47 true => f32::ceil(max_length / (layer.tile_size.y as f32 * layer.scale.y)) as i32,
48 false => 0,
49 };
50
51 let x_max_index = match layer.repeat.has_horizontal() {
52 true => f32::ceil(max_length / (layer.tile_size.x as f32 * layer.scale.x)) as i32,
53 false => 0,
54 };
55
56 let texture_count = Vec2::new(f32::max(2.0 * x_max_index as f32, 1.), f32::max(2.0 * y_max_index as f32, 1.));
57
58 let x_range = if layer.repeat.has_horizontal() {
59 (-x_max_index + 1)..=x_max_index
60 } else {
61 0..=0
62 };
63 let y_range = if layer.repeat.has_vertical() {
64 (-y_max_index + 1)..=y_max_index
65 } else {
66 0..=0
67 };
68
69 let mut entity_commands = commands.spawn_empty();
71 entity_commands
72 .insert(Name::new(format!("Parallax Layer ({})", i)))
73 .insert(RenderLayers::from_layers(&[render_layer.into()]))
74 .insert(SpatialBundle {
75 transform: Transform {
76 translation: Vec3::new(layer.position.x, layer.position.y, layer.z),
77 scale: layer.scale.extend(1.0),
78 ..default()
79 },
80 ..default()
81 })
82 .with_children(|parent| {
83 for x in x_range {
84 for y in y_range.clone() {
85 let repeat_strategy = layer.repeat.get_strategy();
86 let mut adjusted_sprite_bundle = sprite_bundle.clone();
87 repeat_strategy.transform(&mut adjusted_sprite_bundle, (x, y));
88 adjusted_sprite_bundle.transform.translation.x = layer.tile_size.x as f32 * x as f32;
89 adjusted_sprite_bundle.transform.translation.y = layer.tile_size.y as f32 * y as f32;
90 let mut child_commands = parent.spawn((
91 adjusted_sprite_bundle,
92 TextureAtlas {
93 layout: texture_atlas_handle.clone(),
94 index: 0,
95 },
96 ));
97 child_commands
98 .insert(RenderLayers::from_layers(&[render_layer.into()]))
99 .insert(layer.crate_layer_texture());
100 if let Some(animation_bundle) = layer.create_animation_bundle() {
101 child_commands.insert(animation_bundle);
102 }
103 }
104 }
105 });
106
107 entity_commands
109 .insert(layer::LayerComponent {
110 speed: match layer.speed {
111 layer::LayerSpeed::Horizontal(vx) => Vec2::new(vx, 0.0),
112 layer::LayerSpeed::Vertical(vy) => Vec2::new(0.0, vy),
113 layer::LayerSpeed::Bidirectional(vx, vy) => Vec2::new(vx, vy),
114 },
115 repeat: layer.repeat.clone(),
116 texture_count,
117 camera: self.camera,
118 })
119 .insert(RenderLayers::from_layers(&[render_layer.into()]));
120 }
121 }
122}
123
124#[derive(Event, Debug)]
126pub struct ParallaxMoveEvent {
127 pub translation: Vec2,
129
130 pub rotation: f32,
132
133 pub camera: Entity,
134}
135
136impl ParallaxMoveEvent {
137 pub fn has_translation(&self) -> bool {
138 self.translation != Vec2::ZERO
139 }
140
141 pub fn has_right_translation(&self) -> bool {
142 self.translation.x > 0.
143 }
144
145 pub fn has_left_translation(&self) -> bool {
146 self.translation.x < 0.
147 }
148
149 pub fn has_up_translation(&self) -> bool {
150 self.translation.y > 0.
151 }
152
153 pub fn has_down_translation(&self) -> bool {
154 self.translation.y < 0.
155 }
156}
157
158#[derive(Component)]
160#[cfg_attr(feature = "bevy-inspector-egui", derive(Reflect, InspectorOptions))]
161pub struct ParallaxCameraComponent {
162 pub render_layer: u8,
163 pub limits: Vec2Limit,
164}
165
166#[derive(Debug, Clone, Copy)]
167#[cfg_attr(feature = "bevy-inspector-egui", derive(Reflect, InspectorOptions))]
168#[cfg_attr(feature = "bevy-inspector-egui", reflect(InspectorOptions))]
169pub struct Limit {
170 pub min: f32,
171 pub max: f32,
172}
173
174impl Default for Limit {
175 fn default() -> Self {
176 Self {
177 min: f32::NEG_INFINITY,
178 max: f32::INFINITY,
179 }
180 }
181}
182
183impl Limit {
184 pub fn new(min: f32, max: f32) -> Self {
185 Self { min: min, max: max }
186 }
187
188 pub fn zero_to_infinity() -> Self {
189 Self {
190 min: 0.,
191 max: f32::INFINITY,
192 }
193 }
194
195 pub fn zero_to(max: f32) -> Self {
196 Self { min: 0., max: max }
197 }
198
199 pub fn fix(&self, value: f32) -> f32 {
200 f32::min(f32::max(value, self.min), self.max)
201 }
202}
203
204#[derive(Debug, Clone, Copy)]
205#[cfg_attr(feature = "bevy-inspector-egui", derive(Reflect, InspectorOptions))]
206#[cfg_attr(feature = "bevy-inspector-egui", reflect(InspectorOptions))]
207pub struct Vec2Limit {
208 pub x: Limit,
209 pub y: Limit,
210}
211
212impl Vec2Limit {
213 pub fn new(x: Limit, y: Limit) -> Self {
214 Self { x: x, y: y }
215 }
216
217 pub fn fix(&self, vec: Vec2) -> Vec2 {
218 Vec2::new(self.x.fix(vec.x), self.y.fix(vec.y))
219 }
220}
221
222impl Default for Vec2Limit {
223 fn default() -> Self {
224 Self {
225 x: default(),
226 y: default(),
227 }
228 }
229}
230
231impl ParallaxCameraComponent {
232 pub fn inside_limits(&self, translation: Vec2) -> Vec2 {
233 self.limits.fix(translation)
234 }
235
236 pub fn new(render_layer: u8) -> Self {
237 Self {
238 render_layer: render_layer,
239 ..default()
240 }
241 }
242}
243
244impl Default for ParallaxCameraComponent {
245 fn default() -> Self {
246 Self {
247 render_layer: 0,
248 limits: default(),
249 }
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use bevy::prelude::*;
256
257 use crate::ParallaxMoveEvent;
258
259 #[test]
260 fn test_check() {
261 assert_eq!(true, true);
262 }
263
264 #[test]
265 fn test_parallax_event() {
266 let camera = Entity::from_raw(0);
267
268 let no_movement = ParallaxMoveEvent {
269 translation: Vec2::ZERO,
270 rotation: 0.,
271 camera: camera,
272 };
273 assert_eq!(no_movement.has_translation(), false);
274 assert_eq!(no_movement.has_up_translation(), false);
275 assert_eq!(no_movement.has_down_translation(), false);
276 assert_eq!(no_movement.has_left_translation(), false);
277 assert_eq!(no_movement.has_right_translation(), false);
278
279 let up = ParallaxMoveEvent {
280 translation: Vec2::new(0., 1.),
281 rotation: 0.,
282 camera: camera,
283 };
284 assert_eq!(up.has_translation(), true);
285 assert_eq!(up.has_up_translation(), true);
286 assert_eq!(up.has_down_translation(), false);
287 assert_eq!(up.has_left_translation(), false);
288 assert_eq!(up.has_right_translation(), false);
289
290 let down = ParallaxMoveEvent {
291 translation: Vec2::new(0., -1.),
292 rotation: 0.,
293 camera: camera,
294 };
295 assert_eq!(down.has_translation(), true);
296 assert_eq!(down.has_up_translation(), false);
297 assert_eq!(down.has_down_translation(), true);
298 assert_eq!(down.has_left_translation(), false);
299 assert_eq!(down.has_right_translation(), false);
300
301 let left = ParallaxMoveEvent {
302 translation: Vec2::new(-1., 0.),
303 rotation: 0.,
304 camera: camera,
305 };
306 assert_eq!(left.has_translation(), true);
307 assert_eq!(left.has_up_translation(), false);
308 assert_eq!(left.has_down_translation(), false);
309 assert_eq!(left.has_left_translation(), true);
310 assert_eq!(left.has_right_translation(), false);
311
312 let right = ParallaxMoveEvent {
313 translation: Vec2::new(1., 0.),
314 rotation: 0.,
315 camera: camera,
316 };
317 assert_eq!(right.has_translation(), true);
318 assert_eq!(right.has_up_translation(), false);
319 assert_eq!(right.has_down_translation(), false);
320 assert_eq!(right.has_left_translation(), false);
321 assert_eq!(right.has_right_translation(), true);
322
323 let left_down = ParallaxMoveEvent {
324 translation: Vec2::new(-1., -1.),
325 rotation: 0.,
326 camera: camera,
327 };
328 assert_eq!(left_down.has_translation(), true);
329 assert_eq!(left_down.has_up_translation(), false);
330 assert_eq!(left_down.has_down_translation(), true);
331 assert_eq!(left_down.has_left_translation(), true);
332 assert_eq!(left_down.has_right_translation(), false);
333
334 let up_right = ParallaxMoveEvent {
335 translation: Vec2::new(1., 1.),
336 rotation: 0.,
337 camera: camera,
338 };
339 assert_eq!(up_right.has_translation(), true);
340 assert_eq!(up_right.has_up_translation(), true);
341 assert_eq!(up_right.has_down_translation(), false);
342 assert_eq!(up_right.has_left_translation(), false);
343 assert_eq!(up_right.has_right_translation(), true);
344 }
345}