FPS camera done. Camera rotates but player doesn't
This commit is contained in:
parent
8ed0ba71fe
commit
146be24a7c
|
@ -1,4 +1,4 @@
|
||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, window::CursorGrabMode};
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
use crate::logic::core::player::player_movement::{PlayerMovementInput, move_player, PlayerLinearYState};
|
use crate::logic::core::player::player_movement::{PlayerMovementInput, move_player, PlayerLinearYState};
|
||||||
|
@ -6,7 +6,7 @@ use crate::logic::core::player::player_movement::{PlayerMovementInput, move_play
|
||||||
use super::markers::player::Player;
|
use super::markers::player::Player;
|
||||||
|
|
||||||
/// System that captures input and fires events
|
/// System that captures input and fires events
|
||||||
pub fn capture_input(keyboard_input: Res<Input<KeyCode>>, query: Query<(&mut Velocity, &mut ExternalImpulse, &mut PlayerLinearYState), With<Player>>, time: Res<Time>) {
|
pub fn capture_input(keyboard_input: Res<Input<KeyCode>>, query: Query<(&mut Velocity, &mut ExternalImpulse, &mut PlayerLinearYState, &Transform), With<Player>>, time: Res<Time>) {
|
||||||
// Don't allocate on each frame. Instead Check if any of the inputs are being pressed and then allocate.
|
// Don't allocate on each frame. Instead Check if any of the inputs are being pressed and then allocate.
|
||||||
if keyboard_input.any_pressed([KeyCode::A, KeyCode::S, KeyCode::D, KeyCode::W, KeyCode::C, KeyCode::Space]) {
|
if keyboard_input.any_pressed([KeyCode::A, KeyCode::S, KeyCode::D, KeyCode::W, KeyCode::C, KeyCode::Space]) {
|
||||||
let player_movement_input = PlayerMovementInput {
|
let player_movement_input = PlayerMovementInput {
|
||||||
|
@ -22,3 +22,28 @@ pub fn capture_input(keyboard_input: Res<Input<KeyCode>>, query: Query<(&mut Vel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn capture_cursor(
|
||||||
|
mut windows: Query<&mut Window>,
|
||||||
|
btn: Res<Input<MouseButton>>,
|
||||||
|
key: Res<Input<KeyCode>>,
|
||||||
|
) {
|
||||||
|
let mut window = windows.single_mut();
|
||||||
|
|
||||||
|
if btn.just_pressed(MouseButton::Left) {
|
||||||
|
// if you want to use the cursor, but not let it leave the window,
|
||||||
|
// use `Confined` mode:
|
||||||
|
// window.cursor.grab_mode = CursorGrabMode::Confined;
|
||||||
|
|
||||||
|
// for a game that doesn't use the cursor (like a shooter):
|
||||||
|
// use `Locked` mode to keep the cursor in one place
|
||||||
|
window.cursor.grab_mode = CursorGrabMode::Locked;
|
||||||
|
// also hide the cursor
|
||||||
|
window.cursor.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if key.just_pressed(KeyCode::Escape) {
|
||||||
|
window.cursor.grab_mode = CursorGrabMode::None;
|
||||||
|
// also hide the cursor
|
||||||
|
window.cursor.visible = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,67 @@
|
||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, input::mouse::MouseMotion};
|
||||||
|
//use bevy_rapier3d::prelude::*;
|
||||||
|
|
||||||
|
use crate::comps::core::{markers::player::Player, camera::MainCamera};
|
||||||
|
|
||||||
use crate::{comps::core::{markers::player::Player, camera::MainCamera}, utils::rad_deg::radians_from_degrees};
|
/// Mouse sensitivity and movement speed
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct MouseMovementSettings {
|
||||||
|
pub sensitivity: f32,
|
||||||
|
pub speed: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MouseMovementSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sensitivity: 0.0003,
|
||||||
|
speed: 12.,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Synchronizes camera's translation & rotation (only 1 axis) to player.
|
||||||
pub fn sync_camera_to_player(
|
pub fn sync_camera_to_player(
|
||||||
player: Query<&Transform, (With<Player>, Without<MainCamera>)>,
|
mut player: Query<&mut Transform, (With<Player>, Without<MainCamera>)>,
|
||||||
mut camera: Query<&mut Transform, (With<MainCamera>, Without<Player>)>,
|
mut camera: Query<&mut Transform, (With<MainCamera>, Without<Player>)>,
|
||||||
) {
|
) {
|
||||||
let Ok(player) = player.get_single() else { return };
|
let Ok(mut player) = player.get_single_mut() else { return };
|
||||||
let Ok(mut camera_transform) = camera.get_single_mut() else { return };
|
let Ok(mut camera_transform) = camera.get_single_mut() else { return };
|
||||||
|
|
||||||
camera_transform.translation = player.translation;
|
camera_transform.translation = player.translation;
|
||||||
camera_transform.rotation = player.rotation;
|
|
||||||
|
|
||||||
camera_transform.translation.y += 0.5;
|
camera_transform.translation.y += 0.5;
|
||||||
camera_transform.rotate_x(radians_from_degrees(-15.0)); // Make camera slightly point downward.
|
|
||||||
|
player.rotation = camera_transform.rotation;
|
||||||
|
|
||||||
|
//camera_transform.rotate_x(radians_from_degrees(-15.0)); // Make camera slightly point downward.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Handles looking around if cursor is locked
|
||||||
|
pub fn follow_cursor_with_camera(
|
||||||
|
settings: Res<MouseMovementSettings>,
|
||||||
|
primary_window: Query<&Window>,
|
||||||
|
mut motions: EventReader<MouseMotion>,
|
||||||
|
mut player_query: Query<&mut Transform, (With<Player>, Without<MainCamera>)>,
|
||||||
|
mut camera_query: Query<&mut Transform, (With<MainCamera>, Without<Player>)>,
|
||||||
|
) {
|
||||||
|
if let Ok(window) = primary_window.get_single() {
|
||||||
|
for player_transform in player_query.iter_mut() {
|
||||||
|
let (mut yaw, mut pitch, _) = player_transform.rotation.to_euler(EulerRot::YXZ);
|
||||||
|
for motion in motions.iter() {
|
||||||
|
let window_scale = window.height().min(window.width());
|
||||||
|
pitch -= (settings.sensitivity * motion.delta.y * window_scale).to_radians();
|
||||||
|
yaw -= (settings.sensitivity * motion.delta.x * window_scale).to_radians();
|
||||||
|
}
|
||||||
|
pitch = pitch.clamp(-1.54, 1.54);
|
||||||
|
|
||||||
|
let desired_rotation_quat = Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch);
|
||||||
|
|
||||||
|
for mut camera_transform in camera_query.iter_mut() {
|
||||||
|
camera_transform.rotation = desired_rotation_quat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("Primary window not found for `player_look`!");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -56,8 +56,8 @@ pub struct PlayerMovementInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies game logic to determine how player should move.
|
/// Applies game logic to determine how player should move.
|
||||||
pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<(&mut Velocity, &mut ExternalImpulse, &mut PlayerLinearYState), With<Player>>, time: Res<Time>,) {
|
pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<(&mut Velocity, &mut ExternalImpulse, &mut PlayerLinearYState, &Transform), With<Player>>, time: Res<Time>,) {
|
||||||
for (mut player_velocity, mut player_external_force, mut player_linear_y_state) in &mut query {
|
for (mut player_velocity, mut player_external_force, mut player_linear_y_state, player_transform) in &mut query {
|
||||||
let crouch_multiplier = if player_movement_input.down {
|
let crouch_multiplier = if player_movement_input.down {
|
||||||
0.25
|
0.25
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,17 +68,20 @@ pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<
|
||||||
} else {
|
} else {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
|
let local_z = player_transform.local_z();
|
||||||
|
let forward = -Vec3::new(local_z.x, 0.0, local_z.z);
|
||||||
|
let right = Vec3::new(local_z.z, 0.0, -local_z.x);
|
||||||
if player_movement_input.front {
|
if player_movement_input.front {
|
||||||
player_velocity.linvel.z = apply_movement_acceleration(player_velocity.linvel.z, false, time.delta_seconds(), sprint_multiplier);
|
player_velocity.linvel = apply_movement_acceleration_to_vec(forward, player_velocity.linvel, time.delta_seconds(), sprint_multiplier);
|
||||||
}
|
}
|
||||||
if player_movement_input.back {
|
if player_movement_input.back {
|
||||||
player_velocity.linvel.z = apply_movement_acceleration(player_velocity.linvel.z, true, time.delta_seconds(), 1.0);
|
player_velocity.linvel = apply_movement_acceleration_to_vec(-forward, player_velocity.linvel, time.delta_seconds(), 1.0);
|
||||||
}
|
}
|
||||||
if player_movement_input.right {
|
if player_movement_input.right {
|
||||||
player_velocity.linvel.x = apply_movement_acceleration(player_velocity.linvel.x, true, time.delta_seconds(), 1.0);
|
player_velocity.linvel = apply_movement_acceleration_to_vec(right, player_velocity.linvel, time.delta_seconds(), 1.0);
|
||||||
}
|
}
|
||||||
if player_movement_input.left {
|
if player_movement_input.left {
|
||||||
player_velocity.linvel.x = apply_movement_acceleration(player_velocity.linvel.x, false, time.delta_seconds(), 1.0);
|
player_velocity.linvel = apply_movement_acceleration_to_vec(-right, player_velocity.linvel, time.delta_seconds(), 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if player_movement_input.up && player_linear_y_state.is_grounded(&PLAYER_JUMP_COOLDOWN_MS) {
|
if player_movement_input.up && player_linear_y_state.is_grounded(&PLAYER_JUMP_COOLDOWN_MS) {
|
||||||
|
@ -91,7 +94,7 @@ pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<
|
||||||
if positive { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier * sprint_multiplier }
|
if positive { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier * sprint_multiplier }
|
||||||
else { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
else { player_velocity.linvel.x = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
||||||
}
|
}
|
||||||
if player_velocity.linvel.z.abs() > MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier {
|
if player_velocity.linvel.z.abs() > MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier * sprint_multiplier{
|
||||||
let positive = player_velocity.linvel.z.is_sign_positive();
|
let positive = player_velocity.linvel.z.is_sign_positive();
|
||||||
if positive { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier }
|
if positive { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * crouch_multiplier }
|
||||||
else { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
else { player_velocity.linvel.z = MAX_LINEAR_PLAYER_VELOCITY * -1.0 * crouch_multiplier }
|
||||||
|
@ -99,21 +102,10 @@ pub fn move_player(player_movement_input: PlayerMovementInput, mut query: Query<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// currentLinearVelocity + Acceleration * deltaTime
|
// currentLinearVelocity + Acceleration * deltaTime
|
||||||
fn apply_movement_acceleration(current_linvel: f32, positive: bool, delta_time_secs: f32, multiplier: f32) -> f32 {
|
fn apply_movement_acceleration_to_vec(direction: Vec3, current_linvel: Vec3, delta_time_secs: f32, multiplier: f32) -> Vec3 {
|
||||||
if positive {
|
current_linvel + (
|
||||||
if current_linvel.is_sign_positive() {
|
direction * PLAYER_ACCELERATION * delta_time_secs * multiplier
|
||||||
current_linvel + PLAYER_ACCELERATION * delta_time_secs * multiplier
|
)
|
||||||
} else {
|
|
||||||
// Make it so deacceleration is faster
|
|
||||||
current_linvel + (PLAYER_ACCELERATION * delta_time_secs * 2.0) * multiplier
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if current_linvel.is_sign_negative() {
|
|
||||||
current_linvel - PLAYER_ACCELERATION * delta_time_secs * multiplier
|
|
||||||
} else {
|
|
||||||
// Make it so deacceleration is faster
|
|
||||||
current_linvel - (PLAYER_ACCELERATION * delta_time_secs * 2.0) * multiplier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -10,12 +10,12 @@ pub fn spawn_player(mut commands: Commands) {
|
||||||
.insert(RigidBody::Dynamic)
|
.insert(RigidBody::Dynamic)
|
||||||
.insert(GravityScale(2.5))
|
.insert(GravityScale(2.5))
|
||||||
.insert(Collider::capsule_y(2.0, 2.0))
|
.insert(Collider::capsule_y(2.0, 2.0))
|
||||||
.insert(Restitution::coefficient(0.3))
|
.insert(Restitution::coefficient(0.0))
|
||||||
.insert(Friction { coefficient: 0.0, ..Default::default() })
|
.insert(Friction { coefficient: 0.0, ..Default::default() })
|
||||||
.insert(TransformBundle::from(Transform::from_xyz(3.0, 5.0, 2.0)))
|
.insert(TransformBundle{ local: Transform::from_xyz(3.0, 5.0, 2.0), global: Default::default() })
|
||||||
.insert(Velocity::zero())
|
.insert(Velocity::zero())
|
||||||
.insert(Damping { linear_damping: 1.0, angular_damping: 1.0 })
|
.insert(Damping { linear_damping: 1.0, angular_damping: 1.0 })
|
||||||
.insert(LockedAxes::ROTATION_LOCKED_X | LockedAxes::ROTATION_LOCKED_Z | LockedAxes::ROTATION_LOCKED_Y)
|
.insert(LockedAxes::ROTATION_LOCKED_Z | LockedAxes::ROTATION_LOCKED_X )
|
||||||
.insert(ColliderMassProperties::Density(2.0))
|
.insert(ColliderMassProperties::Density(2.0))
|
||||||
.insert(ExternalImpulse {
|
.insert(ExternalImpulse {
|
||||||
impulse: Vec3::ZERO,
|
impulse: Vec3::ZERO,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::{logic::core::player::{spawn_player::spawn_player, camera_player_sync::sync_camera_to_player, player_vertical_sync::sync_player_y_state}, comps::core::controller::capture_input};
|
use crate::{logic::core::player::{spawn_player::spawn_player, camera_player_sync::{sync_camera_to_player, MouseMovementSettings, follow_cursor_with_camera}, player_vertical_sync::sync_player_y_state}, comps::core::controller::{capture_input, capture_cursor}};
|
||||||
|
|
||||||
use super::{ground::spawn_ground, lighting::setup_lighting, obstacles::spawn_obstacles};
|
use super::{ground::spawn_ground, lighting::setup_lighting, obstacles::spawn_obstacles};
|
||||||
|
|
||||||
|
|
||||||
pub fn load_scene(application: &mut App) {
|
pub fn load_scene(application: &mut App) {
|
||||||
|
application.insert_resource(MouseMovementSettings::default());
|
||||||
// Startup
|
// Startup
|
||||||
application.add_systems(Startup, spawn_ground);
|
application.add_systems(Startup, spawn_ground);
|
||||||
application.add_systems(Startup, spawn_obstacles);
|
application.add_systems(Startup, spawn_obstacles);
|
||||||
|
@ -15,7 +16,9 @@ pub fn load_scene(application: &mut App) {
|
||||||
// Update
|
// Update
|
||||||
application.add_systems(Update, capture_input);
|
application.add_systems(Update, capture_input);
|
||||||
application.add_systems(Update, sync_camera_to_player);
|
application.add_systems(Update, sync_camera_to_player);
|
||||||
|
application.add_systems(Update, capture_cursor);
|
||||||
application.add_systems(Update, sync_player_y_state);
|
application.add_systems(Update, sync_player_y_state);
|
||||||
|
application.add_systems(Update, follow_cursor_with_camera);
|
||||||
|
|
||||||
application.add_systems(Startup, setup_lighting);
|
application.add_systems(Startup, setup_lighting);
|
||||||
}
|
}
|
Loading…
Reference in New Issue