Fix camera getting uneven, clamp top/bottom rotation

This commit is contained in:
Felix Ableitner 2021-01-02 19:26:37 +01:00
parent f2cb9f0cae
commit e31a473b3e

View file

@ -1,16 +1,17 @@
use bevy::{ use bevy::{
input::mouse::MouseMotion, input::mouse::MouseMotion,
prelude::*, prelude::*,
render::camera::{Camera, PerspectiveProjection, VisibleEntities}, render::camera::{PerspectiveProjection, VisibleEntities},
}; };
use bevy_rapier3d::{ use bevy_rapier3d::{
na::Matrix3x1, na::{clamp, wrap, Matrix3x1},
physics::RigidBodyHandleComponent, physics::RigidBodyHandleComponent,
rapier::{ rapier::{
dynamics::{RigidBody, RigidBodyBuilder, RigidBodySet}, dynamics::{RigidBody, RigidBodyBuilder, RigidBodySet},
geometry::ColliderBuilder, geometry::ColliderBuilder,
}, },
}; };
use std::f32::consts::{FRAC_PI_2, PI};
pub struct PlayerPlugin; pub struct PlayerPlugin;
@ -32,6 +33,12 @@ struct State {
#[derive(Default)] #[derive(Default)]
struct PlayerMarker; struct PlayerMarker;
#[derive(Default, Debug)]
struct CameraData {
yaw: f32,
pitch: f32,
}
#[derive(Bundle)] #[derive(Bundle)]
pub struct PlayerBundle { pub struct PlayerBundle {
pub perspective_projection: PerspectiveProjection, pub perspective_projection: PerspectiveProjection,
@ -60,7 +67,7 @@ impl Default for PlayerBundle {
} }
const PLAYER_SPEED: f32 = 320.0; const PLAYER_SPEED: f32 = 320.0;
const MOUSE_SENSITIVITY: f32 = 1.0; const MOUSE_SENSITIVITY: f32 = 0.5;
const PLAYER_HEIGHT: f32 = 1.8; const PLAYER_HEIGHT: f32 = 1.8;
const PLAYER_WIDTH: f32 = 0.25; const PLAYER_WIDTH: f32 = 0.25;
@ -68,10 +75,12 @@ fn init_player(commands: &mut Commands) {
commands commands
.spawn(PlayerBundle::default()) .spawn(PlayerBundle::default())
.with_children(|parent| { .with_children(|parent| {
parent.spawn(Camera3dBundle { parent
.spawn(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(0.0, PLAYER_HEIGHT / 2., 0.0)), transform: Transform::from_translation(Vec3::new(0.0, PLAYER_HEIGHT / 2., 0.0)),
..Default::default() ..Default::default()
}); })
.with(CameraData::default());
}); });
} }
@ -79,19 +88,18 @@ fn player_movement_system(
time: Res<Time>, time: Res<Time>,
mut bodies: ResMut<RigidBodySet>, mut bodies: ResMut<RigidBodySet>,
keyboard_input: Res<Input<KeyCode>>, keyboard_input: Res<Input<KeyCode>>,
// TODO: need to use better queries which filters by parent.player_marker camera_transform_query: Query<&Transform, With<CameraData>>,
camera_transform_query: Query<&Transform, With<Camera>>,
mut player_query: Query<&RigidBodyHandleComponent, With<PlayerMarker>>, mut player_query: Query<&RigidBodyHandleComponent, With<PlayerMarker>>,
) { ) {
for camera_transform in camera_transform_query.iter() { for camera_transform in camera_transform_query.iter() {
for body_handle in player_query.iter_mut() { for body_handle in player_query.iter_mut() {
let body: &mut RigidBody = bodies.get_mut(body_handle.handle()).unwrap(); let body: &mut RigidBody = bodies.get_mut(body_handle.handle()).unwrap();
let axis_straight = movement_axis(&keyboard_input, KeyCode::D, KeyCode::A); let axis_strafe = movement_axis(&keyboard_input, KeyCode::D, KeyCode::A);
let axis_strafe = movement_axis(&keyboard_input, KeyCode::S, KeyCode::W); let axis_straight = movement_axis(&keyboard_input, KeyCode::S, KeyCode::W);
let rotation = camera_transform.rotation; let rotation = camera_transform.rotation;
let mut speed_2d: Vec3 = let mut speed_2d: Vec3 =
(strafe_vector(&rotation) * axis_straight) + (forward_vector(&rotation) * axis_strafe); (strafe_vector(&rotation) * axis_strafe) + (forward_vector(&rotation) * axis_straight);
if speed_2d.length() != 0.0 { if speed_2d.length() != 0.0 {
speed_2d = speed_2d.normalize() * PLAYER_SPEED; speed_2d = speed_2d.normalize() * PLAYER_SPEED;
} }
@ -132,7 +140,7 @@ fn player_look_system(
time: Res<Time>, time: Res<Time>,
mut state: ResMut<State>, mut state: ResMut<State>,
mouse_motion_events: Res<Events<MouseMotion>>, mouse_motion_events: Res<Events<MouseMotion>>,
mut query: Query<&mut Transform, With<Camera>>, mut query: Query<(&mut Transform, &mut CameraData)>,
) { ) {
let mut delta: Vec2 = Vec2::zero(); let mut delta: Vec2 = Vec2::zero();
for event in state.mouse_motion_event_reader.iter(&mouse_motion_events) { for event in state.mouse_motion_event_reader.iter(&mouse_motion_events) {
@ -142,15 +150,22 @@ fn player_look_system(
return; return;
} }
// TODO: need to keep the camera level for (mut transform, mut data) in query.iter_mut() {
for mut transform in query.iter_mut() { data.yaw -= delta.y * MOUSE_SENSITIVITY * time.delta_seconds();
let yaw = -delta.y * MOUSE_SENSITIVITY * time.delta_seconds(); data.pitch -= delta.x * MOUSE_SENSITIVITY * time.delta_seconds();
let pitch = -delta.x * MOUSE_SENSITIVITY * time.delta_seconds(); // NOTE: if we just use FRAC_PI_2 here, for some reason it results in a blank screen when
// looking up/down
let half_pi = FRAC_PI_2 - 0.01;
data.yaw = clamp(data.yaw, -half_pi, half_pi);
data.pitch = wrap(data.pitch, -PI, PI);
let quat_yaw = Quat::from_axis_angle(Vec3::unit_x(), yaw); let quat_yaw = Quat::from_axis_angle(Vec3::unit_x(), data.yaw);
let quat_pitch = Quat::from_axis_angle(Vec3::unit_y(), pitch); let quat_pitch = Quat::from_axis_angle(Vec3::unit_y(), data.pitch);
let orientation_change: Quat = (quat_pitch * quat_yaw).normalize(); let mut orientation = Quat::identity();
transform.rotate(orientation_change); orientation = orientation * quat_yaw;
orientation = quat_pitch * orientation;
transform.rotation = orientation.normalize();
} }
} }