use bevy::prelude::*; use bevy::input::mouse::MouseMotion; use bevy::window::PrimaryWindow; use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings}; use bevy_xpbd_3d::prelude::*; use std::f32::consts::*; use crate::{settings, audio, actor}; pub struct CameraControllerPlugin; impl Plugin for CameraControllerPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup_camera); app.add_systems(Update, handle_input); app.add_systems(Update, manage_player_actor); app.add_systems(Update, run_camera_controller); } } // Based on Valorant's default sensitivity, not entirely sure why it is exactly 1.0 / 180.0, // but I'm guessing it is a misunderstanding between degrees/radians and then sticking with // it because it felt nice. pub const RADIANS_PER_DOT: f32 = 1.0 / 180.0; #[derive(Component)] pub struct CameraController { pub enabled: bool, pub initialized: bool, pub sensitivity: f32, pub pitch: f32, pub yaw: f32, } impl Default for CameraController { fn default() -> Self { Self { enabled: true, initialized: false, sensitivity: 0.5, pitch: 1.0, // pitch=0/yaw=0 -> face sun yaw: 0.3, } } } fn setup_camera( mut commands: Commands, ) { // Add player commands.spawn(( Camera3dBundle { camera: Camera { hdr: true, // HDR is required for bloom ..default() }, transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, CameraController::default(), BloomSettings { composite_mode: BloomCompositeMode::EnergyConserving, ..default() }, )); } pub fn handle_input( keyboard_input: Res>, mut settings: ResMut, ) { if keyboard_input.just_pressed(settings.key_camera) { settings.third_person ^= true; } } fn manage_player_actor( settings: Res, mut q_playercam: Query<&mut Visibility, With> ) { for mut vis in &mut q_playercam { if settings.third_person { *vis = Visibility::Inherited; } else { *vis = Visibility::Hidden; } } } #[allow(clippy::too_many_arguments)] fn run_camera_controller( time: Res