Fixed guns reloading all animation players when reload anim is triggered on the same gun

This commit is contained in:
Franklin 2023-11-12 16:38:23 -04:00
parent 01bd24bf19
commit 865070ed90
22 changed files with 190 additions and 85 deletions

View File

@ -0,0 +1,37 @@
use bevy::prelude::*;
use crate::{comps::core::{items::item::{Item, ItemType}, grid::UGrid, markers::holdable::HoldableObjectType}, logic::core::guns::firearm::Firearm};
#[derive(Component)]
pub struct Glock17GunItem;
impl Item for Glock17GunItem {
fn get_type(&self) -> ItemType {
ItemType::Holdable(HoldableObjectType::Firearm(Firearm::Glock17))
}
fn asset_path(&self) -> &str {
"weapons/glock_17_pistol.glb"
}
#[doc = " Optional Stackable. If value is Some(x) x is the max quantity per stack"]
fn stackable(&self) -> Option<u32> {
None
}
fn inventory_size(&self) -> UGrid {
UGrid { width: 2, height: 1 }
}
fn inventory_rotatable(&self) -> bool {
true
}
fn inventory_title(&self) -> String {
String::from("Glock17 Firearm")
}
fn inventory_description(&self) -> String {
String::from("Glock17 Firearm chambered in 9x19mm.")
}
}

View File

@ -1 +1,2 @@
pub mod m4a1; pub mod m4a1;
pub mod glock17;

View File

@ -67,6 +67,7 @@ pub trait Item {
)), )),
)) ))
.id(); .id();
let firearm_size = firearm.get_size();
commands commands
.spawn(( .spawn((
firearm.holdable_object_data(), firearm.holdable_object_data(),
@ -80,7 +81,7 @@ pub trait Item {
..Default::default() ..Default::default()
}, },
RigidBody::Dynamic, RigidBody::Dynamic,
Collider::cuboid(5.0, 5.0, 5.0), Collider::cuboid(firearm_size.x, firearm_size.y, firearm_size.z),
Interactable::Item, Interactable::Item,
)) ))
.push_children(&[firearm_asset_entity]); .push_children(&[firearm_asset_entity]);

View File

@ -4,3 +4,4 @@ pub mod grid;
pub mod inventory; pub mod inventory;
pub mod items; pub mod items;
pub mod markers; pub mod markers;
pub mod spawners;

View File

@ -0,0 +1,18 @@
use bevy::prelude::*;
use crate::comps::core::{items::{guns::glock17::Glock17GunItem, item::Item}, spawners::item::ItemSpawnPoint};
#[derive(Component)]
pub struct Glock17SpawnPoint {
pub transform: Transform,
}
impl ItemSpawnPoint for Glock17SpawnPoint {
fn get_transform(&self) -> Transform {
self.transform
}
fn get_item(&self) -> Box<dyn Item> {
Box::new(Glock17GunItem)
}
}

View File

@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::{setup::spawners::item::ItemSpawnPoint, comps::core::items::{guns::m4a1::M4a1GunItem, item::Item}}; use crate::comps::core::{items::{guns::m4a1::M4a1GunItem, item::Item}, spawners::item::ItemSpawnPoint};
#[derive(Component)] #[derive(Component)]
pub struct M4a1SpawnPoint { pub struct M4a1SpawnPoint {

View File

@ -0,0 +1,2 @@
pub mod m4a1_spawner;
pub mod glock17_spawner;

View File

@ -1,6 +1,6 @@
use bevy::{prelude::*, gltf::Gltf}; use bevy::{prelude::*, gltf::Gltf};
use crate::{setup::{load_state::GameLoadState, assets::GltfAssets, spawners::guns::m4a1_spawner::M4a1SpawnPoint}, comps::core::items::item::Item}; use crate::{setup::{load_state::GameLoadState, assets::GltfAssets}, comps::core::{items::item::Item, spawners::guns::{m4a1_spawner::M4a1SpawnPoint, glock17_spawner::Glock17SpawnPoint}}};
#[bevy_trait_query::queryable] #[bevy_trait_query::queryable]
pub trait ItemSpawnPoint { pub trait ItemSpawnPoint {
@ -32,6 +32,7 @@ impl Plugin for ItemSpawnPointPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
use bevy_trait_query::RegisterExt; use bevy_trait_query::RegisterExt;
app app
.register_component_as::<dyn ItemSpawnPoint, M4a1SpawnPoint>(); .register_component_as::<dyn ItemSpawnPoint, M4a1SpawnPoint>()
.register_component_as::<dyn ItemSpawnPoint, Glock17SpawnPoint>();
} }
} }

View File

@ -1,4 +1,5 @@
pub mod item; pub mod item;
pub mod player; pub mod player;
pub mod spawn_point; pub mod spawn_point;
pub mod guns; pub mod guns;
pub mod spawn;

View File

@ -0,0 +1,15 @@
use bevy::prelude::*;
use super::{player::player_spawner, item::{item_spawner, ItemSpawnPointPlugin}, spawn_point::SpawnPointPlugin};
pub struct SpawnerPlugin;
impl Plugin for SpawnerPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((SpawnPointPlugin, ItemSpawnPointPlugin));
app.add_systems(
Update,
(player_spawner, item_spawner),
);
}
}

View File

@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::setup::spawners::player::PlayerSpawnPoint; use crate::comps::core::spawners::player::PlayerSpawnPoint;
#[bevy_trait_query::queryable] #[bevy_trait_query::queryable]

View File

@ -111,4 +111,10 @@ impl Firearm {
}, },
} }
} }
pub fn get_size(&self) -> Vec3 {
match self {
Firearm::M4A1 => Vec3 { x: 0.3, y: 0.7, z: 2.5 },
Firearm::Glock17 => Vec3::ZERO,
}
}
} }

View File

@ -1,4 +1,4 @@
use bevy::prelude::*; use bevy::{prelude::*, ecs::system::SystemParam};
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use crate::{ use crate::{
@ -19,34 +19,40 @@ use crate::{
load_state::GameLoadState, load_state::GameLoadState,
}, },
ui::game::{hud::hud::HudState, settings::SettingsScreenUIConfiguration}, ui::game::{hud::hud::HudState, settings::SettingsScreenUIConfiguration},
utils::rad_deg::radians_from_degrees, utils::{rad_deg::radians_from_degrees, self},
}; };
pub fn capture_hand_usage( #[derive(SystemParam)]
mut commands: Commands, pub struct CaptureHandUsageResourcesParams<'w> {
mouse_buttons: Res<Input<MouseButton>>, mouse_buttons: Res<'w, Input<MouseButton>>,
keyboard_input: Res<Input<KeyCode>>, keyboard_input: Res<'w, Input<KeyCode>>,
mut hand_query: Query<&mut Transform, With<PlayerHand>>, game_load_state: Res<'w, GameLoadState>,
time: Res<Time>, settings_screen_config: Res<'w, SettingsScreenUIConfiguration>,
meshes: ResMut<'w, Assets<Mesh>>,
materials: ResMut<'w, Assets<StandardMaterial>>,
animation_clips: Res<'w, Assets<AnimationClip>>,
all_firearm_animations: Res<'w, AllFirearmAnimations>,
time: Res<'w, Time>,
}
pub fn capture_hand_usage(
mut resources: CaptureHandUsageResourcesParams,
mut commands: Commands,
mut hand_query: Query<&mut Transform, With<PlayerHand>>,
mut firearm_query: Query< mut firearm_query: Query<
(&GlobalTransform, &'static FirearmData, &mut MagazineData), (Entity, &GlobalTransform, &'static FirearmData, &mut MagazineData),
(With<InPlayerHands>, Without<PlayerHand>), (With<InPlayerHands>, Without<PlayerHand>),
>, >,
player_query: Query<&Player>, player_query: Query<&Player>,
mut player_firing_info_query: Query<&mut PlayerFiringInfo, With<Player>>, mut player_firing_info_query: Query<&mut PlayerFiringInfo, With<Player>>,
all_firearm_animations: Res<AllFirearmAnimations>, mut animation_players: Query<(Entity, &mut AnimationPlayer)>,
mut animation_players: Query<&mut AnimationPlayer>,
animation_clips: Res<Assets<AnimationClip>>,
game_load_state: Res<GameLoadState>, children: Query<&Children>,
#[allow(unused)] mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
settings_screen_config: Res<SettingsScreenUIConfiguration>, mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) { ) {
if !game_load_state.player_loaded { if !resources.game_load_state.player_loaded {
return; return;
} }
if player_query.iter().len() == 0 { if player_query.iter().len() == 0 {
@ -56,14 +62,14 @@ pub fn capture_hand_usage(
// Equipping stuff // Equipping stuff
// Equipping gun // Equipping gun
if !settings_screen_config.settings_menu_shown { if !resources.settings_screen_config.settings_menu_shown {
if keyboard_input.just_pressed(KeyCode::Key1) { if resources.keyboard_input.just_pressed(KeyCode::Key1) {
equipment_change_event_writer equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(Firearm::M4A1))); .send(EquipmentChangeEvent(Equipment::Firearm(Firearm::M4A1)));
} else if keyboard_input.just_pressed(KeyCode::Key2) { } else if resources.keyboard_input.just_pressed(KeyCode::Key2) {
equipment_change_event_writer equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(Firearm::Glock17))); .send(EquipmentChangeEvent(Equipment::Firearm(Firearm::Glock17)));
} else if keyboard_input.just_pressed(KeyCode::Key3) { } else if resources.keyboard_input.just_pressed(KeyCode::Key3) {
equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing)); equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing));
} }
} }
@ -71,19 +77,22 @@ pub fn capture_hand_usage(
// Firearm stuff // Firearm stuff
if let Equipment::Firearm(player_firearm) = player_query.single().0.equipment.clone() { if let Equipment::Firearm(player_firearm) = player_query.single().0.equipment.clone() {
for mut player_firing_info in player_firing_info_query.iter_mut() { for mut player_firing_info in player_firing_info_query.iter_mut() {
player_firing_info.full_auto_timer.tick(time.delta()); player_firing_info.full_auto_timer.tick(resources.time.delta());
for (firearm_transform, firearm_data, mut magazine_data) in firearm_query.iter_mut() { for (firearm_entity, firearm_transform, firearm_data, mut magazine_data) in firearm_query.iter_mut() {
for mut hand_transform in hand_query.iter_mut() { for mut hand_transform in hand_query.iter_mut() {
if player_firing_info.is_reloading { if player_firing_info.is_reloading {
for animation_player in &mut animation_players { for (animation_player_entity, animation_player) in &mut animation_players {
if let Some(firearm_animations) = all_firearm_animations //children.get_component(entity)
// 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_firearm_animations
.animations .animations
.iter() .iter()
.find(|animation| &animation.firearm == &player_firearm) .find(|animation| &animation.firearm == &player_firearm)
{ {
if let Some(animation_clip) = if let Some(animation_clip) =
animation_clips.get(&firearm_animations.reload_magazine) resources.animation_clips.get(&firearm_animations.reload_magazine)
{ {
if animation_player.elapsed() >= animation_clip.duration() { if animation_player.elapsed() >= animation_clip.duration() {
magazine_data.rounds_shot = 0; magazine_data.rounds_shot = 0;
@ -91,39 +100,45 @@ pub fn capture_hand_usage(
} }
} }
} }
}
} }
} else { } else {
// Player is not in a reload animation // Player is not in a reload animation
if keyboard_input.just_pressed(KeyCode::R) if resources.keyboard_input.just_pressed(KeyCode::R)
&& !settings_screen_config.settings_menu_shown && !resources.settings_screen_config.settings_menu_shown
{ {
// Start reload animation // Start reload animation
for mut animation_player in &mut animation_players { for (animation_player_entity, mut animation_player) in &mut animation_players {
if let Some(firearm_animations) = all_firearm_animations // 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_firearm_animations
.animations .animations
.iter() .iter()
.find(|animation| &animation.firearm == &player_firearm) .find(|animation| &animation.firearm == &player_firearm)
{ {
animation_player animation_player
.start(firearm_animations.reload_magazine.clone_weak()); .start(firearm_animations.reload_magazine.clone_weak());
player_firing_info.is_reloading = true; player_firing_info.is_reloading = true;
}
} }
} }
// Set is_reloading = true // Set is_reloading = true
// At the end of reload animation, set magazine data to capacity = 0 // At the end of reload animation, set magazine data to capacity = 0
} }
// AIMING IN/OUT // AIMING IN/OUT
if mouse_buttons.pressed(MouseButton::Right) if resources.mouse_buttons.pressed(MouseButton::Right)
&& !settings_screen_config.settings_menu_shown && !resources.settings_screen_config.settings_menu_shown
{ {
let rotation_lerp_quat = hand_transform.rotation.lerp( let rotation_lerp_quat = hand_transform.rotation.lerp(
firearm_data.final_aimed_rotation, firearm_data.final_aimed_rotation,
(time.delta_seconds() / firearm_data.rebound_time_seconds) (resources.time.delta_seconds() / firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0), .clamp(0.0, 1.0),
); );
let position_lerp_vec3 = hand_transform.translation.lerp( let position_lerp_vec3 = hand_transform.translation.lerp(
firearm_data.final_aimed_position, firearm_data.final_aimed_position,
(time.delta_seconds() / firearm_data.rebound_time_seconds) (resources.time.delta_seconds() / firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0), .clamp(0.0, 1.0),
); );
hand_transform.rotation = rotation_lerp_quat; hand_transform.rotation = rotation_lerp_quat;
@ -131,19 +146,19 @@ pub fn capture_hand_usage(
} else { } else {
hand_transform.rotation = hand_transform.rotation.lerp( hand_transform.rotation = hand_transform.rotation.lerp(
firearm_data.final_rotation, firearm_data.final_rotation,
(time.delta_seconds() / firearm_data.rebound_time_seconds) (resources.time.delta_seconds() / firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0), .clamp(0.0, 1.0),
); );
hand_transform.translation = hand_transform.translation.lerp( hand_transform.translation = hand_transform.translation.lerp(
firearm_data.final_position, firearm_data.final_position,
(time.delta_seconds() / firearm_data.rebound_time_seconds) (resources.time.delta_seconds() / firearm_data.rebound_time_seconds)
.clamp(0.0, 1.0), .clamp(0.0, 1.0),
); );
} }
// SHOOTING & RECOIL // SHOOTING & RECOIL
if mouse_buttons.pressed(MouseButton::Left) if resources.mouse_buttons.pressed(MouseButton::Left)
&& !settings_screen_config.settings_menu_shown && !resources.settings_screen_config.settings_menu_shown
{ {
if player_firing_info.full_auto_timer.finished() { if player_firing_info.full_auto_timer.finished() {
if magazine_data.rounds_shot < magazine_data.max_capacity { if magazine_data.rounds_shot < magazine_data.max_capacity {
@ -177,8 +192,8 @@ pub fn capture_hand_usage(
let up = firearm_transform.up(); let up = firearm_transform.up();
shoot_bullet( shoot_bullet(
&mut commands, &mut commands,
&mut meshes, &mut resources.meshes,
&mut materials, &mut resources.materials,
Transform::from_translation(firing_point), Transform::from_translation(firing_point),
forward, forward,
up, up,
@ -186,7 +201,7 @@ pub fn capture_hand_usage(
); );
// Increment indexes and timers // Increment indexes and timers
player_firing_info.current_round_index += 1; player_firing_info.current_round_index += 1;
player_firing_info.last_shot_timestamp = time.elapsed_seconds(); player_firing_info.last_shot_timestamp = resources.time.elapsed_seconds();
player_firing_info.full_auto_timer.reset(); player_firing_info.full_auto_timer.reset();
magazine_data.rounds_shot += 1; magazine_data.rounds_shot += 1;

View File

@ -4,7 +4,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use scenes::scene1; use scenes::scene1;
use setup::spawners::{spawn_point::SpawnPointPlugin, item::ItemSpawnPointPlugin};
use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin}; use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin};
mod comps; mod comps;
@ -34,7 +33,7 @@ fn setup_plugins(application: &mut App) {
//.add_plugins(WorldInspectorPlugin::new()) //.add_plugins(WorldInspectorPlugin::new())
.add_plugins(MainGameUIPlugin) .add_plugins(MainGameUIPlugin)
.add_plugins(MainEditorUiPlugin) .add_plugins(MainEditorUiPlugin)
.add_plugins((SpawnPointPlugin, ItemSpawnPointPlugin)); .add_plugins(RapierDebugRenderPlugin::default());
} }
fn load(application: &mut App) { fn load(application: &mut App) {

View File

@ -1,7 +1,7 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::{ use crate::{
comps::core::controller::capture_input, comps::core::{controller::capture_input, spawners::{player::player_spawner, spawn::SpawnerPlugin}},
logic::core::{ logic::core::{
guns::despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets}, guns::despawn_shots::{despawn_muzzle_flashes, despawn_stray_bullets},
player::{ player::{
@ -18,8 +18,6 @@ use crate::{
assets::load_all_assets, assets::load_all_assets,
equipment::{change_equipment, EquipmentChangeEvent}, equipment::{change_equipment, EquipmentChangeEvent},
load_state::GameLoadState, load_state::GameLoadState,
spawn::add_all_spawners,
spawners::player::player_spawner,
}, },
}; };
@ -33,6 +31,8 @@ pub fn load_scene(application: &mut App) {
application.insert_resource(MouseMovementSettings::default()); application.insert_resource(MouseMovementSettings::default());
application.insert_resource(AllFirearmAnimations::default()); application.insert_resource(AllFirearmAnimations::default());
application.insert_resource(PlayerValuesState::default()); application.insert_resource(PlayerValuesState::default());
application.add_plugins(SpawnerPlugin);
// Startup // Startup
application.add_systems(PreStartup, load_all_assets); application.add_systems(PreStartup, load_all_assets);
application.add_systems(Startup, spawn_ground); application.add_systems(Startup, spawn_ground);
@ -43,7 +43,7 @@ pub fn load_scene(application: &mut App) {
application.add_systems(Startup, setup_lighting); application.add_systems(Startup, setup_lighting);
application.add_systems(Startup, set_spawn_points); application.add_systems(Startup, set_spawn_points);
// Update // Update
add_all_spawners(application);
application.add_systems(Update, capture_input); application.add_systems(Update, capture_input);
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(Update, follow_cursor_with_camera);
@ -51,11 +51,12 @@ pub fn load_scene(application: &mut App) {
application.add_systems(Update, set_skybox_if_loaded); application.add_systems(Update, set_skybox_if_loaded);
application.add_systems(Update, update_camera_vertical_position); application.add_systems(Update, update_camera_vertical_position);
application.add_systems(Update, (capture_hand_usage, interact_action)); application.add_systems(Update, capture_hand_usage);
application.add_systems(Update, interact_action);
application.add_systems(Update, change_equipment.before(player_spawner)); application.add_systems(Update, change_equipment.before(player_spawner));
application.add_systems(Update, (despawn_muzzle_flashes, despawn_stray_bullets)); application.add_systems(Update, (despawn_muzzle_flashes, despawn_stray_bullets));
//application.add_systems(Update, register_bullet_hits); //application.add_systems(Update, register_bullet_hits);
application.add_event::<EquipmentChangeEvent>(); application.add_event::<EquipmentChangeEvent>();
} }

View File

@ -1,9 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::{ use crate::{comps::core::{markers::player::{Player, PlayerData}, spawners::{player::PlayerSpawnPoint, guns::{m4a1_spawner::M4a1SpawnPoint, glock17_spawner::Glock17SpawnPoint}}}, utils};
comps::core::markers::player::{Player, PlayerData},
setup::spawners::{player::PlayerSpawnPoint, guns::m4a1_spawner::M4a1SpawnPoint},
};
pub fn set_spawn_points(mut commands: Commands) { pub fn set_spawn_points(mut commands: Commands) {
commands.spawn(PlayerSpawnPoint { commands.spawn(PlayerSpawnPoint {
@ -11,6 +8,17 @@ pub fn set_spawn_points(mut commands: Commands) {
player: Player(PlayerData::default()), player: Player(PlayerData::default()),
}); });
commands.spawn(M4a1SpawnPoint { commands.spawn(M4a1SpawnPoint {
transform: Transform::from_xyz(20.0, 10.0, 10.0), transform: {
let mut transform = Transform::from_xyz(18.0, 10.0, 10.0);
transform.rotate_z(utils::rad_deg::radians_from_degrees(-90.0));
transform
},
});
commands.spawn(Glock17SpawnPoint {
transform: {
let mut transform = Transform::from_xyz(20.0, 10.0, 10.0);
transform.rotate_z(utils::rad_deg::radians_from_degrees(-90.0));
transform
},
}); });
} }

View File

@ -2,5 +2,3 @@ pub mod animations;
pub mod assets; pub mod assets;
pub mod equipment; pub mod equipment;
pub mod load_state; pub mod load_state;
pub mod spawn;
pub mod spawners;

View File

@ -1,16 +0,0 @@
use bevy::prelude::*;
use super::spawners::{item::item_spawner, player::player_spawner};
/// Where some Bundle T will replace this.
#[derive(Component, Reflect)]
pub struct SpawnPoint {
pub at: Transform,
}
pub fn add_all_spawners(application: &mut App) {
application.add_systems(
Update,
(player_spawner, item_spawner),
);
}

View File

@ -1 +0,0 @@
pub mod m4a1_spawner;

17
src/utils/hierarchy.rs Normal file
View File

@ -0,0 +1,17 @@
use bevy::prelude::*;
pub fn find_child_in_parent_children(commands: &mut Commands, parent_entity: Entity, descendant_entity: Entity, children: &Query<&Children>) -> bool {
let all_children = flatten_if_possible_inf_levels(commands, parent_entity, children);
all_children.contains(&descendant_entity)
}
fn flatten_if_possible_inf_levels(commands: &mut Commands, parent_entity: Entity, children: &Query<&Children>) -> Vec<Entity> {
let mut all_descendant_entities: Vec<Entity> = Vec::new();
let descendants = children.iter_descendants(parent_entity);
for descendant in descendants {
all_descendant_entities.push(descendant);
all_descendant_entities.append(&mut flatten_if_possible_inf_levels(commands, descendant, children));
}
all_descendant_entities
}

View File

@ -1 +1,2 @@
pub mod rad_deg; pub mod rad_deg;
pub mod hierarchy;