From 4a2bbf3242cfbc82f9972c0e22c75f5f4aced5c9 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Tue, 19 Aug 2025 11:13:52 -0700 Subject: [PATCH] More correct parallax example! --- assets/bevy.png | 3 ++ examples/parallax.rs | 76 ++++++++++++++++++++---------------------- src/bin/flappy/main.rs | 42 +++++++++++++++++++++++ src/parallax.rs | 34 +++++++++++-------- 4 files changed, 101 insertions(+), 54 deletions(-) create mode 100644 assets/bevy.png diff --git a/assets/bevy.png b/assets/bevy.png new file mode 100644 index 0000000..4830a1f --- /dev/null +++ b/assets/bevy.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b90571125870b8ca14002ce544a6b8ab7aef1c03a20d327e2e56b9e15d73ed0 +size 10450 diff --git a/examples/parallax.rs b/examples/parallax.rs index 771b762..eaefa9a 100644 --- a/examples/parallax.rs +++ b/examples/parallax.rs @@ -9,7 +9,6 @@ fn main() { },)) .add_systems(Startup, spawn_background) .add_systems(Update, move_camera) - .add_systems(Update, parallax_gizmos) .run(); } @@ -17,43 +16,55 @@ fn spawn_background( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, + server: Res, ) { - let mesh = Mesh2d(meshes.add(Circle::new(1.0))); commands.spawn(( - Name::new("Depth: 1.1"), + Name::new("Depth: 1.0"), Transform::default().with_translation(Vec3::new(0.0, 0.0, 0.0)).with_scale(Vec3::splat(50.0)), - mesh.clone(), - MeshMaterial2d(materials.add(ColorMaterial::from_color(RED))), - ParallaxDepth(1.1), + Mesh2d(meshes.add(Circle::new(1.0))), + MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("bevy.png")), + color: RED.into(), + ..default() + })), + ParallaxDepth(1.0), Visibility::Inherited, - children![(Text2d("1.1".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); commands.spawn(( - Name::new("Depth: 2.1"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -1.0)).with_scale(Vec3::splat(50.0)), - mesh.clone(), - MeshMaterial2d(materials.add(ColorMaterial::from_color(GREEN))), - ParallaxDepth(2.1), + Name::new("Depth: 2.0"), + Transform::default().with_translation(Vec3::new(0.0, 0.0, -1.0)).with_scale(Vec3::splat(25.0)), + Mesh2d(meshes.add(Circle::new(2.0))), + MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("bevy.png")), + color: GREEN.into(), + ..default() + })), + 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.1"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -2.0)).with_scale(Vec3::splat(50.0)), - mesh.clone(), - MeshMaterial2d(materials.add(ColorMaterial::from_color(BLUE))), - ParallaxDepth(4.1), + Name::new("Depth: 4.0"), + Transform::default().with_translation(Vec3::new(0.0, 0.0, -2.0)).with_scale(Vec3::splat(12.5)), + Mesh2d(meshes.add(Circle::new(4.0))), + MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("bevy.png")), + color: BLUE.into(), + ..default() + })), + ParallaxDepth(4.0), Visibility::Inherited, - children![(Text2d("4.1".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); commands.spawn(( - Name::new("Depth: 8.1"), - Transform::default().with_translation(Vec3::new(0.0, 0.0, -3.0)).with_scale(Vec3::splat(50.0)), - mesh.clone(), - MeshMaterial2d(materials.add(ColorMaterial::from_color(YELLOW))), - ParallaxDepth(8.1), + Name::new("Depth: 8.0"), + Transform::default().with_translation(Vec3::new(0.0, 0.0, -3.0)).with_scale(Vec3::splat(6.25)), + Mesh2d(meshes.add(Circle::new(8.0))), + MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("bevy.png")), + color: YELLOW.into(), + ..default() + })), + ParallaxDepth(8.0), Visibility::Inherited, - children![(Text2d("8.1".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); } @@ -70,18 +81,3 @@ fn move_camera(mut t: Single<&mut Transform, With>, keys: Res>) { - // Closest to camera - // Parallax(1) - q.iter().for_each(|t| { - gizmos - .grid_2d( - t.translation.truncate(), - UVec2::new(5, 5), - Vec2::splat(10.), - MAGENTA, - ) - .outer_edges(); - }); -} diff --git a/src/bin/flappy/main.rs b/src/bin/flappy/main.rs index 95fce32..789e11a 100644 --- a/src/bin/flappy/main.rs +++ b/src/bin/flappy/main.rs @@ -36,6 +36,7 @@ fn main() { init_bird.after(init_assets), init_first_batches.after(init_assets), init_ui, + init_background, tweak_camera.after(create_camera_2d), ), ) @@ -699,6 +700,47 @@ fn init_ui(mut commands: Commands, server: Res) { )); } +fn init_background( + mut commands: Commands, + server: Res, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + { + let material = MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("flappy/background-city.png")), + color: BLACK.into(), + alpha_mode: AlphaMode2d::Blend, + ..default() + })); + let mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0))); + let t = Transform::from_xyz(0.0, 0.0, -32.0).with_scale(Vec3::splat(650.0)); + commands.spawn((ParallaxDepth(4.0), mesh, material, t)); + } + { + let material = MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("flappy/background-clouds.png")), + color: BLACK.into(), + alpha_mode: AlphaMode2d::Blend, + ..default() + })); + let mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0))); + let t = Transform::from_xyz(0.0, 0.0, -64.0).with_scale(Vec3::splat(650.0)); + commands.spawn((ParallaxDepth(8.0), mesh, material, t)); + } + { + let material = MeshMaterial2d(materials.add(ColorMaterial { + texture: Some(server.load("flappy/background-gradient.png")), + color: BLACK.into(), + alpha_mode: AlphaMode2d::Blend, + ..default() + })); + let mesh = Mesh2d(meshes.add(Rectangle::new(1.0, 1.0))); + let t = Transform::from_xyz(0.0, 0.0, -128.0).with_scale(Vec3::splat(650.0)); + commands.spawn((ParallaxDepth(16.0), mesh, material, t)); + } +} + fn start_rewind(_trigger: Trigger>, mut next: ResMut>) { next.set(PlayerState::Rewind); } diff --git a/src/parallax.rs b/src/parallax.rs index 1ff4905..79681ab 100644 --- a/src/parallax.rs +++ b/src/parallax.rs @@ -1,3 +1,6 @@ +use bevy::render::primitives::Aabb; +use bevy::render::mesh::MeshAabb; + use super::*; pub struct ParallaxPlugin; @@ -54,9 +57,10 @@ fn move_parallax_items( } fn wrap_parallax_items( - mut items: Query<(&mut Transform, &GlobalTransform, &ViewVisibility), (With, Without, Changed)>, + mut items: Query<(&mut Transform, &GlobalTransform, &ViewVisibility, &Mesh2d), (With, Without, Changed)>, camera: Single<(&Camera, &GlobalTransform), With>, window: Single<&Window>, + meshes: Res>, ) { if !items.is_empty() { let (cam, cam_gt) = *camera; @@ -68,26 +72,28 @@ fn wrap_parallax_items( Vec2::abs(Vec2::new(bottom_right.x - top_left.x, bottom_right.y - top_left.y)) }; - debug!("Window size: {:?}", window_size_in_world_space); // for each item in the paralax items - items.iter_mut().for_each(|(mut t, gt, v)| { + items.iter_mut().for_each(|(mut t, gt, v, Mesh2d(m))| { if !v.get() { - debug!("The item is not visible"); - + info!("Item is not visible"); // Get the total size (window + scale) - let total_size = window_size_in_world_space + (t.scale.truncate() * 2.0); - debug!("Window size: {:?} | Object size: {:?}", window_size_in_world_space, t.scale.truncate()); - debug!("Total size: {:?}", total_size); + let half_extents = { + let Aabb { half_extents, .. } = meshes.get(m).unwrap().compute_aabb().unwrap(); + half_extents.truncate() + }; + let object_size = t.scale.truncate() * 2.0; + let total_size = window_size_in_world_space + (object_size * half_extents); + info!("Sizes:\n\twindow {window_size_in_world_space}\n\tobject size: {object_size}\n\tAabb Half extents: {half_extents}\n\tTotal size: {total_size}"); // Double check that item is out of bounds let bounds_check = Vec2::abs(cam_gt.translation().truncate() - gt.translation().truncate()); let out_of_bounds = (total_size / 2.0) - bounds_check; - debug!("Bounds check {:?}", bounds_check); - debug!("Out of bounds: {:?}", out_of_bounds); - debug!("Starting position: {:?}", t.translation); + info!("Bounds check {bounds_check} | Out of bounds: {out_of_bounds:?}"); + + info!("Starting position: {:?}", t.translation); if out_of_bounds.x < 0.0 { - debug!("Object is actually out of bounds horizontally"); + info!("Object is actually out of bounds horizontally"); // determine if should move to the left or right relative to camera let move_right = cam_gt.translation().x > gt.translation().x; @@ -99,7 +105,7 @@ fn wrap_parallax_items( } } if out_of_bounds.y < 0.0 { - debug!("Object is actually out of bounds vertically"); + info!("Object is actually out of bounds vertically"); let move_up = cam_gt.translation().y > gt.translation().y; // move up or down @@ -109,7 +115,7 @@ fn wrap_parallax_items( t.translation.y -= total_size.y; } } - debug!("Moved to {:?}", t.translation); + info!("Moved to {:?}", t.translation); } }); }