Parallax example works ish with repeating patterns

main
Elijah Voigt 2 months ago
parent 063a3dd7fc
commit c1de38988f

@ -10,22 +10,48 @@ fn main() {
.add_systems(Startup, spawn_background) .add_systems(Startup, spawn_background)
.add_systems(Update, move_camera) .add_systems(Update, move_camera)
.add_systems(Update, parallax_gizmos) .add_systems(Update, parallax_gizmos)
.add_systems(Update, move_parallax_items)
.run(); .run();
} }
fn spawn_background( fn spawn_background(
mut commands: Commands, mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) { ) {
commands.spawn((Parallax(1.0), children![(Text2d("1.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))])); let mesh = Mesh2d(meshes.add(Circle::new(50.0)));
commands.spawn((Parallax(2.0), children![(Text2d("2.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))])); let material = MeshMaterial2d(materials.add(ColorMaterial::from_color(RED)));
commands.spawn((Parallax(4.0), children![(Text2d("4.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))])); commands.spawn((
commands.spawn((Parallax(8.0), children![(Text2d("8.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))])); mesh.clone(),
material.clone(),
Parallax(1.0),
Visibility::Inherited,
children![(Text2d("1.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))],
));
commands.spawn((
mesh.clone(),
material.clone(),
Parallax(2.0),
Visibility::Inherited,
children![(Text2d("2.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))],
));
commands.spawn((
mesh.clone(),
material.clone(),
Parallax(4.0),
Visibility::Inherited,
children![(Text2d("4.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))],
));
commands.spawn((
mesh.clone(),
material.clone(),
Parallax(8.0),
Visibility::Inherited,
children![(Text2d("8.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))],
));
} }
fn move_camera( fn move_camera(mut t: Single<&mut Transform, With<Camera2d>>, keys: Res<ButtonInput<KeyCode>>) {
mut t: Single<&mut Transform, With<Camera2d>>,
keys: Res<ButtonInput<KeyCode>>,
) {
if keys.pressed(KeyCode::ArrowLeft) { if keys.pressed(KeyCode::ArrowLeft) {
t.translation.x -= 5.0; t.translation.x -= 5.0;
} else if keys.pressed(KeyCode::ArrowRight) { } else if keys.pressed(KeyCode::ArrowRight) {
@ -38,18 +64,31 @@ fn move_camera(
t.translation.y += 5.0; t.translation.y += 5.0;
} }
} }
fn parallax_gizmos(
mut gizmos: Gizmos, fn parallax_gizmos(mut gizmos: Gizmos, q: Query<&Transform, With<Parallax>>) {
q: Query<&Transform, With<Parallax>>,
) {
// Closest to camera // Closest to camera
// Parallax(1) // Parallax(1)
q.iter().for_each(|t| { q.iter().for_each(|t| {
gizmos.grid_2d( gizmos
.grid_2d(
t.translation.truncate(), t.translation.truncate(),
UVec2::new(5, 5), UVec2::new(5, 5),
Vec2::splat(10.), Vec2::splat(10.),
RED, RED,
).outer_edges(); )
.outer_edges();
});
}
// TODO: Move to src/parallax.rs
fn move_parallax_items(
mut q: Query<(Entity, &ViewVisibility, &mut ParallaxRepeatIteration), (With<Parallax>, Changed<ViewVisibility>)>,
) {
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");
}
}); });
} }

@ -150,7 +150,14 @@ impl Tape {
} }
} }
fn push(&mut self, lv: LinearVelocity, av: AngularVelocity, ei: ExternalImpulse, p: Position, r: Rotation) { fn push(
&mut self,
lv: LinearVelocity,
av: AngularVelocity,
ei: ExternalImpulse,
p: Position,
r: Rotation,
) {
// If we are at capacity, make room // If we are at capacity, make room
if self.linear_velocities.len() == self.capacity { if self.linear_velocities.len() == self.capacity {
self.linear_velocities.pop_front().unwrap(); self.linear_velocities.pop_front().unwrap();
@ -167,7 +174,15 @@ impl Tape {
self.rotations.push_back(r); self.rotations.push_back(r);
} }
fn pop(&mut self) -> Option<(LinearVelocity, AngularVelocity, ExternalImpulse, Position, Rotation)> { fn pop(
&mut self,
) -> Option<(
LinearVelocity,
AngularVelocity,
ExternalImpulse,
Position,
Rotation,
)> {
if self.linear_velocities.is_empty() { if self.linear_velocities.is_empty() {
None None
} else { } else {
@ -194,8 +209,7 @@ fn init_bird(mut commands: Commands, bird_assets: Res<BirdAssets>) {
MaxLinearSpeed(500.0), MaxLinearSpeed(500.0),
); );
// 60fps * 60 seconds // 60fps * 5 seconds
// let tape = Tape::new_with_capacity(60 * 60);
const REWIND_SECONDS: usize = 5; const REWIND_SECONDS: usize = 5;
let tape = Tape::new_with_capacity(60 * REWIND_SECONDS); let tape = Tape::new_with_capacity(60 * REWIND_SECONDS);
@ -611,8 +625,15 @@ fn init_ui(mut commands: Commands, server: Res<AssetServer>) {
RewindButton, RewindButton,
children![ children![
( (
ImageNode { color: BLACK.into(), image: rewind_image, ..default() }, ImageNode {
Node { height: Val::Px(50.0), ..default() }, color: BLACK.into(),
image: rewind_image,
..default()
},
Node {
height: Val::Px(50.0),
..default()
},
), ),
( (
Text::new("Rewind! (R)"), Text::new("Rewind! (R)"),
@ -648,8 +669,15 @@ fn init_ui(mut commands: Commands, server: Res<AssetServer>) {
TextLayout::new_with_justify(JustifyText::Center) TextLayout::new_with_justify(JustifyText::Center)
), ),
( (
ImageNode { color: BLACK.into(), image: play_image, ..default() }, ImageNode {
Node { height: Val::Px(50.0), ..default() }, color: BLACK.into(),
image: play_image,
..default()
},
Node {
height: Val::Px(50.0),
..default()
},
), ),
], ],
)) ))
@ -667,7 +695,7 @@ fn init_ui(mut commands: Commands, server: Res<AssetServer>) {
SyncResource::<Score>::default(), SyncResource::<Score>::default(),
Text::default(), Text::default(),
TextLayout::new_with_justify(JustifyText::Center), TextLayout::new_with_justify(JustifyText::Center),
)] )],
)); ));
} }
@ -793,9 +821,7 @@ fn record(
"Only record in the alive state" "Only record in the alive state"
); );
birds birds.iter_mut().for_each(|(lv, av, ei, p, r, mut tape)| {
.iter_mut()
.for_each(|(lv, av, ei, p, r, mut tape)| {
tape.push(*lv, *av, *ei, *p, *r); tape.push(*lv, *av, *ei, *p, *r);
}); });
} }
@ -822,8 +848,9 @@ fn rewind(
"Only rewind in the rewinding state" "Only rewind in the rewinding state"
); );
birds.iter_mut().for_each( birds
|(mut lv, mut av, mut ei, mut p, mut r, mut tape)| { .iter_mut()
.for_each(|(mut lv, mut av, mut ei, mut p, mut r, mut tape)| {
if let Some((new_lv, new_av, new_ei, new_p, new_r)) = tape.pop() { if let Some((new_lv, new_av, new_ei, new_p, new_r)) = tape.pop() {
lv.0 = new_lv.0; lv.0 = new_lv.0;
av.0 = new_av.0; av.0 = new_av.0;
@ -834,8 +861,7 @@ fn rewind(
} else { } else {
next.set(PlayerState::Pause); next.set(PlayerState::Pause);
} }
}, });
);
} }
// PERF: May run more than necessary, should be event-driven on aabb intersection // PERF: May run more than necessary, should be event-driven on aabb intersection

@ -4,12 +4,12 @@
mod base_game; mod base_game;
mod debug; mod debug;
mod loading; mod loading;
mod parallax;
pub mod physics2d; pub mod physics2d;
pub mod physics3d; pub mod physics3d;
mod scheduling; mod scheduling;
mod ui; mod ui;
mod version; mod version;
mod parallax;
// Rust stdlib // Rust stdlib
pub use std::collections::VecDeque; pub use std::collections::VecDeque;
@ -42,7 +42,7 @@ pub use thiserror::Error;
pub use base_game::*; pub use base_game::*;
pub use debug::*; pub use debug::*;
pub use loading::*; pub use loading::*;
pub use parallax::*;
pub use scheduling::*; pub use scheduling::*;
pub use ui::*; pub use ui::*;
pub use version::*; pub use version::*;
pub use parallax::*;

@ -4,24 +4,47 @@ pub struct ParallaxPlugin;
impl Plugin for ParallaxPlugin { impl Plugin for ParallaxPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Update, move_parallax_items.run_if(any_component_changed::<Transform>)); app.add_systems(
Update,
move_parallax_items.run_if(any_component_changed::<Transform>),
);
} }
} }
#[derive(Component)] #[derive(Component)]
#[require(Transform)] #[require(Transform, ParallaxRepeat, ParallaxRepeatIteration)]
pub struct Parallax(pub f32); 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);
fn move_parallax_items( fn move_parallax_items(
mut q: Query<(&mut Transform, &Parallax), Without<Camera2d>>, mut q: Query<(&mut Transform, &Parallax, &ParallaxRepeat, &ParallaxRepeatIteration), Without<Camera2d>>,
cam_t: Single<&Transform, With<Camera2d>>, camera: Single<(&Camera, &Transform, &GlobalTransform), With<Camera2d>>,
window: Single<&Window>
) { ) {
let (cam, cam_t, cam_gt) = *camera;
let base = cam_t.translation.truncate(); let base = cam_t.translation.truncate();
let size = window.size();
q.iter_mut().for_each(|(mut t, p)| { q.iter_mut().for_each(|(mut t, p, pr, pri)| {
let val = base * (1.0 - (1.0 / p.0)); 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.x = val.x;
t.translation.y = val.y; t.translation.y = val.y;
}); });
} }

Loading…
Cancel
Save