use crate::{
components::DebugCamera,
resources::{ActiveGamepad, DebugCameraActive, GamepadBindings, KeyboardBindings},
};
use bevy::{
input::{
gamepad::{GamepadButton, GamepadConnection, GamepadEvent, GamepadSettings},
mouse::MouseMotion,
},
prelude::*,
utils::tracing::{event, Level},
window::CursorGrabMode,
};
#[allow(clippy::too_many_arguments)]
pub fn camera_movement_system(
mut q: Query<&mut DebugCamera>,
time: Res<Time>,
keys: Res<Input<KeyCode>>,
debug_camera_active: Res<DebugCameraActive>,
keyboard_bindings: Res<KeyboardBindings>,
gamepad_bindings: Res<GamepadBindings>,
mut motion_evr: EventReader<MouseMotion>,
axes: Res<Axis<GamepadAxis>>,
buttons: Res<Input<GamepadButton>>,
button_axes: Res<Axis<GamepadButton>>,
active_gamepad: ResMut<ActiveGamepad>,
) {
if !(debug_camera_active.gamepad || debug_camera_active.keymouse) {
return;
}
let mut rotate_vec = Vec3::default();
let mut local_translate_vec = Vec3::default();
if debug_camera_active.gamepad {
if let Some(gamepad) = active_gamepad.0 {
if let (Some(x), Some(y), Some(down), Some(up)) = (
axes.get(GamepadAxis::new(gamepad, gamepad_bindings.left_right)),
axes.get(GamepadAxis::new(gamepad, gamepad_bindings.fwd_bwd)),
button_axes.get(GamepadButton::new(gamepad, gamepad_bindings.down)),
button_axes.get(GamepadButton::new(gamepad, gamepad_bindings.up)),
) {
let up_down = up - down;
local_translate_vec += time.delta_seconds() * Vec3::new(y, up_down, x);
}
if let (Some(x), Some(y), roll_left, roll_right) = (
axes.get(GamepadAxis::new(gamepad, gamepad_bindings.yaw)),
axes.get(GamepadAxis::new(gamepad, gamepad_bindings.pitch)),
buttons.pressed(GamepadButton::new(gamepad, gamepad_bindings.roll_left)),
buttons.pressed(GamepadButton::new(gamepad, gamepad_bindings.roll_right)),
) {
let roll = buttons_to_dir(roll_right, roll_left);
rotate_vec += time.delta_seconds() * Vec3::new(-x, y, roll);
}
}
}
if debug_camera_active.keymouse {
let key_fwd = keys.pressed(keyboard_bindings.fwd);
let key_bwd = keys.pressed(keyboard_bindings.bwd);
let key_up = keys.pressed(keyboard_bindings.up);
let key_down = keys.pressed(keyboard_bindings.down);
let key_left = keys.pressed(keyboard_bindings.left);
let key_right = keys.pressed(keyboard_bindings.right);
let key_roll_left = keys.pressed(keyboard_bindings.roll_left);
let key_roll_right = keys.pressed(keyboard_bindings.roll_right);
let mouse_delta = {
let mut d = Vec2::default();
for ev in motion_evr.iter() {
d -= ev.delta;
}
d
};
local_translate_vec += time.delta_seconds()
* 0.5
* Vec3::new(
buttons_to_dir(key_fwd, key_bwd),
buttons_to_dir(key_up, key_down),
buttons_to_dir(key_right, key_left),
);
rotate_vec += time.delta_seconds()
* 0.5
* Vec3::new(
mouse_delta.x,
mouse_delta.y,
buttons_to_dir(key_roll_right, key_roll_left),
);
}
for mut controlled_camera in q.iter_mut() {
let mut right = controlled_camera.fwd.cross(controlled_camera.up);
controlled_camera.up = right.cross(controlled_camera.fwd);
controlled_camera.fwd = controlled_camera.up.cross(right);
controlled_camera.up = controlled_camera.up.normalize();
controlled_camera.fwd = controlled_camera.fwd.normalize();
right = controlled_camera.fwd.cross(controlled_camera.up);
let basis_matrix = Mat3::from_cols(controlled_camera.fwd, controlled_camera.up, right);
let speed_translate = controlled_camera.speed_translate;
controlled_camera.position += speed_translate * (basis_matrix * local_translate_vec);
let x_rot_quat = Quat::from_axis_angle(
controlled_camera.up,
rotate_vec.x * controlled_camera.speed_rotate,
);
controlled_camera.fwd = x_rot_quat * controlled_camera.fwd;
right = x_rot_quat * right;
let y_rot_quat =
Quat::from_axis_angle(right, rotate_vec.y * controlled_camera.speed_rotate);
controlled_camera.fwd = y_rot_quat * controlled_camera.fwd;
controlled_camera.up = y_rot_quat * controlled_camera.up;
let z_rot_quat = Quat::from_axis_angle(
controlled_camera.fwd,
rotate_vec.z * controlled_camera.speed_rotate,
);
controlled_camera.up = z_rot_quat * controlled_camera.up;
}
}
pub fn camera_update_system(
mut q: Query<(&mut Transform, &DebugCamera), With<Camera>>,
debug_camera_active: Res<DebugCameraActive>,
) {
if debug_camera_active.gamepad || debug_camera_active.keymouse {
for (mut transform, controlled_camera) in q.iter_mut() {
*transform = Transform::from_translation(controlled_camera.position).looking_at(
controlled_camera.position + controlled_camera.fwd,
controlled_camera.up,
);
}
}
}
pub fn cursor_grab_system(
mut windows: Query<&mut Window>,
debug_camera_active: Res<DebugCameraActive>,
) {
if debug_camera_active.keymouse {
if let Some(mut window) = windows.iter_mut().next() {
window.cursor.grab_mode = CursorGrabMode::Locked;
window.cursor.visible = false;
}
}
}
pub fn gamepad_connections(
mut active_gamepad: ResMut<ActiveGamepad>,
mut gamepad_evr: EventReader<GamepadEvent>,
mut settings: ResMut<GamepadSettings>,
) {
for ev in gamepad_evr.iter() {
if let GamepadEvent::Connection(conn_event) = ev {
let id = conn_event.gamepad;
match &conn_event.connection {
GamepadConnection::Connected(info) => {
if active_gamepad.0.is_none() {
event!(
Level::INFO,
event = "active_gamepad_set",
gamepad_name = info.name,
gamepad_id = id.id,
);
active_gamepad.0 = Some(id);
settings.default_axis_settings.set_deadzone_lowerbound(-0.1);
settings.default_axis_settings.set_deadzone_upperbound(0.1);
}
}
GamepadConnection::Disconnected => {
let mut remove_gamepad = false;
if let Some(old_id) = active_gamepad.0 {
if old_id == id {
event!(
Level::INFO,
event = "active_gamepad_removed",
gamepad_id = id.id,
);
remove_gamepad = true;
}
}
if remove_gamepad {
active_gamepad.0 = None;
}
}
}
}
}
}
fn buttons_to_dir(positive: bool, negative: bool) -> f32 {
if positive == negative {
0.
} else if positive {
1.
} else {
-1.
}
}