From 56fc163b5c72fabdb99543accb41447ebad05ae3 Mon Sep 17 00:00:00 2001 From: Franklin Blanco Date: Sat, 16 Sep 2023 13:19:33 -0700 Subject: [PATCH] Added shooting, recoil system like csgo with patterns, and set gun aim time to rebound_time --- src/comps/core/controller.rs | 2 +- src/comps/core/markers/firearm.rs | 23 ++++- src/comps/core/markers/holdable.rs | 3 + src/logic/core/guns/firearm.rs | 30 +++++- src/logic/core/guns/mod.rs | 2 + src/logic/core/guns/player_firing.rs | 28 ++++++ src/logic/core/guns/spawn_firearm.rs | 15 ++- src/logic/core/guns/spray_pattern.rs | 6 ++ src/logic/core/player/camera_player_sync.rs | 56 +++++++---- src/logic/core/player/hands.rs | 102 +++++++++++++++----- src/main.rs | 5 +- src/scenes/scene1/init.rs | 6 +- 12 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 src/logic/core/guns/player_firing.rs create mode 100644 src/logic/core/guns/spray_pattern.rs diff --git a/src/comps/core/controller.rs b/src/comps/core/controller.rs index 1bf224a..8cbb661 100644 --- a/src/comps/core/controller.rs +++ b/src/comps/core/controller.rs @@ -50,4 +50,4 @@ pub fn capture_input( }; move_player(player_movement_input, player_query, time); } -} \ No newline at end of file +} diff --git a/src/comps/core/markers/firearm.rs b/src/comps/core/markers/firearm.rs index 50fffde..70302f6 100644 --- a/src/comps/core/markers/firearm.rs +++ b/src/comps/core/markers/firearm.rs @@ -1,6 +1,6 @@ -use bevy::prelude::{Component, Vec3}; +use bevy::prelude::{Component, Quat, Vec3}; -use crate::logic::core::guns::caliber::Caliber; +use crate::logic::core::guns::{caliber::Caliber, spray_pattern::FirearmSprayPattern}; #[derive(Component)] pub struct FirearmData<'a> { @@ -10,8 +10,21 @@ pub struct FirearmData<'a> { /// Placeholder until mags get implemented pub max_capacity: u32, /// Rounds per minute - pub fire_rate: u32, - /// Amount of ms it takes for gun to come down from shooting - pub rebound_time_millis: i64, + pub fire_rate: f32, + /// Amount of seconds it takes for gun to come down from shooting + pub rebound_time_seconds: f32, pub asset_path: &'a str, + + pub vertical_recoil_modifier: f32, + pub horizontal_recoil_modifier: f32, + pub recoil_pattern: FirearmSprayPattern, + + /// Final rotation of hands when aimed in + pub final_aimed_rotation: Quat, + /// Final rotation of hands when not aimed in + pub final_rotation: Quat, + /// Final position of hands when aimed in + pub final_aimed_position: Vec3, + /// Final position of hands when not aimed in + pub final_position: Vec3, } diff --git a/src/comps/core/markers/holdable.rs b/src/comps/core/markers/holdable.rs index b9db35d..c8cbed2 100644 --- a/src/comps/core/markers/holdable.rs +++ b/src/comps/core/markers/holdable.rs @@ -8,3 +8,6 @@ pub struct HoldableObjectData { /// Initial Rotation in degrees pub y_rot: f32, } + +#[derive(Component)] +pub struct InPlayerHands; diff --git a/src/logic/core/guns/firearm.rs b/src/logic/core/guns/firearm.rs index 908981b..3e2c32a 100644 --- a/src/logic/core/guns/firearm.rs +++ b/src/logic/core/guns/firearm.rs @@ -1,7 +1,7 @@ use crate::comps::core::markers::{firearm::FirearmData, holdable::HoldableObjectData}; use bevy::prelude::*; -use super::caliber::Caliber; +use super::{caliber::Caliber, spray_pattern::FirearmSprayPattern}; pub enum Firearm { M4A1, @@ -13,9 +13,33 @@ impl Firearm { firing_point: Vec3::ZERO, caliber: Caliber::NATO556, max_capacity: 30, - fire_rate: 800, - rebound_time_millis: 10, + fire_rate: 800.0, + rebound_time_seconds: 0.1, + vertical_recoil_modifier: 2.0, + horizontal_recoil_modifier: 0.5, + recoil_pattern: FirearmSprayPattern { + vertical: Vec::from([ + 1.0, 1.2, 1.3, 1.6, 1.5, 1.7, 1.5, 1.5, 1.5, 2.0 + ]), + horizontal: Vec::from([ + 1.0, 1.2, 1.3, -1.6, 1.5, -1.7, -1.5, 1.5, -1.5, 2.0 + ]), + }, asset_path: "weapons/m4a1_rifle.glb#Scene0", + + final_aimed_rotation: Quat::from_rotation_x(0.026), + final_rotation: Quat::default(), + final_aimed_position: Vec3 { + x: -0.003, + y: -0.35, + z: -1.6, + }, + final_position: Vec3 { + x: 0.6, + y: -0.45, + z: -2.7, + }, + } } pub fn holdable_object_data(&self) -> HoldableObjectData { diff --git a/src/logic/core/guns/mod.rs b/src/logic/core/guns/mod.rs index 3fb7b2e..b370c15 100644 --- a/src/logic/core/guns/mod.rs +++ b/src/logic/core/guns/mod.rs @@ -1,3 +1,5 @@ pub mod caliber; pub mod firearm; +pub mod player_firing; pub mod spawn_firearm; +pub mod spray_pattern; \ No newline at end of file diff --git a/src/logic/core/guns/player_firing.rs b/src/logic/core/guns/player_firing.rs new file mode 100644 index 0000000..49ceba7 --- /dev/null +++ b/src/logic/core/guns/player_firing.rs @@ -0,0 +1,28 @@ +use std::time::Duration; + +use bevy::prelude::*; + +#[derive(Resource, Reflect)] +#[reflect(Resource)] +pub struct PlayerFiringInfo { + /// Timestamp since last round fired from the gun. (seconds) + pub last_shot_timestamp: f32, + /// How many rounds were fired in the last sray + pub rounds_in_last_spray: i32, + /// What round the player is currently at. + /// This is pretty much a multiplier for the recoil, since the higher the round index the higher the recoil. + /// Decreases with time, each gun has its own rebound time + pub current_round_index: usize, + pub full_auto_timer: Timer, +} + +impl Default for PlayerFiringInfo { + fn default() -> Self { + Self { + last_shot_timestamp: Default::default(), + rounds_in_last_spray: Default::default(), + current_round_index: Default::default(), + full_auto_timer: Timer::new(Duration::from_secs_f32(0.0), TimerMode::Repeating), + } + } +} diff --git a/src/logic/core/guns/spawn_firearm.rs b/src/logic/core/guns/spawn_firearm.rs index 5688b0e..fa978a0 100644 --- a/src/logic/core/guns/spawn_firearm.rs +++ b/src/logic/core/guns/spawn_firearm.rs @@ -1,14 +1,20 @@ +use std::time::Duration; + use bevy::prelude::*; use crate::{ - comps::core::markers::player::PlayerHand, constants::player_values::DEFAULT_PLAYER_FIREARM, + comps::core::markers::{holdable::InPlayerHands, player::PlayerHand}, + constants::player_values::DEFAULT_PLAYER_FIREARM, utils, }; +use super::player_firing::PlayerFiringInfo; + pub fn spawn_firearm_on_player_hands( mut commands: Commands, query: Query>, asset_server: Res, + mut player_firing_info: ResMut, ) { for entity in query.iter() { let mut firearm_transform = Transform::from_xyz(0.0, 0.0, 0.0); @@ -25,9 +31,16 @@ pub fn spawn_firearm_on_player_hands( }, DEFAULT_PLAYER_FIREARM.firearm_data(), DEFAULT_PLAYER_FIREARM.holdable_object_data(), + InPlayerHands, )) .id(); commands.entity(entity).push_children(&[firearm]); + let time_in_secs_between_each_round = + 1.0 / DEFAULT_PLAYER_FIREARM.firearm_data().fire_rate * 60.0; + player_firing_info.full_auto_timer = Timer::new( + Duration::from_secs_f32(time_in_secs_between_each_round), + TimerMode::Once, + ); } } diff --git a/src/logic/core/guns/spray_pattern.rs b/src/logic/core/guns/spray_pattern.rs new file mode 100644 index 0000000..fed82c6 --- /dev/null +++ b/src/logic/core/guns/spray_pattern.rs @@ -0,0 +1,6 @@ + + +pub struct FirearmSprayPattern { + pub vertical: Vec, + pub horizontal: Vec, +} diff --git a/src/logic/core/player/camera_player_sync.rs b/src/logic/core/player/camera_player_sync.rs index 5aba2bf..7da1009 100644 --- a/src/logic/core/player/camera_player_sync.rs +++ b/src/logic/core/player/camera_player_sync.rs @@ -3,7 +3,8 @@ use bevy::{input::mouse::MouseMotion, prelude::*, window::CursorGrabMode}; use crate::{ comps::core::markers::{camera::MainCamera, player::Player}, - constants::player_values::{PLAYER_CAMERA_HEIGHT, PLAYER_CROUCH_HEIGHT, PLAYER_CROUCH_TIME_S}, utils::rad_deg::radians_from_degrees, + constants::player_values::{PLAYER_CAMERA_HEIGHT, PLAYER_CROUCH_HEIGHT, PLAYER_CROUCH_TIME_S}, + utils::rad_deg::radians_from_degrees, }; use super::player_movement::PlayerLinearXZState; @@ -42,12 +43,25 @@ pub fn update_camera_vertical_position( if let PlayerLinearXZState::Crouched(since) = player_linear_xz_state { // Lerp/Smooth out this movement let delta = time.elapsed().as_secs_f32() - since; - camera_transform.translation = camera_transform.translation.lerp(Vec3 { x: camera_transform.translation.x, y: PLAYER_CROUCH_HEIGHT, z: camera_transform.translation.z }, (delta / PLAYER_CROUCH_TIME_S).clamp(0.0, 1.0)); + camera_transform.translation = camera_transform.translation.lerp( + Vec3 { + x: camera_transform.translation.x, + y: PLAYER_CROUCH_HEIGHT, + z: camera_transform.translation.z, + }, + (delta / PLAYER_CROUCH_TIME_S).clamp(0.0, 1.0), + ); } else { // TODO: Add elapsed time to standup so that crouch time and standup time is the same. - camera_transform.translation = camera_transform.translation.lerp(Vec3 { x: camera_transform.translation.x, y: PLAYER_CAMERA_HEIGHT, z: camera_transform.translation.z }, time.delta_seconds().clamp(0.0, 1.0)); + camera_transform.translation = camera_transform.translation.lerp( + Vec3 { + x: camera_transform.translation.x, + y: PLAYER_CAMERA_HEIGHT, + z: camera_transform.translation.z, + }, + time.delta_seconds().clamp(0.0, 1.0), + ); } - } /// Handles looking around if cursor is locked @@ -66,14 +80,14 @@ pub fn follow_cursor_with_camera( // 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 keyboard_input.just_pressed(KeyCode::Escape) { window.cursor.grab_mode = CursorGrabMode::None; // also hide the cursor @@ -86,35 +100,43 @@ pub fn follow_cursor_with_camera( for motion in motions.iter() { let window_scale = window.height().min(window.width()); if btn.pressed(MouseButton::Right) { - pitch -= (settings.aimed_sensitivity * motion.delta.y * window_scale).to_radians(); - yaw -= (settings.aimed_sensitivity * motion.delta.x * window_scale).to_radians(); + pitch -= (settings.aimed_sensitivity * motion.delta.y * window_scale) + .to_radians(); + yaw -= (settings.aimed_sensitivity * motion.delta.x * window_scale) + .to_radians(); } else { - pitch -= (settings.sensitivity * motion.delta.y * window_scale).to_radians(); + 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() { player_transform.rotation = desired_rotation_quat; if keyboard_input.pressed(KeyCode::Q) { let final_quat = Quat::from_axis_angle(Vec3::Z, radians_from_degrees(30.0)); - camera_transform.rotation = camera_transform.rotation.lerp(final_quat, time.delta_seconds() / 0.2); + camera_transform.rotation = camera_transform + .rotation + .lerp(final_quat, time.delta_seconds() / 0.2); } else if keyboard_input.pressed(KeyCode::E) { - let final_quat = Quat::from_axis_angle(Vec3::Z, radians_from_degrees(-30.0)); - camera_transform.rotation = camera_transform.rotation.lerp(final_quat, time.delta_seconds() / 0.2); + let final_quat = + Quat::from_axis_angle(Vec3::Z, radians_from_degrees(-30.0)); + camera_transform.rotation = camera_transform + .rotation + .lerp(final_quat, time.delta_seconds() / 0.2); } else { - camera_transform.rotation = camera_transform.rotation.lerp(Quat::default(), time.delta_seconds() / 0.2); + camera_transform.rotation = camera_transform + .rotation + .lerp(Quat::default(), time.delta_seconds() / 0.2); } // headbob_camera(&mut camera_transform, time.delta_seconds_f64()); } } } - } else { warn!("Primary window not found for `player_look`!"); } diff --git a/src/logic/core/player/hands.rs b/src/logic/core/player/hands.rs index cc31cd2..bc6a36c 100644 --- a/src/logic/core/player/hands.rs +++ b/src/logic/core/player/hands.rs @@ -1,33 +1,91 @@ use bevy::prelude::*; -use crate::comps::core::markers::player::PlayerHand; +use crate::{ + comps::core::markers::{firearm::FirearmData, holdable::InPlayerHands, player::PlayerHand}, + logic::core::guns::player_firing::PlayerFiringInfo, utils::rad_deg::radians_from_degrees, +}; pub fn capture_hand_usage( mouse_buttons: Res>, - mut query: Query<&mut Transform, With>, + mut hand_query: Query<&mut Transform, With>, time: Res