use bevy::prelude::*; use bevy::window::{CursorGrabMode, PrimaryWindow}; use bevy_camera_shake::{CameraShakePlugin, RandomSource, Shake3d}; use rand::{thread_rng, Rng}; fn main() { App::new() .add_plugins(DefaultPlugins) .add_plugins(CameraShakePlugin) .add_plugins(NoCameraPlayerPlugin) .add_systems(Startup, setup) .add_systems(Update, add_shake) .run(); } fn random_number() -> f32 { let mut rng = thread_rng(); let x: f32 = rng.gen(); x * 2.0 - 1.0 } struct MyRandom; impl RandomSource for MyRandom { fn rand(&self, _time: f32) -> f32 { random_number() } } #[derive(Component)] struct Player { pub speed: f32, } #[derive(Component)] struct ThirdPersonCamera; fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Plane { size: 150.0, subdivisions: 0, })), material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), transform: Transform::from_xyz(0.0, -0.5, 0.0), ..default() }); commands.spawn(PointLightBundle { point_light: PointLight { intensity: 1500.0, shadows_enabled: true, ..default() }, transform: Transform::from_xyz(4.0, 8.0, 4.0), ..default() }); let camera_id = commands .spawn(Camera3dBundle { transform: Transform::from_xyz(0.0, 0.5, 15.0).looking_at(Vec3::ZERO, Vec3::Y), ..Default::default() }) .insert(ThirdPersonCamera) .id(); let shake_id = commands .spawn(Shake3d { max_offset: Vec3::new(0.0, 0.0, 0.0), max_yaw_pitch_roll: Vec3::new(0.1, 0.1, 0.1), trauma: 0.0, trauma_power: 2.0, decay: 0.8, random_sources: [ Box::new(MyRandom), Box::new(MyRandom), Box::new(MyRandom), Box::new(MyRandom), Box::new(MyRandom), Box::new(MyRandom), ], }) .insert(SpatialBundle::default()) .id(); let player_transform = Transform::default(); let player_id = commands .spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), material: materials.add(Color::rgb(1.0, 0.8, 0.6).into()), transform: player_transform, ..default() }) .insert(Player { speed: 5.0 }) .id(); let player_face_id = commands .spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), material: materials.add(Color::rgb(0.0, 0.8, 0.6).into()), transform: Transform::from_translation(player_transform.forward() * 0.5) .with_scale(Vec3::new(0.3, 0.1, 0.5)), ..default() }) .id(); for _ in 0..250 { commands.spawn(PbrBundle { mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), material: materials.add(Color::rgb(0.3, 0.7, 0.8).into()), transform: Transform { translation: Vec3::new( (random_number()) * 10.0, ((random_number()) + 1.0) * 10.0, (random_number()) * 10.0, ), rotation: Quat::default(), scale: Vec3::new(0.3, 0.3, 0.3), }, ..default() }); } commands.entity(player_id).push_children(&[shake_id]); commands.entity(player_id).push_children(&[player_face_id]); commands.entity(shake_id).push_children(&[camera_id]); println!("Press R to add trauma to the camera."); } const TRAUMA_AMOUNT: f32 = 0.5; fn add_shake(mut shakeables: Query<&mut Shake3d>, keyboard_input: Res>) { if keyboard_input.just_pressed(KeyCode::R) { for mut shakeable in shakeables.iter_mut() { let past_trauma = shakeable.trauma; let current_trauma = f32::min(shakeable.trauma + TRAUMA_AMOUNT, 1.0); info!( "Past trauma: {}, Current trauma: {}", past_trauma, current_trauma ); shakeable.trauma = current_trauma; } } } // Code shamelessly stolen and edited from https://github.com/sburris0/bevy_flycam/blob/master/src/lib.rs use bevy::ecs::event::{Events, ManualEventReader}; use bevy::input::mouse::MouseMotion; /// Keeps track of mouse motion events, pitch, and yaw #[derive(Default, Debug, Resource)] struct InputState { reader_motion: ManualEventReader, pitch: f32, yaw: f32, } /// Mouse sensitivity #[derive(Resource)] pub struct MouseSensitivity { pub sensitivity: f32, } impl Default for MouseSensitivity { fn default() -> Self { Self { sensitivity: 0.00012, } } } /// Grabs/ungrabs mouse cursor fn toggle_grab_cursor(window: &mut Window) { window.cursor.grab_mode = match window.cursor.grab_mode { CursorGrabMode::None => CursorGrabMode::Confined, CursorGrabMode::Confined => CursorGrabMode::None, CursorGrabMode::Locked => CursorGrabMode::None, }; window.cursor.visible = !window.cursor.visible; } /// Grabs the cursor when game first starts fn initial_grab_cursor(mut windows: Query<(&mut Window, With)>) { match windows.get_single_mut() { Ok(mut window) => toggle_grab_cursor(&mut window.0), Err(_) => warn!("Primary window not found for `initial_grab_cursor`!"), } } /// Handles keyboard input and movement fn player_move( keys: Res>, time: Res