use games::*; fn main() { App::new() .add_plugins((BaseGamePlugin { name: "parallax example".into(), title: "Parallax".into(), game_type: GameType::Two, },)) .add_systems(Startup, spawn_background) .add_systems(Update, move_camera) .add_systems(Update, parallax_gizmos) .add_systems(Update, wrap_parallax_items.run_if(any_component_changed::)) .run(); } fn spawn_background( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { let mesh = Mesh2d(meshes.add(Circle::new(1.0))); commands.spawn(( Name::new("Depth: 1"), Transform::default().with_scale(Vec3::splat(50.0)), mesh.clone(), MeshMaterial2d(materials.add(ColorMaterial::from_color(RED))), 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::default().with_scale(Vec3::splat(50.0)), mesh.clone(), MeshMaterial2d(materials.add(ColorMaterial::from_color(GREEN))), 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::default().with_scale(Vec3::splat(50.0)), mesh.clone(), MeshMaterial2d(materials.add(ColorMaterial::from_color(BLUE))), 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::default().with_scale(Vec3::splat(50.0)), mesh.clone(), MeshMaterial2d(materials.add(ColorMaterial::from_color(YELLOW))), ParallaxDepth(8.0), Visibility::Inherited, children![(Text2d("8.0".into()), Transform::from_xyz(0.0, 35.0, 0.0))], )); } fn move_camera(mut t: Single<&mut Transform, With>, keys: Res>) { if keys.pressed(KeyCode::ArrowLeft) { t.translation.x -= 5.0; } else if keys.pressed(KeyCode::ArrowRight) { t.translation.x += 5.0; } if keys.pressed(KeyCode::ArrowDown) { t.translation.y -= 5.0; } else if keys.pressed(KeyCode::ArrowUp) { t.translation.y += 5.0; } } fn parallax_gizmos(mut gizmos: Gizmos, q: Query<&Transform, With>) { // 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(); }); } fn wrap_parallax_items( mut items: Query<(&mut Transform, &GlobalTransform, &ViewVisibility), (With, Without, Changed)>, camera: Single<(&Camera, &GlobalTransform), With>, window: Single<&Window>, ) { 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)) }; info!("Window size: {:?}", window_size_in_world_space); // for each item in the paralax items items.iter_mut().for_each(|(mut t, gt, v)| { if !v.get() { info!("The item is not visible"); // Get the total size (window + scale) let total_size = window_size_in_world_space + (t.scale.truncate() * 2.0); info!("Window size: {:?} | Object size: {:?}", window_size_in_world_space, t.scale.truncate()); info!("Total 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; info!("Bounds check {:?}", bounds_check); info!("Out of bounds: {:?}", out_of_bounds); info!("Starting position: {:?}", t.translation); if out_of_bounds.x < 0.0 { 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; // 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 { info!("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; } } info!("Moved to {:?}", t.translation); } }); } }