Compare commits
13 Commits
8c440317e7
...
1293a03968
| Author | SHA1 | Date |
|---|---|---|
|
|
1293a03968 | 2 months ago |
|
|
d1957652c5 | 2 months ago |
|
|
4a2bbf3242 | 2 months ago |
|
|
1525cc75f9 | 2 months ago |
|
|
8374d87d45 | 2 months ago |
|
|
654dd32fce | 2 months ago |
|
|
b8a626194b | 2 months ago |
|
|
c1de38988f | 2 months ago |
|
|
063a3dd7fc | 2 months ago |
|
|
94383709c3 | 2 months ago |
|
|
ccfaf30b81 | 2 months ago |
|
|
3aea4ee5b0 | 2 months ago |
|
|
fd716e3989 | 2 months ago |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,27 +1,122 @@
|
||||
use bevy::render::primitives::Aabb;
|
||||
use bevy::render::mesh::MeshAabb;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub struct ParallaxPlugin;
|
||||
|
||||
impl Plugin for ParallaxPlugin {
|
||||
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>),
|
||||
wrap_parallax_items.run_if(any_component_changed::<ViewVisibility>),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 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)]
|
||||
pub struct Parallax(pub f32);
|
||||
pub struct ParallaxDepth(pub f32);
|
||||
|
||||
fn move_parallax_items(
|
||||
mut q: Query<(&mut Transform, &Parallax), Without<Camera2d>>,
|
||||
cam_t: Single<&Transform, With<Camera2d>>,
|
||||
mut q: Query<(&mut Transform, &ParallaxDepth), Without<Camera2d>>,
|
||||
camera: Single<&Transform, (With<Camera2d>, Changed<Transform>)>,
|
||||
mut prev_camera_pos: Local<Vec2>,
|
||||
) {
|
||||
let base = cam_t.translation.truncate();
|
||||
// Unpack the camera data
|
||||
let cam_t = *camera;
|
||||
|
||||
// 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);
|
||||
|
||||
q.iter_mut().for_each(|(mut t, p)| {
|
||||
let val = base * (1.0 - (1.0 / p.0));
|
||||
t.translation.x = val.x;
|
||||
t.translation.y = val.y;
|
||||
// Update actual position
|
||||
t.translation.x -= depth_movement.x;
|
||||
t.translation.y -= depth_movement.y;
|
||||
});
|
||||
|
||||
*prev_camera_pos = cam_t.translation.truncate();
|
||||
}
|
||||
|
||||
fn wrap_parallax_items(
|
||||
mut items: Query<(&mut Transform, &GlobalTransform, &ViewVisibility, &Mesh2d), (With<ParallaxDepth>, Without<Camera2d>, Changed<ViewVisibility>)>,
|
||||
camera: Single<(&Camera, &GlobalTransform), With<Camera2d>>,
|
||||
window: Single<&Window>,
|
||||
meshes: Res<Assets<Mesh>>,
|
||||
) {
|
||||
if !items.is_empty() {
|
||||
let (cam, cam_gt) = *camera;
|
||||
|
||||
// get the window size in world space
|
||||
let window_size_in_world_space = {
|
||||
let top_left = cam.viewport_to_world_2d(cam_gt, Vec2::ZERO).unwrap();
|
||||
let bottom_right = cam.viewport_to_world_2d(cam_gt, window.size()).unwrap();
|
||||
|
||||
Vec2::abs(Vec2::new(bottom_right.x - top_left.x, bottom_right.y - top_left.y))
|
||||
};
|
||||
|
||||
// for each item in the paralax items
|
||||
items.iter_mut().for_each(|(mut t, gt, v, Mesh2d(m))| {
|
||||
if !v.get() {
|
||||
debug!("Item is not visible");
|
||||
// Get the total size (window + scale)
|
||||
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);
|
||||
debug!("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} | Out of bounds: {out_of_bounds:?}");
|
||||
|
||||
debug!("Starting position: {:?}", t.translation);
|
||||
if out_of_bounds.x < 0.0 {
|
||||
debug!("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;
|
||||
|
||||
// move left or right
|
||||
if move_right {
|
||||
t.translation.x += total_size.x;
|
||||
} else {
|
||||
t.translation.x -= total_size.x;
|
||||
}
|
||||
}
|
||||
if out_of_bounds.y < 0.0 {
|
||||
debug!("Object is actually out of bounds vertically");
|
||||
let move_up = cam_gt.translation().y > gt.translation().y;
|
||||
|
||||
// move up or down
|
||||
if move_up {
|
||||
t.translation.y += total_size.y;
|
||||
} else {
|
||||
t.translation.y -= total_size.y;
|
||||
}
|
||||
}
|
||||
debug!("Moved to {:?}", t.translation);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue