outfly/src/camera.rs

188 lines
6.4 KiB
Rust
Raw Normal View History

use bevy::prelude::*;
use bevy::input::mouse::MouseMotion;
2024-03-16 23:24:47 +00:00
use bevy::window::PrimaryWindow;
2024-03-18 03:39:26 +00:00
use std::f32::consts::*;
2024-03-21 17:45:43 +00:00
use crate::{settings, audio, actor};
pub struct CameraControllerPlugin;
impl Plugin for CameraControllerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, run_camera_controller);
}
}
2024-03-18 03:39:26 +00:00
// 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.
2024-03-18 02:06:41 +00:00
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 move_speed: f32,
pub friction: f32,
pub pitch: f32,
pub yaw: f32,
pub velocity: Vec3,
}
impl Default for CameraController {
fn default() -> Self {
Self {
enabled: true,
initialized: false,
2024-03-18 02:06:41 +00:00
sensitivity: 0.5,
2024-03-21 18:01:18 +00:00
move_speed: 30.0,
friction: 0.05,
2024-03-18 02:13:44 +00:00
pitch: 1.0, // pitch=0/yaw=0 -> face sun
yaw: 0.3,
velocity: Vec3::ZERO,
}
}
}
#[allow(clippy::too_many_arguments)]
fn run_camera_controller(
time: Res<Time>,
2024-03-18 03:10:08 +00:00
settings: Res<settings::Settings>,
2024-03-16 23:24:47 +00:00
mut windows: Query<&mut Window, With<PrimaryWindow>>,
mut mouse_events: EventReader<MouseMotion>,
key_input: Res<ButtonInput<KeyCode>>,
2024-03-16 23:41:06 +00:00
thruster_sound_controller: Query<&AudioSink, With<audio::ComponentThrusterSound>>,
2024-03-28 13:10:10 +00:00
rocket_sound_controller: Query<&AudioSink, With<audio::ComponentRocketSound>>,
2024-03-28 23:01:17 +00:00
mut q_engine: Query<&mut actor::Engine, With<actor::PlayerDrivesThis>>,
mut query: Query<(
&mut Transform,
&mut CameraController,
&mut Projection,
&mut actor::Actor,
&actor::LifeForm,
&mut actor::Engine
), (With<Camera>, Without<actor::PlayerDrivesThis>)>,
) {
let dt = time.delta_seconds();
2024-03-16 23:41:06 +00:00
let mut play_thruster_sound = false;
2024-03-16 23:24:47 +00:00
let window_result = windows.get_single_mut();
let mut focused = true;
if window_result.is_ok() {
focused = window_result.unwrap().focused;
}
2024-03-28 22:38:24 +00:00
if let Ok((mut transform, mut controller, mut projection, mut actor, lifeform, player_engine)) = query.get_single_mut() {
if !controller.initialized {
controller.initialized = true;
2024-03-18 02:13:44 +00:00
transform.rotation =
Quat::from_euler(EulerRot::ZYX, 0.0, controller.yaw, controller.pitch);
}
if !controller.enabled {
mouse_events.clear();
return;
}
// Handle key input
let mut axis_input = Vec3::ZERO;
2024-03-16 23:24:47 +00:00
if focused {
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_forward) {
2024-03-16 23:24:47 +00:00
axis_input.z += 1.0;
}
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_back) {
2024-03-16 23:24:47 +00:00
axis_input.z -= 1.0;
}
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_right) {
2024-03-16 23:24:47 +00:00
axis_input.x += 1.0;
}
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_left) {
2024-03-16 23:24:47 +00:00
axis_input.x -= 1.0;
}
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_up) {
2024-03-16 23:24:47 +00:00
axis_input.y += 1.0;
}
2024-03-18 03:39:26 +00:00
if key_input.pressed(settings.key_down) {
2024-03-16 23:24:47 +00:00
axis_input.y -= 1.0;
}
}
2024-03-21 17:45:43 +00:00
if key_input.pressed(settings.key_stop) {
2024-03-21 18:01:18 +00:00
actor.v = actor.v * (1.0 - controller.friction);
2024-03-21 17:45:43 +00:00
if actor.v.length_squared() < 1e-6 {
actor.v = Vec3::ZERO;
}
}
2024-03-18 03:39:26 +00:00
let friction = if key_input.pressed(settings.key_stop) {
2024-03-17 13:39:42 +00:00
controller.friction.clamp(0.0, 1.0)
} else {
0.0
};
2024-03-28 23:01:17 +00:00
let mut engine = if let Ok(engine) = q_engine.get_single_mut() { engine } else { player_engine };
// Apply movement update
if axis_input != Vec3::ZERO {
let new_velocity = controller.velocity + axis_input.normalize() * controller.move_speed;
controller.velocity = new_velocity;
2024-03-28 23:01:17 +00:00
engine.current_warmup = (engine.current_warmup + dt / engine.warmup_seconds).clamp(0.0, 1.0);
2024-03-18 03:10:08 +00:00
play_thruster_sound = !settings.mute_sfx;
} else {
controller.velocity *= 1.0 - friction;
2024-03-28 23:01:17 +00:00
engine.current_warmup = (engine.current_warmup - dt / engine.warmup_seconds).clamp(0.0, 1.0);
if controller.velocity.length_squared() < 1e-6 {
controller.velocity = Vec3::ZERO;
}
}
2024-03-28 23:01:17 +00:00
let forward = *transform.forward() * engine.current_warmup * (if axis_input.z > 0.0 {
engine.thrust_forward
} else {
engine.thrust_back
});
2024-03-28 23:01:17 +00:00
let right = *transform.right() * engine.thrust_sideways * engine.current_warmup;
2024-03-21 17:45:43 +00:00
actor.v += controller.velocity.x * dt * right
+ controller.velocity.y * dt * Vec3::Y
+ controller.velocity.z * dt * forward;
2024-03-21 17:45:43 +00:00
controller.velocity = Vec3::ZERO;
//transform.translation += controller.velocity.x * dt * right
//+ controller.velocity.y * dt * Vec3::Y
//+ controller.velocity.z * dt * forward;
// Handle mouse input
let mut mouse_delta = Vec2::ZERO;
2024-03-18 03:39:26 +00:00
for mouse_event in mouse_events.read() {
mouse_delta += mouse_event.delta;
}
if mouse_delta != Vec2::ZERO {
// Apply look update
controller.pitch = (controller.pitch
- mouse_delta.y * RADIANS_PER_DOT * controller.sensitivity)
.clamp(-PI / 2., PI / 2.);
controller.yaw -= mouse_delta.x * RADIANS_PER_DOT * controller.sensitivity;
transform.rotation =
Quat::from_euler(EulerRot::ZYX, 0.0, controller.yaw, controller.pitch);
}
2024-03-16 23:41:06 +00:00
2024-03-28 22:38:24 +00:00
let fov = (lifeform.adrenaline * lifeform.adrenaline * lifeform.adrenaline * 45.0 + 45.0).to_radians();
*projection = Projection::Perspective(PerspectiveProjection { fov: fov, ..default() });
2024-03-16 23:41:06 +00:00
if let Ok(sink) = thruster_sound_controller.get_single() {
2024-03-28 13:10:10 +00:00
if play_thruster_sound && engine.engine_type == actor::EngineType::Monopropellant {
sink.play()
} else {
sink.pause()
}
}
if let Ok(sink) = rocket_sound_controller.get_single() {
if play_thruster_sound && engine.engine_type == actor::EngineType::Rocket {
2024-03-16 23:41:06 +00:00
sink.play()
} else {
sink.pause()
}
}
}
}