From b8a626194bf886c67eb5bd9114179efed3f3f3fd Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Mon, 18 Aug 2025 11:34:39 -0700 Subject: [PATCH] Slight rework of parallax system --- examples/parallax.rs | 35 +++++++++++-------------- src/parallax.rs | 62 +++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/examples/parallax.rs b/examples/parallax.rs index f12c8bd..f302a9e 100644 --- a/examples/parallax.rs +++ b/examples/parallax.rs @@ -10,7 +10,6 @@ fn main() { .add_systems(Startup, spawn_background) .add_systems(Update, move_camera) .add_systems(Update, parallax_gizmos) - .add_systems(Update, move_parallax_items) .run(); } @@ -19,33 +18,42 @@ fn spawn_background( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mesh = Mesh2d(meshes.add(Circle::new(50.0))); + let mesh = Mesh2d(meshes.add(Circle::new(1.0))); let material = MeshMaterial2d(materials.add(ColorMaterial::from_color(RED))); + let transform = Transform::default().with_scale(Vec3::splat(50.0)); commands.spawn(( + Name::new("Depth: 1"), + transform, mesh.clone(), material.clone(), - Parallax(1.0), + ParallaxDepth(1.0), Visibility::Inherited, children![(Text2d("1.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); commands.spawn(( + Name::new("Depth: 2"), + transform, mesh.clone(), material.clone(), - Parallax(2.0), + ParallaxDepth(2.0), Visibility::Inherited, children![(Text2d("2.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); commands.spawn(( + Name::new("Depth: 4"), + transform, mesh.clone(), material.clone(), - Parallax(4.0), + ParallaxDepth(4.0), Visibility::Inherited, children![(Text2d("4.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); commands.spawn(( + Name::new("Depth: 8"), + transform, mesh.clone(), material.clone(), - Parallax(8.0), + ParallaxDepth(8.0), Visibility::Inherited, children![(Text2d("8.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); @@ -65,7 +73,7 @@ fn move_camera(mut t: Single<&mut Transform, With>, keys: Res>) { +fn parallax_gizmos(mut gizmos: Gizmos, q: Query<&Transform, With>) { // Closest to camera // Parallax(1) q.iter().for_each(|t| { @@ -79,16 +87,3 @@ fn parallax_gizmos(mut gizmos: Gizmos, q: Query<&Transform, With>) { .outer_edges(); }); } - -// TODO: Move to src/parallax.rs -fn move_parallax_items( - mut q: Query<(Entity, &ViewVisibility, &mut ParallaxRepeatIteration), (With, Changed)>, -) { - q.iter_mut().for_each(|(e, vis, mut pri)| { - warn!("{e} {:?}", vis.get()); - if !vis.get() { - pri.0 += 1; - todo!("Works when moving camera right, make it work left too"); - } - }); -} diff --git a/src/parallax.rs b/src/parallax.rs index 232b246..ad799c4 100644 --- a/src/parallax.rs +++ b/src/parallax.rs @@ -11,40 +11,42 @@ impl Plugin for ParallaxPlugin { } } +/// +/// ParallaxDepth describes how far from the camera something is +/// +/// A parallax depth of 1 means it moves 1:1 with camera movement; +/// If the camera moves 1 pixel to the left, the background moves 1px to the right +/// +/// A parallax depth of 2 means the movement is 1:2 +/// Camera moves 2px, the element moves 1px +/// #[derive(Component)] -#[require(Transform, ParallaxRepeat, ParallaxRepeatIteration)] -pub struct Parallax(pub f32); - -#[derive(Component)] -pub struct ParallaxRepeat(pub f32); - -impl Default for ParallaxRepeat{ - fn default() -> Self { - ParallaxRepeat(1.0) - } -} - -#[derive(Component, Default)] -pub struct ParallaxRepeatIteration(pub isize); +pub struct ParallaxDepth(pub f32); fn move_parallax_items( - mut q: Query<(&mut Transform, &Parallax, &ParallaxRepeat, &ParallaxRepeatIteration), Without>, - camera: Single<(&Camera, &Transform, &GlobalTransform), With>, - window: Single<&Window> + mut q: Query<(&mut Transform, &ParallaxDepth), Without>, + window: Single<&Window>, + camera: Single<(&Camera, &Transform, &GlobalTransform), (With, Changed)>, + mut prev_camera_pos: Local, ) { + // Unpack the camera data let (cam, cam_t, cam_gt) = *camera; - let base = cam_t.translation.truncate(); - let size = window.size(); - - q.iter_mut().for_each(|(mut t, p, pr, pri)| { - let offset: Vec2 = { - let a = cam.viewport_to_world_2d(cam_gt, Vec2::new(0.0, size.y / 2.0)).unwrap(); - let b = cam.viewport_to_world_2d(cam_gt, Vec2::new(size.x, size.y / 2.0)).unwrap(); - (b - a) * pr.0 * (pri.0 as f32) - }; - // Something like add screen-dimensions * parallax repeat cycle number - let val = base * (1.0 - (1.0 / p.0)) + offset; - t.translation.x = val.x; - t.translation.y = val.y; + + // Calculate how far the camera moved since the last update + let delta = cam_t.translation.truncate() - *prev_camera_pos; + debug!("Cam Delta: {:?}", delta); + + // For each object + q.iter_mut().for_each(|(mut t, pd)| { + // Update ParallaxPosition + let depth_movement = delta / pd.0; + + debug!("Depth: {:?} | Move: {:?}", pd.0, depth_movement); + + // Update actual position + t.translation.x -= depth_movement.x; + t.translation.y -= depth_movement.y; }); + + *prev_camera_pos = cam_t.translation.truncate(); }