Shooting, weapon customization, magazine data in gun not in magazine

This commit is contained in:
Franklin 2023-11-21 14:35:26 -04:00
parent 312017c771
commit a447e49036
21 changed files with 311 additions and 231 deletions

Binary file not shown.

Binary file not shown.

View File

@ -7,14 +7,14 @@ use bevy_rapier3d::{dynamics::{RigidBody, GravityScale, ExternalImpulse}, geomet
use crate::{comps::core::{ use crate::{comps::core::{
grid::UGrid, grid::UGrid,
items::item::{Item, ItemType, ItemId}, items::item::{Item, ItemType, ItemId},
markers::{holdable::HoldableObjectType, interactable::Interactable}, inventory::slot::PlayerInventorySlotType, weapons::{firearm::Firearm, firearm_data::FirearmData}, events::pickup_item::ItemState, markers::{holdable::HoldableObjectType, interactable::Interactable, proxy::weapons::initial_attachments::InitialAttachments}, inventory::slot::PlayerInventorySlotType, weapons::{firearm::Firearm, firearm_data::FirearmData, attachments::weapon_attachment::WeaponAttachment}, events::pickup_item::ItemState,
}, setup::assets::{GltfAssets, GltfAssetType}, utils}; }, setup::assets::{GltfAssets, GltfAssetType}, utils};
#[derive(Component, Clone)] #[derive(Component, Clone)]
pub struct Ak105GunItem { pub struct Ak105GunItem {
pub id: ItemId, pub id: ItemId,
pub state: Mutex<Option<ItemState>>, pub state: Mutex<Option<ItemState>>,
pub initial_attachments: Option<InitialAttachments>,
} }
impl Item for Ak105GunItem { impl Item for Ak105GunItem {
@ -102,6 +102,9 @@ impl Item for Ak105GunItem {
Some(ref state) => { commands.entity(firearm_asset_entity).insert(state.clone()); }, Some(ref state) => { commands.entity(firearm_asset_entity).insert(state.clone()); },
None => {}, None => {},
}; };
if let Some(initial_attachments) = &self.initial_attachments {
commands.entity(firearm_asset_entity).insert(initial_attachments.clone());
}
let firearm_size = firearm.get_size(); let firearm_size = firearm.get_size();
commands commands
.spawn(( .spawn((

View File

@ -1,16 +1,13 @@
use crate::{ use crate::{
comps::core::{ comps::core::{
grid::UGrid, grid::UGrid,
markers::{holdable::HoldableObjectType, interactable::Interactable}, inventory::slot::PlayerInventorySlotType, weapons::{firearm_data::FirearmData, firearm::Firearm}, events::pickup_item::ItemState, markers::holdable::HoldableObjectType, inventory::slot::PlayerInventorySlotType, weapons::firearm::Firearm, events::pickup_item::ItemState,
}, },
setup::assets::{GltfAssetType, GltfAssets}, setup::assets::GltfAssets,
utils,
}; };
use bevy::{gltf::Gltf, prelude::*}; use bevy::{gltf::Gltf, prelude::*};
use bevy_rapier3d::prelude::*;
use uuid::Uuid; use uuid::Uuid;
#[allow(unused)]
pub enum ItemType { pub enum ItemType {
Holdable(HoldableObjectType), Holdable(HoldableObjectType),
Equippable, Equippable,

View File

@ -2,47 +2,49 @@ use bevy::{prelude::*, gltf::Gltf, ecs::system::SystemParam, scene::SceneInstanc
use crate::{comps::core::{weapons::{firearm::Firearm, firearm_state::FirearmState, slot::slot::WeaponSlot, attachment_slot::AttachmentSlot, attachments::weapon_attachment::WeaponAttachment}, events::pickup_item::ItemState, markers::holdable::InPlayerHands, inventory::player_inventory::PlayerInventory, items::item::ItemId}, setup::assets::{GltfAssets, GltfAssetType}}; use crate::{comps::core::{weapons::{firearm::Firearm, firearm_state::FirearmState, slot::slot::WeaponSlot, attachment_slot::AttachmentSlot, attachments::weapon_attachment::WeaponAttachment}, events::pickup_item::ItemState, markers::holdable::InPlayerHands, inventory::player_inventory::PlayerInventory, items::item::ItemId}, setup::assets::{GltfAssets, GltfAssetType}};
use super::initial_attachments::InitialAttachments;
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct InsertFirearmStateIntoFirearmsParams<'w, 's> { pub struct InsertFirearmStateIntoFirearmsParams<'w, 's> {
firearm_scene_bundle: Query<'w, 's, (Entity, Option<&'static ItemState>, &'static Children), With<SceneInstance>>, firearm_scene_bundle: Query<'w, 's, (Entity, Option<&'static ItemState>, Option<&'static InitialAttachments>, &'static Children), With<SceneInstance>>,
firearm_query: Query<'w, 's, (Entity, &'static Firearm, &'static Parent, Option<&'static FirearmState>), Or<(Without<FirearmState>, Changed<FirearmState>)>>, firearm_query: Query<'w, 's, (Entity, &'static Firearm, &'static Parent, Option<&'static mut FirearmState>), Or<(Without<FirearmState>, Changed<FirearmState>)>>,
slots_query: Query<'w, 's, (Entity, &'static WeaponSlot, &'static Parent)>, slots_query: Query<'w, 's, (Entity, &'static WeaponSlot, &'static Parent)>,
attachments_query: Query<'w, 's, (Entity, &'static WeaponAttachment, &'static Parent)>, attachments_query: Query<'w, 's, (Entity, &'static WeaponAttachment, &'static Parent)>,
in_player_hands_query: Query<'w, 's, &'static ItemId, With<InPlayerHands>>, in_player_hands_query: Query<'w, 's, &'static ItemId, With<InPlayerHands>>,
player_inventories_query: Query<'w, 's, &'static PlayerInventory> player_inventories_query: Query<'w, 's, &'static PlayerInventory>,
} }
/// This query inserts FirearmState into firearms, updates firearm assets that already have a FirearmState, /// This query inserts FirearmState into firearms, updates firearm assets that already have a FirearmState,
/// And Re-inserts FirearmState into spawned Firearms that have a passed in ItemState at the root of the SceneBundle /// And Re-inserts FirearmState into spawned Firearms that have a passed in ItemState at the root of the SceneBundle
pub fn insert_firearm_state_to_firearms( pub fn insert_firearm_state_to_firearms(
// needed for tri meshes // needed for tri meshes
queries: InsertFirearmStateIntoFirearmsParams, mut queries: InsertFirearmStateIntoFirearmsParams,
assets_gltf: Res<GltfAssets>, assets_gltf: Res<GltfAssets>,
loaded_gltf_assets: Res<Assets<Gltf>>, loaded_gltf_assets: Res<Assets<Gltf>>,
mut commands: Commands, mut commands: Commands,
) { ) {
for (firearm_scene_entity, item_state_opt, scene_bundle_children) in queries.firearm_scene_bundle.iter() { for (firearm_scene_entity, item_state_opt, initial_attchments_opt, scene_bundle_children) in queries.firearm_scene_bundle.iter() {
for scene_bundle_child in scene_bundle_children.iter() { for scene_bundle_child in scene_bundle_children.iter() {
for (firearm_entity, _, firearm_parent, firearm_state_opt) in queries.firearm_query.iter() { for (firearm_entity, _, firearm_parent, firearm_state_opt) in queries.firearm_query.iter_mut() {
if &firearm_parent.get() == scene_bundle_child { if &firearm_parent.get() == scene_bundle_child {
if let Some(item_state) = item_state_opt { if let Some(item_state) = item_state_opt {
// Firearm State is already created and item is being spawned again into world // Firearm State is already created and item is being spawned again into world
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
if let ItemState::Weapon(firearm_state) = item_state { if let ItemState::Weapon(mut firearm_state) = item_state.clone() {
commands.entity(firearm_scene_entity).remove::<ItemState>(); commands.entity(firearm_scene_entity).remove::<ItemState>();
spawn_attachments_in_firearm(&mut commands, firearm_entity, &mut firearm_state, &queries.slots_query, &assets_gltf, &loaded_gltf_assets);
commands commands
.entity(firearm_entity) .entity(firearm_entity)
.insert(firearm_state.clone()); .insert(firearm_state);
spawn_attachments_in_firearm(&mut commands, firearm_entity, firearm_state, &queries.slots_query, &assets_gltf, &loaded_gltf_assets);
return; return;
} }
} }
match firearm_state_opt { match firearm_state_opt {
Some(firearm_state) => { Some(mut firearm_state) => {
// Change the Slots // Change the Slots
spawn_attachments_in_firearm(&mut commands, firearm_entity, firearm_state, &queries.slots_query, &assets_gltf, &loaded_gltf_assets); spawn_attachments_in_firearm(&mut commands, firearm_entity, &mut firearm_state, &queries.slots_query, &assets_gltf, &loaded_gltf_assets);
//TODO: Change firearm state inside inventory
for in_player_hands_item_id in queries.in_player_hands_query.iter() { for in_player_hands_item_id in queries.in_player_hands_query.iter() {
for player_inventory in queries.player_inventories_query.iter() { for player_inventory in queries.player_inventories_query.iter() {
if let Some(current_item) = player_inventory.get_current_slot_item() { if let Some(current_item) = player_inventory.get_current_slot_item() {
@ -56,6 +58,7 @@ pub fn insert_firearm_state_to_firearms(
None => { None => {
// Create the firearm_state // Create the firearm_state
let mut firearm_slots = Vec::new(); let mut firearm_slots = Vec::new();
let magazine_data = None;
for (slot_entity, slot, parent_entity) in queries.slots_query.iter() { for (slot_entity, slot, parent_entity) in queries.slots_query.iter() {
if firearm_entity == parent_entity.get() { if firearm_entity == parent_entity.get() {
let mut attachment = None; let mut attachment = None;
@ -70,7 +73,13 @@ pub fn insert_firearm_state_to_firearms(
}); });
} }
} }
let firearm_state = FirearmState::new(firearm_slots); if let Some(initial_attachments) = initial_attchments_opt {
for initial_attachment in initial_attachments.attachments.iter() {
firearm_slots.iter_mut().for_each(|firearm_slot| if initial_attachment.fits_into_slot(&firearm_slot.slot_type) { firearm_slot.attachment = Some(initial_attachment.clone()) });
}
commands.entity(firearm_scene_entity).remove::<InitialAttachments>();
}
let firearm_state = FirearmState::new(firearm_slots, magazine_data);
commands commands
.entity(firearm_entity) .entity(firearm_entity)
.insert(firearm_state.clone()); .insert(firearm_state.clone());
@ -85,7 +94,7 @@ pub fn insert_firearm_state_to_firearms(
fn spawn_attachments_in_firearm( fn spawn_attachments_in_firearm(
commands: &mut Commands, commands: &mut Commands,
firearm_entity: Entity, firearm_entity: Entity,
firearm_state: &FirearmState, firearm_state: &mut FirearmState,
slots_query: &Query<(Entity, &WeaponSlot, &Parent)>, slots_query: &Query<(Entity, &WeaponSlot, &Parent)>,
assets_gltf: &GltfAssets, assets_gltf: &GltfAssets,
loaded_gltf_assets: &Assets<Gltf>, loaded_gltf_assets: &Assets<Gltf>,
@ -112,6 +121,11 @@ fn spawn_attachments_in_firearm(
commands.entity(slot_entity).add_child( commands.entity(slot_entity).add_child(
scene_bundle scene_bundle
); );
if let None = &firearm_state.magazine_data {
if let WeaponAttachment::Magazine(magazine) = attachment {
firearm_state.magazine_data = Some(magazine.magazine_data());
}
}
}}, }},
None => {}, None => {},
}; };

View File

@ -0,0 +1,9 @@
use bevy::prelude::*;
use crate::comps::core::weapons::attachments::weapon_attachment::WeaponAttachment;
#[derive(Component, Reflect, Default, Clone)]
#[reflect(Component)]
pub struct InitialAttachments {
pub attachments: Vec<WeaponAttachment>
}

View File

@ -1 +1,2 @@
pub mod firearm; pub mod firearm;
pub mod initial_attachments;

View File

@ -4,12 +4,13 @@ use uuid::Uuid;
use crate::comps::core::{ use crate::comps::core::{
items::{guns::ak105::Ak105GunItem, item::{Item, ItemId}}, items::{guns::ak105::Ak105GunItem, item::{Item, ItemId}},
spawners::item::ItemSpawnPoint, spawners::item::ItemSpawnPoint, weapons::attachments::{weapon_attachment::WeaponAttachment, compensator::Compensator, foregrip::ForeGrip, magazine::Magazine, stock::Stock}, markers::proxy::weapons::initial_attachments::InitialAttachments,
}; };
#[derive(Component)] #[derive(Component)]
pub struct Ak105SpawnPoint { pub struct Ak105SpawnPoint {
pub transform: Transform, pub transform: Transform,
pub attachments: Vec<WeaponAttachment>
} }
impl ItemSpawnPoint for Ak105SpawnPoint { impl ItemSpawnPoint for Ak105SpawnPoint {
@ -18,6 +19,32 @@ impl ItemSpawnPoint for Ak105SpawnPoint {
} }
fn get_item(&self) -> Box<dyn Item> { fn get_item(&self) -> Box<dyn Item> {
Box::new(Ak105GunItem { state: Mutex::new(None), id: ItemId(Uuid::new_v4()) }) let initial_attachments = if self.attachments.is_empty() {
None
} else {
Some(InitialAttachments { attachments: self.attachments.clone() })
};
Box::new(Ak105GunItem { state: Mutex::new(None), id: ItemId(Uuid::new_v4()), initial_attachments })
}
}
#[allow(unused)]
impl Ak105SpawnPoint {
pub fn new(transform: Transform) -> Self {
Self {
transform,
attachments: Vec::new(),
}
}
pub fn new_fully_kitted_default(transform: Transform) -> Self {
Self {
transform,
attachments: Vec::from([
WeaponAttachment::Compensator(Compensator::FirstCompensator),
WeaponAttachment::ForeGrip(ForeGrip::Pk5),
WeaponAttachment::Magazine(Magazine::Ak105),
WeaponAttachment::Stock(Stock::MagpullTan),
]),
}
} }
} }

View File

@ -1,5 +1,7 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}}; use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use crate::comps::core::weapons::magazine_data::MagazineData;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
@ -9,7 +11,10 @@ pub enum Magazine {
} }
impl Magazine { impl Magazine {
pub fn capacity(&self) -> u32 { pub fn magazine_data(&self) -> MagazineData {
MagazineData { rounds_shot: 0, max_capacity: self.capacity() }
}
pub fn capacity(&self) -> usize {
match self { match self {
Magazine::Ak105 => 30, Magazine::Ak105 => 30,
} }

View File

@ -1,5 +1,7 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::weapons::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot};
use super::{compensator::Compensator, magazine::Magazine, stock::Stock, foregrip::ForeGrip, optic::Optic}; use super::{compensator::Compensator, magazine::Magazine, stock::Stock, foregrip::ForeGrip, optic::Optic};
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Debug)] #[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Debug)]
@ -56,4 +58,13 @@ impl WeaponAttachment {
}, },
} }
} }
pub fn fits_into_slot(&self, slot: &WeaponSlot) -> bool {
match self {
WeaponAttachment::Compensator(_) => slot == &WeaponSlot::CompensatorSlot,
WeaponAttachment::Magazine(_) => slot == &WeaponSlot::MagazineSlot,
WeaponAttachment::Stock(_) => slot == &WeaponSlot::StockSlot,
WeaponAttachment::ForeGrip(_) => slot == &WeaponSlot::ForeGripSlot,
WeaponAttachment::Optic(_) => slot == &WeaponSlot::SightPlacementStartSlot || slot == &WeaponSlot::SightPlacementEndSlot,
}
}
} }

View File

@ -41,7 +41,7 @@ impl Firearm {
}, },
final_aimed_rotation: Quat::default(),//Quat::from_rotation_x(0.026), final_aimed_rotation: Quat::default(),//Quat::from_rotation_x(0.026),
final_rotation: Quat::default(), rotation_offset: Quat::default(),
final_aimed_position: Vec3 { final_aimed_position: Vec3 {
// x: -0.003, // x: -0.003,
// y: -0.35, // y: -0.35,
@ -50,7 +50,7 @@ impl Firearm {
y: -0.35, y: -0.35,
z: -1.6, z: -1.6,
}, },
final_position: Vec3::ZERO, /*Vec3 { translation_offset: Vec3::ZERO, /*Vec3 {
x: 0.6, x: 0.6,
y: -0.45, y: -0.45,
z: -2.7, z: -2.7,
@ -64,7 +64,8 @@ impl Firearm {
FirearmData { FirearmData {
caliber: Caliber::Parabellum9mm, caliber: Caliber::Parabellum9mm,
fire_rate: 600.0, fire_rate: 600.0,
rebound_time_seconds: 0.1, aim_time_seconds: 0.1,
rebound_time_seconds: 0.5,
recoil_pattern: FirearmSprayPattern { recoil_pattern: FirearmSprayPattern {
vertical: Vec::from([ vertical: Vec::from([
1.0, 1.2, 1.3, 1.6, 1.5, 1.7, 1.5, 1.5, 1.5, 2.0, // 10 for now 1.0, 1.2, 1.3, 1.6, 1.5, 1.7, 1.5, 1.5, 1.5, 2.0, // 10 for now
@ -75,7 +76,7 @@ impl Firearm {
}, },
final_aimed_rotation: Quat::from_rotation_x(0.026), final_aimed_rotation: Quat::from_rotation_x(0.026),
final_rotation: Quat::default(), rotation_offset: Quat::default(),
final_aimed_position: Vec3 { final_aimed_position: Vec3 {
// x: -0.003, // x: -0.003,
// y: -0.35, // y: -0.35,
@ -84,7 +85,7 @@ impl Firearm {
y: -0.5, y: -0.5,
z: -1.6, z: -1.6,
}, },
final_position: Vec3 { translation_offset: Vec3 {
x: 1.0, x: 1.0,
y: -0.45, y: -0.45,
z: -2.7, z: -2.7,
@ -97,7 +98,8 @@ impl Firearm {
Firearm::Ak105 => FirearmData { Firearm::Ak105 => FirearmData {
caliber: Caliber::RU545, caliber: Caliber::RU545,
fire_rate: 600.0, fire_rate: 600.0,
rebound_time_seconds: 0.2, aim_time_seconds: 0.25,
rebound_time_seconds: 0.6,
asset_path: String::from("weapons/ak105_rifle.glb"), asset_path: String::from("weapons/ak105_rifle.glb"),
recoil_pattern: FirearmSprayPattern { recoil_pattern: FirearmSprayPattern {
vertical: Vec::from([ vertical: Vec::from([
@ -108,10 +110,10 @@ impl Firearm {
]), ]),
}, },
final_aimed_rotation: Quat::default(), final_aimed_rotation: Quat::default(),
final_rotation: Quat::default(), rotation_offset: Quat::default(),
final_aimed_position: Vec3::ZERO, final_aimed_position: Vec3 { x: 0.016, y: 0.0, z: -0.1 },
final_position: Vec3::ZERO, translation_offset: Vec3 { x: -0.2, y: -0.03, z: 0.0 },
scale_factor: 0.3, scale_factor: 0.2,
firearm_type: FirearmType::Primary, firearm_type: FirearmType::Primary,
}, },
} }

View File

@ -9,19 +9,20 @@ pub struct FirearmData {
pub caliber: Caliber, pub caliber: Caliber,
/// Rounds per minute /// Rounds per minute
pub fire_rate: f32, pub fire_rate: f32,
/// Amount of time it takes for the gun to aim in or aim out.
pub aim_time_seconds: f32,
/// Amount of seconds it takes for gun to come down from shooting /// Amount of seconds it takes for gun to come down from shooting
/// Also is the time it takes for the gun to aim in or aim out.
pub rebound_time_seconds: f32, pub rebound_time_seconds: f32,
pub asset_path: String, pub asset_path: String,
pub recoil_pattern: FirearmSprayPattern, pub recoil_pattern: FirearmSprayPattern,
/// Final rotation of hands when aimed in /// Final rotation of hands when aimed in
pub final_aimed_rotation: Quat, pub final_aimed_rotation: Quat,
/// Final rotation of hands when not aimed in /// Final rotation of hands when not aimed in
pub final_rotation: Quat, pub rotation_offset: Quat,
/// Final position of hands when aimed in /// Final position of hands when aimed in
pub final_aimed_position: Vec3, pub final_aimed_position: Vec3,
/// Final position of hands when not aimed in /// Final position of hands when not aimed in
pub final_position: Vec3, pub translation_offset: Vec3,
pub scale_factor: f32, pub scale_factor: f32,
pub firearm_type: FirearmType, pub firearm_type: FirearmType,
} }

View File

@ -1,15 +1,16 @@
use bevy::prelude::*; use bevy::prelude::*;
use super::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot}; use super::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot, magazine_data::MagazineData};
#[derive(Component, Reflect, PartialEq, Eq, PartialOrd, Ord, Debug, Clone)] #[derive(Component, Reflect, PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
pub struct FirearmState { pub struct FirearmState {
pub attachment_slots: Vec<AttachmentSlot>, pub attachment_slots: Vec<AttachmentSlot>,
pub magazine_data: Option<MagazineData>,
} }
impl FirearmState { impl FirearmState {
pub fn new(attachment_slots: Vec<AttachmentSlot>) -> Self { pub fn new(attachment_slots: Vec<AttachmentSlot>, magazine_data: Option<MagazineData>) -> Self {
Self { attachment_slots } Self { attachment_slots, magazine_data: None }
} }
} }

View File

@ -9,6 +9,7 @@ pub fn switch_camera(
keyboard_input: Res<Input<KeyCode>>, keyboard_input: Res<Input<KeyCode>>,
) { ) {
if keyboard_input.just_pressed(KeyCode::Key0) { if keyboard_input.just_pressed(KeyCode::Key0) {
return;
for mut main_cam in main_camera_query.iter_mut() { for mut main_cam in main_camera_query.iter_mut() {
main_cam.is_active = !main_cam.is_active; main_cam.is_active = !main_cam.is_active;
} }

View File

@ -10,9 +10,9 @@ use crate::{
holdable::InPlayerHands, holdable::InPlayerHands,
interactable::Interactable, interactable::Interactable,
player::Player, proxy::{character::in_player_hands_parent::InPlayerHandsParent, physics::rapier::LinkToPlayer}, player::Player, proxy::{character::in_player_hands_parent::InPlayerHandsParent, physics::rapier::LinkToPlayer},
}, weapons::{firearm::Firearm, firearm_state::FirearmState}, }, weapons::{firearm::Firearm, firearm_state::FirearmState, parts::firing_point::FiringPoint},
}, },
logic::core::guns::{player_firing::PlayerFiringInfo}, logic::core::guns::{player_firing::PlayerFiringInfo, shoot::shoot_bullet},
setup::{ setup::{
equipment::{Equipment, EquipmentChangeEvent}, equipment::{Equipment, EquipmentChangeEvent},
load_state::GameLoadState, assets::GltfAssets, //animations::AllAnimations, load_state::GameLoadState, assets::GltfAssets, //animations::AllAnimations,
@ -21,8 +21,11 @@ use crate::{
utils::{rad_deg::radians_from_degrees, hierarchy::find_child_in_parent_children}, utils::{rad_deg::radians_from_degrees, hierarchy::find_child_in_parent_children},
}; };
use super::player_settings::PlayerSettings;
#[derive(SystemParam)] #[derive(SystemParam)]
pub struct CaptureHandUsageResourcesParams<'w> { pub struct CaptureHandUsageResourcesParams<'w> {
player_settings: Res<'w, PlayerSettings>,
mouse_buttons: Res<'w, Input<MouseButton>>, mouse_buttons: Res<'w, Input<MouseButton>>,
keyboard_input: Res<'w, Input<KeyCode>>, keyboard_input: Res<'w, Input<KeyCode>>,
game_load_state: Res<'w, GameLoadState>, game_load_state: Res<'w, GameLoadState>,
@ -36,37 +39,32 @@ pub struct CaptureHandUsageResourcesParams<'w> {
loaded_gltf_assets: Res<'w, Assets<Gltf>>, loaded_gltf_assets: Res<'w, Assets<Gltf>>,
} }
#[derive(SystemParam)]
pub struct CaptureHandUsageQueryParams<'w, 's> {
hand_query: Query<'w, 's, (&'static mut Transform, Entity), (With<InPlayerHandsParent>, Without<Player>)>,
in_hand_query: Query<'w, 's, (&'static Parent, &'static mut Transform), (With<InPlayerHands>, Without<InPlayerHandsParent>, Without<PlayerInventory>)>,
firearms_query: Query<'w, 's, (Entity, &'static GlobalTransform, &'static Firearm, &'static mut FirearmState),>,
firing_point_query: Query<'w, 's, (&'static GlobalTransform, &'static Parent), With<FiringPoint>>,
player_query: Query<'w, 's, (&'static Player, &'static mut PlayerInventory, Entity, &'static Transform, &'static mut PlayerFiringInfo), Without<InPlayerHands>>,
children: Query<'w, 's, &'static Children>,
}
#[allow(irrefutable_let_patterns)] #[allow(irrefutable_let_patterns)]
pub fn capture_hand_usage( pub fn capture_hand_usage(
mut resources: CaptureHandUsageResourcesParams, mut resources: CaptureHandUsageResourcesParams,
mut queries: CaptureHandUsageQueryParams,
mut commands: Commands, mut commands: Commands,
mut hand_query: Query<(&mut Transform, Entity), (With<InPlayerHandsParent>, Without<Player>)>,
mut firearms_query: Query<
(
Entity,
&Firearm,
&FirearmState,
&GlobalTransform,
),
>,
mut player_query: Query<(&Player, &mut PlayerInventory, Entity, &Transform, &mut PlayerFiringInfo)>,
children: Query<&Children>,
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>, mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
mut inventory_changed_events: EventWriter<PlayerInventoryChangedEvent>, mut inventory_changed_events: EventWriter<PlayerInventoryChangedEvent>,
) { ) {
if !resources.game_load_state.player_loaded { if !resources.game_load_state.player_loaded {
return; return;
} }
if player_query.iter().len() == 0 {
return;
}
// Equipping stuff // Equipping stuff
for (player, mut player_inventory, player_entity, player_transform, mut player_firing_info) in player_query.iter_mut() { for (player, mut player_inventory, player_entity, player_transform, mut player_firing_info) in queries.player_query.iter_mut() {
// Equipping gun // Equipping gun
// Validate player has primary item, and secondary item in inventory // Validate player has primary item, and secondary item in inventory
if !resources.game_ui_state.any_window() && !player_firing_info.is_reloading { if !resources.game_ui_state.any_window() && !player_firing_info.is_reloading {
@ -102,9 +100,9 @@ pub fn capture_hand_usage(
} else if resources.keyboard_input.just_pressed(KeyCode::G) { } else if resources.keyboard_input.just_pressed(KeyCode::G) {
match player_inventory.current_slot { match player_inventory.current_slot {
Some(current_slot) => { Some(current_slot) => {
for (_, in_player_hands_entity) in hand_query.iter() { for (_, in_player_hands_entity) in queries.hand_query.iter() {
for (firearm_entity, _, firearm_state, _) in firearms_query.iter() { for (firearm_entity, _, _, firearm_state) in queries.firearms_query.iter() {
if find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &children) { if find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &queries.children) {
player_inventory::drop_slot_in_game_world(&mut commands, player_transform, &mut inventory_changed_events, &mut player_inventory, &resources.assets_gltf, &resources.loaded_gltf_assets, current_slot, Some(ItemState::Weapon(firearm_state.clone()))); player_inventory::drop_slot_in_game_world(&mut commands, player_transform, &mut inventory_changed_events, &mut player_inventory, &resources.assets_gltf, &resources.loaded_gltf_assets, current_slot, Some(ItemState::Weapon(firearm_state.clone())));
equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing, None)); equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing, None));
player_inventory.current_slot = None; player_inventory.current_slot = None;
@ -118,176 +116,149 @@ pub fn capture_hand_usage(
} }
// Firearm stuff // Firearm stuff
if let Equipment::Firearm(_f, _) = player.0.equipment.clone() { if let Equipment::Firearm(_, _) = player.0.equipment.clone() {
player_firing_info player_firing_info
.full_auto_timer .full_auto_timer
.tick(resources.time.delta()); .tick(resources.time.delta());
for (_f, firearm_transform, _, _) in for (firearm_entity, firearm_transform, firearm, mut firearm_state) in
firearms_query.iter_mut() queries.firearms_query.iter_mut()
{ {
for mut hand_transform in hand_query.iter_mut() { for (mut hand_transform, hand_entity) in queries.hand_query.iter_mut() {
if player_firing_info.is_reloading { if !find_child_in_parent_children(&mut commands, hand_entity, firearm_entity, &queries.children) {
/* TODO: continue;
for (animation_player_entity, animation_player) in &mut animation_players { }
//children.get_component(entity) for (in_hand_parent, mut in_hand_transform) in queries.in_hand_query.iter_mut() {
// Only reload if this animation_player_entity is a child of the firearm_entity if in_hand_parent.get() == hand_entity {
if utils::hierarchy::find_child_in_parent_children( if player_firing_info.is_reloading {
&mut commands, // TODO: Here you should keep track of reload animation & time, then set player_firing_info.is_reloading = false
firearm_entity, } else {
animation_player_entity, // Player is not currently reloading
&children, // TODO: Add item check (make sure he has extra mags)
) { if resources.keyboard_input.just_pressed(KeyCode::R)
if let Some(firearm_animations) = resources && !resources.game_ui_state.any_window()
.all_animations
.firearm_animations
.iter()
.find(|animation| &animation.firearm == &player_firearm)
{ {
if let Some(animation_clip) = resources if let Some(magazine_data) = &mut firearm_state.magazine_data {
.animation_clips magazine_data.rounds_shot = 0;
.get(&firearm_animations.reload_magazine) }
{ // TODO: start reloading
if animation_player.elapsed() >= animation_clip.duration() { // TODO: Drop magazine in game world
magazine_data.rounds_shot = 0;
player_firing_info.is_reloading = false; // Set is_reloading = true
}
// AIMING IN/OUT
let firearm_data = firearm.firearm_data();
let lerp_time = if player_firing_info.current_round_index > 0 { firearm_data.rebound_time_seconds } else {
if resources.time.elapsed_seconds() - player_firing_info.last_shot_timestamp > firearm_data.rebound_time_seconds * 1.5 {
firearm_data.aim_time_seconds
} else {
firearm_data.rebound_time_seconds
}
};
if resources.mouse_buttons.pressed(MouseButton::Right)
&& !resources.game_ui_state.any_window()
{
let rotation_lerp_quat = in_hand_transform.rotation.lerp(
firearm_data.final_aimed_rotation + resources.player_settings.rot_aimed_offset,
(resources.time.delta_seconds()
/ lerp_time)
.clamp(0.0, 1.0),
);
let position_lerp_vec3 = in_hand_transform.translation.lerp(
firearm_data.final_aimed_position + resources.player_settings.pos_aimed_offset,
(resources.time.delta_seconds()
/ lerp_time)
.clamp(0.0, 1.0),
);
in_hand_transform.rotation = rotation_lerp_quat;
in_hand_transform.translation = position_lerp_vec3;
} else {
in_hand_transform.rotation = in_hand_transform.rotation.lerp(
firearm_data.rotation_offset + resources.player_settings.rot_offset,
(resources.time.delta_seconds()
/ lerp_time)
.clamp(0.0, 1.0),
);
in_hand_transform.translation = in_hand_transform.translation.lerp(
firearm_data.translation_offset + resources.player_settings.pos_offset,
(resources.time.delta_seconds()
/ lerp_time)
.clamp(0.0, 1.0),
);
}
// SHOOTING & RECOIL
if resources.mouse_buttons.pressed(MouseButton::Left)
&& !resources.game_ui_state.any_window()
{
if let Some(magazine_data) = &mut firearm_state.magazine_data {
if player_firing_info.full_auto_timer.finished() {
if magazine_data.rounds_shot < magazine_data.max_capacity {
// Get recoil numbers from patterns
let vertical_recoil_number: f32 = match firearm_data.recoil_pattern.vertical.get(player_firing_info.current_round_index) {
Some(vert_recoil_number) => *vert_recoil_number,
None => {
*firearm_data.recoil_pattern.vertical.last().expect("FOUND A FIREARM_DATA WITHOUT ANY FIREARM_RECOIL_PATTERN.")
},
};
let horizontal_recoil_number: f32 = match firearm_data.recoil_pattern.horizontal.get(player_firing_info.current_round_index) {
Some(horizontal_recoil_number) => *horizontal_recoil_number,
None => {
*firearm_data.recoil_pattern.horizontal.last().expect("FOUND A FIREARM_DATA WITHOUT ANY FIREARM_RECOIL_PATTERN.")
},
};
for (firing_point_transform, firing_point_parent) in queries.firing_point_query.iter() {
if firing_point_parent.get() == firearm_entity {
//let firearm_transform = firearm_transform.clone();
let firing_point = firing_point_transform.translation();
let forward = firing_point_transform.forward() ;
let up = firing_point_transform.up();
shoot_bullet(
&mut commands,
&mut resources.meshes,
&mut resources.materials,
Transform::from_translation(firing_point),
forward,
up,
firearm_data.caliber.clone(),
);
// Increment indexes and timers
player_firing_info.current_round_index += 1;
player_firing_info.last_shot_timestamp =
resources.time.elapsed_seconds();
player_firing_info.full_auto_timer.reset();
magazine_data.rounds_shot += 1;
// Apply recoil
in_hand_transform.rotate_x(radians_from_degrees(
//TODO: Recoil modifier firearm_data.vertical_recoil_modifier
-1.0 * 2.0
* vertical_recoil_number,
));
in_hand_transform.rotate_y(radians_from_degrees(
//TODO: Recoil modifier firearm_data.horizontal_recoil_modifier
1.0 * 0.5
* horizontal_recoil_number,
));
}
}
} else {
//TODO: play magazine empty sound
}
} }
} }
} } else {
} if player_firing_info.full_auto_timer.finished() {
}*/ player_firing_info.current_round_index = 0;
} else {
// Player is not in a reload animation
if resources.keyboard_input.just_pressed(KeyCode::R)
&& !resources.game_ui_state.any_window()
{}
/*
// Start reload animation
for (animation_player_entity, mut animation_player) in
&mut animation_players
{
// Only reload if this animation_player_entity is a child of the firearm_entity
if utils::hierarchy::find_child_in_parent_children(
&mut commands,
firearm_entity,
animation_player_entity,
&children,
) {
if let Some(firearm_animations) = resources
.all_animations
.firearm_animations
.iter()
.find(|animation| &animation.firearm == &player_firearm)
{
animation_player
.start(firearm_animations.reload_magazine.clone_weak());
player_firing_info.is_reloading = true;
} }
} }
}*/
// Set is_reloading = true
// At the end of reload animation, set magazine data to capacity = 0
}
// AIMING IN/OUT
/*
if resources.mouse_buttons.pressed(MouseButton::Right)
&& !resources.game_ui_state.any_window()
{
let rotation_lerp_quat = hand_transform.rotation.lerp(
firearm_data.final_aimed_rotation,
(resources.time.delta_seconds()
/ firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0),
);
let position_lerp_vec3 = hand_transform.translation.lerp(
firearm_data.final_aimed_position,
(resources.time.delta_seconds()
/ firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0),
);
hand_transform.rotation = rotation_lerp_quat;
hand_transform.translation = position_lerp_vec3;
} else {
hand_transform.rotation = hand_transform.rotation.lerp(
firearm_data.final_rotation,
(resources.time.delta_seconds()
/ firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0),
);
hand_transform.translation = hand_transform.translation.lerp(
firearm_data.final_position,
(resources.time.delta_seconds()
/ firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0),
);
}
// SHOOTING & RECOIL
if resources.mouse_buttons.pressed(MouseButton::Left)
&& !resources.game_ui_state.any_window()
{
if player_firing_info.full_auto_timer.finished() {
if magazine_data.rounds_shot < magazine_data.max_capacity {
// Get recoil numbers from patterns
let vertical_recoil_number: f32 = match firearm_data.recoil_pattern.vertical.get(player_firing_info.current_round_index) {
Some(vert_recoil_number) => *vert_recoil_number,
None => {
*firearm_data.recoil_pattern.vertical.last().expect("FOUND A FIREARM_DATA WITHOUT ANY FIREARM_RECOIL_PATTERN.")
},
};
let horizontal_recoil_number: f32 = match firearm_data.recoil_pattern.horizontal.get(player_firing_info.current_round_index) {
Some(horizontal_recoil_number) => *horizontal_recoil_number,
None => {
*firearm_data.recoil_pattern.horizontal.last().expect("FOUND A FIREARM_DATA WITHOUT ANY FIREARM_RECOIL_PATTERN.")
},
};
let firearm_transform = firearm_transform.clone();
let firing_point = firearm_transform.translation()
+ (firearm_transform.forward()
* firearm_data.firing_point.forward)
+ (firearm_transform.up() * firearm_data.firing_point.up)
+ (firearm_transform.right()
* firearm_data.firing_point.right);
let forward = firearm_transform.forward();
let up = firearm_transform.up();
shoot_bullet(
&mut commands,
&mut resources.meshes,
&mut resources.materials,
Transform::from_translation(firing_point),
forward,
up,
firearm_data.caliber.clone(),
);
// Increment indexes and timers
player_firing_info.current_round_index += 1;
player_firing_info.last_shot_timestamp =
resources.time.elapsed_seconds();
player_firing_info.full_auto_timer.reset();
magazine_data.rounds_shot += 1;
// Apply recoil
hand_transform.rotate_x(radians_from_degrees(
firearm_data.vertical_recoil_modifier
* vertical_recoil_number,
));
hand_transform.rotate_y(radians_from_degrees(
firearm_data.horizontal_recoil_modifier
* horizontal_recoil_number,
));
} else {
//TODO: play magazine empty sound
}
}
} else {
if player_firing_info.full_auto_timer.finished() {
player_firing_info.current_round_index = 0;
} }
} }
}*/ }
} }
} }
} }
} }

View File

@ -6,4 +6,5 @@ pub mod player_movement;
pub mod player_values_state; pub mod player_values_state;
pub mod player_vertical_sync; pub mod player_vertical_sync;
pub mod animate_player; pub mod animate_player;
pub mod camera_switching; pub mod camera_switching;
pub mod player_settings;

View File

@ -0,0 +1,32 @@
use bevy::prelude::*;
#[derive(Resource, Reflect)]
#[reflect(Resource)]
pub struct PlayerSettings {
/// X Value of hand when something is equipped.
/// Applied to the object inside the hand (InPlayerHands)
//pub gun_offset: f32,
pub fov: f32,
/// Debug thing for me
pub pos_aimed_offset: Vec3,
pub pos_offset: Vec3,
pub rot_aimed_offset: Quat,
pub rot_offset: Quat,
pub third_person_toggle: bool,
}
impl Default for PlayerSettings {
fn default() -> Self {
Self {
fov: 0.0,
pos_aimed_offset: Vec3::ZERO,
pos_offset: Vec3::ZERO,
rot_aimed_offset: Quat::default(),
rot_offset: Quat::default(),
third_person_toggle: false
}
}
}

View File

@ -30,13 +30,13 @@ pub fn set_spawn_points(mut commands: Commands) {
transform transform
}, },
}); });
commands.spawn(Ak105SpawnPoint {
transform: { commands.spawn(Ak105SpawnPoint ::new_fully_kitted_default({
let mut transform = Transform::from_xyz(18.0, 10.0, 18.0); let mut transform = Transform::from_xyz(18.0, 10.0, 18.0);
transform.rotate_z(utils::rad_deg::radians_from_degrees(-90.0)); transform.rotate_z(utils::rad_deg::radians_from_degrees(-90.0));
transform transform
}, }));
});
commands.spawn(Glock17SpawnPoint { commands.spawn(Glock17SpawnPoint {
transform: { transform: {
let mut transform = Transform::from_xyz(20.0, 10.0, 20.0); let mut transform = Transform::from_xyz(20.0, 10.0, 20.0);

View File

@ -26,7 +26,7 @@ pub fn editor_controls() -> EditorControls {
editor_controls.insert( editor_controls.insert(
controls::Action::PlayPauseEditor, controls::Action::PlayPauseEditor,
controls::Binding { controls::Binding {
input: controls::UserInput::Single(controls::Button::Keyboard(KeyCode::Back)), input: controls::UserInput::Single(controls::Button::Keyboard(KeyCode::Grave)),
conditions: vec![controls::BindingCondition::ListeningForText(false)], conditions: vec![controls::BindingCondition::ListeningForText(false)],
}, },
); );

View File

@ -12,7 +12,7 @@ use crate::{
player::{ player::{
camera_player_sync::MouseMovementSettings, camera_player_sync::MouseMovementSettings,
player_movement::{PlayerLinearXZState, PlayerLinearYState, PlayerMovementInput}, player_movement::{PlayerLinearXZState, PlayerLinearYState, PlayerMovementInput},
player_values_state::PlayerValuesState, player_values_state::PlayerValuesState, player_settings::PlayerSettings,
}, },
}, },
scenes::scene1::skybox::Cubemap, scenes::scene1::skybox::Cubemap,
@ -34,7 +34,8 @@ pub struct MainEditorUiPlugin;
impl Plugin for MainEditorUiPlugin { impl Plugin for MainEditorUiPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<PlayerFiringInfo>() app
.register_type::<PlayerFiringInfo>()
.register_type::<PlayerValuesState>() .register_type::<PlayerValuesState>()
.register_type::<FirearmData>() .register_type::<FirearmData>()
.register_type::<MagazineData>() .register_type::<MagazineData>()
@ -52,6 +53,7 @@ impl Plugin for MainEditorUiPlugin {
.register_type::<PlayerMovementInput>() .register_type::<PlayerMovementInput>()
.register_type::<Cubemap>() .register_type::<Cubemap>()
.register_type::<FirearmState>() .register_type::<FirearmState>()
.register_type::<PlayerSettings>()
//.register_type::<AllAnimations>() //.register_type::<AllAnimations>()
//.register_type::<FirearmAnimations>() //.register_type::<FirearmAnimations>()
.register_type::<GltfAssetType>() .register_type::<GltfAssetType>()
@ -61,6 +63,7 @@ impl Plugin for MainEditorUiPlugin {
.add_plugins(EguiPlugin) .add_plugins(EguiPlugin)
.add_plugins(EditorPlugin::default()) .add_plugins(EditorPlugin::default())
.insert_resource(editor_controls()) .insert_resource(editor_controls())
.insert_resource(PlayerSettings::default())
.add_systems(PostStartup, set_cam3d_controls); .add_systems(PostStartup, set_cam3d_controls);
//.add_plugins(ResourceInspectorPlugin::<MouseMovementSettings>::default()); //.add_plugins(ResourceInspectorPlugin::<MouseMovementSettings>::default());
//.add_plugins(bevy_inspector_egui::DefaultInspectorConfigPlugin) // adds default options and `InspectorEguiImpl`s //.add_plugins(bevy_inspector_egui::DefaultInspectorConfigPlugin) // adds default options and `InspectorEguiImpl`s

View File

@ -6,6 +6,7 @@ pub struct SettingsMenuPlugin;
impl Plugin for SettingsMenuPlugin { impl Plugin for SettingsMenuPlugin {
fn build(&self, app: &mut bevy::prelude::App) { fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Startup, menu::setup_settings_screen); app.add_systems(Startup, menu::setup_settings_screen);
app.add_systems( app.add_systems(
Update, Update,