Dropping weapons with G. Updates on inventory and slots

This commit is contained in:
Franklin 2023-11-15 10:49:34 -04:00
parent a81b2f340e
commit 9538f73075
12 changed files with 216 additions and 110 deletions

View File

@ -1,5 +1,13 @@
use std::sync::Arc;
use bevy::prelude::*;
use crate::comps::core::{items::item::Item, inventory::slot::PlayerInventorySlotType};
/// This will be what is triggered after picking up an item or dropping an item.
#[derive(Event)]
pub struct InventoryChangedEvent {}
pub struct PlayerInventoryChangedEvent {
/// A None value will remove the item from the inventory slot
pub item: Option<Arc<dyn Item>>,
pub slot_type: PlayerInventorySlotType
}

View File

@ -1,8 +1,11 @@
use bevy::reflect::Reflect;
use crate::comps::core::items::item::Item;
/// # ItemInventory
/// Specifically made to hold single items such as Guns, Pieces of armor.
#[derive(Default)]
#[derive(Default, Reflect)]
pub struct ItemInventory {
#[reflect(ignore)]
pub item: Option<Box<dyn Item>>,
}

View File

@ -3,3 +3,4 @@
pub mod item_inventory;
pub mod player_inventory;
pub mod plugin;
pub mod slot;

View File

@ -1,14 +1,16 @@
use bevy::prelude::*;
use bevy::{prelude::*, gltf::Gltf};
use crate::comps::core::items::item::Item;
use crate::{comps::core::{items::item::Item, events::inventory_changed::PlayerInventoryChangedEvent, markers::firearm::FirearmType}, setup::assets::GltfAssets};
use super::item_inventory::ItemInventory;
use super::{item_inventory::ItemInventory, slot::PlayerInventorySlotType};
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct PlayerInventory {
pub primary: ItemInventory,
pub secondary: ItemInventory,
//pub backpack: AnyInventory,
pub current_slot: Option<PlayerInventorySlotType>,
}
impl Default for PlayerInventory {
@ -17,10 +19,13 @@ impl Default for PlayerInventory {
primary: Default::default(),
secondary: Default::default(),
//backpack: AnyInventory::new(UGrid::new_square(10)),
current_slot: None
}
}
}
#[allow(unused)]
impl PlayerInventory {
pub fn primary_occupied(&self) -> bool {
self.primary.item.is_some()
@ -35,4 +40,98 @@ impl PlayerInventory {
pub fn get_secondary(&self) -> &Option<Box<dyn Item>> {
&self.secondary.item
}
pub fn get_primary_mut(&mut self) -> &mut ItemInventory {
&mut self.primary
}
pub fn get_secondary_mut(&mut self) -> &mut ItemInventory {
&mut self.secondary
}
/// This comes from a PickupItemEvent usually
pub fn pickup_item(&mut self, item: &dyn Item, slot: PlayerInventorySlotType) {
let mut inventory_slot = match slot {
PlayerInventorySlotType::Primary => &mut self.primary,
PlayerInventorySlotType::Secondary => &mut self.secondary,
};
let Some(firearm) = item.get_firearm() else { return; };
inventory_slot.item = Some(firearm.get_item_box());
}
pub fn drop_item(&mut self, slot: PlayerInventorySlotType) {
match slot {
PlayerInventorySlotType::Primary => self.primary.item = None,
PlayerInventorySlotType::Secondary => self.secondary.item = None,
}
}
}
/// Drop item from a specific slot.
/// This fn does not equip an item
pub fn drop_slot_in_game_world(
commands: &mut Commands,
player_transform: &Transform,
inventory_changed_events: &mut EventWriter<PlayerInventoryChangedEvent>,
player_inventory: &mut PlayerInventory,
assets_gltf: &Res<GltfAssets>,
loaded_gltf_assets: &Res<Assets<Gltf>>,
slot: PlayerInventorySlotType,
) {
let drop_position = Transform::from_translation(
player_transform.translation
+ player_transform.up() * 3.0
+ player_transform.forward() * 2.0,
);
let drop_impulse = player_transform.translation
+ player_transform.up() * 100.0
+ player_transform.forward() * 30.0;
let item_inventory_slot = match slot {
PlayerInventorySlotType::Primary => {
player_inventory.get_primary_mut()
},
PlayerInventorySlotType::Secondary => {
player_inventory.get_secondary_mut()
},
};
match &item_inventory_slot.item {
Some(ref item) => {
match item.get_firearm() {
Some(firearm) => {
match firearm.firearm_data().firearm_type {
FirearmType::Primary => {
// Send equipment_changed_event
if let Some(primary_item) = player_inventory.get_primary() {
// Drop this one
primary_item.spawn(
commands,
drop_position,
&assets_gltf,
&loaded_gltf_assets,
drop_impulse,
);
}
player_inventory.drop_item(PlayerInventorySlotType::Primary);
inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(firearm.get_item_arc()), slot_type: PlayerInventorySlotType::Primary });
}
FirearmType::Secondary => {
if let Some(secondary) = player_inventory.get_secondary() {
secondary.spawn(
commands,
drop_position,
&assets_gltf,
&loaded_gltf_assets,
drop_impulse,
);
}
player_inventory.drop_item(PlayerInventorySlotType::Secondary);
inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(firearm.get_item_arc()), slot_type: PlayerInventorySlotType::Secondary });
}
}
},
None => { unimplemented!("Item being dropped from inventory is not a Firearm. This still isn't implemented") } // Item isn't a firearm. Unimplemented
}
},
None => { return; }, // No item to drop
};
}

View File

@ -1,15 +1,20 @@
use bevy::prelude::*;
use crate::{
comps::core::events::pickup_item::PickupItemEvent,
comps::core::events::{pickup_item::PickupItemEvent, inventory_changed::PlayerInventoryChangedEvent},
logic::core::player::inventory::update_player_inventory_system,
};
use super::player_inventory::PlayerInventory;
pub struct InventoryPlugin;
impl Plugin for InventoryPlugin {
fn build(&self, app: &mut App) {
app.register_type::<PlayerInventory>();
app.add_event::<PickupItemEvent>();
app.add_event::<PlayerInventoryChangedEvent>();
app.add_systems(Update, update_player_inventory_system);
}
}

View File

@ -0,0 +1,11 @@
use bevy::reflect::Reflect;
#[derive(Clone, Copy, Reflect, Default)]
pub enum PlayerInventorySlotType {
#[default]
Primary,
Secondary,
//Slots, // TODO: Pass which slot
}

View File

@ -4,12 +4,12 @@ use crate::{
comps::core::{
grid::UGrid,
items::item::{Item, ItemType},
markers::holdable::HoldableObjectType,
markers::holdable::HoldableObjectType, inventory::slot::PlayerInventorySlotType,
},
logic::core::guns::firearm::Firearm,
};
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct Glock17GunItem;
impl Item for Glock17GunItem {
@ -44,4 +44,8 @@ impl Item for Glock17GunItem {
fn inventory_description(&self) -> String {
String::from("Pistol chambered in 9x19mm.")
}
fn get_item_slot(&self) -> PlayerInventorySlotType {
PlayerInventorySlotType::Secondary
}
}

View File

@ -4,12 +4,12 @@ use crate::{
comps::core::{
grid::UGrid,
items::item::{Item, ItemType},
markers::holdable::HoldableObjectType,
markers::holdable::HoldableObjectType, inventory::slot::PlayerInventorySlotType,
},
logic::core::guns::firearm::Firearm,
};
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct M4a1GunItem;
impl Item for M4a1GunItem {
@ -43,4 +43,8 @@ impl Item for M4a1GunItem {
fn inventory_description(&self) -> String {
String::from("Rifle chambered in 5.56x45mm NATO, shoots 800 rounds per minute.")
}
fn get_item_slot(&self) -> PlayerInventorySlotType {
PlayerInventorySlotType::Primary
}
}

View File

@ -1,7 +1,7 @@
use crate::{
comps::core::{
grid::UGrid,
markers::{firearm::FirearmData, holdable::HoldableObjectType, interactable::Interactable},
markers::{firearm::FirearmData, holdable::HoldableObjectType, interactable::Interactable}, inventory::slot::PlayerInventorySlotType,
},
logic::core::guns::firearm::Firearm,
setup::assets::{GltfAssetType, GltfAssets},
@ -18,7 +18,7 @@ pub enum ItemType {
}
#[bevy_trait_query::queryable]
pub trait Item: Sync + Send {
pub trait Item: Sync + Send + Reflect {
fn get_type(&self) -> ItemType;
fn asset_path(&self) -> &str;
/// Optional Stackable. If value is Some(x) x is the max quantity per stack
@ -114,4 +114,5 @@ pub trait Item: Sync + Send {
_ => None,
}
}
fn get_item_slot(&self) -> PlayerInventorySlotType;
}

View File

@ -1,10 +1,10 @@
use bevy::{ecs::system::SystemParam, prelude::*};
use bevy::{ecs::system::SystemParam, prelude::*, gltf::Gltf};
use bevy_rapier3d::prelude::*;
use crate::{
comps::core::{
events::pickup_item::PickupItemEvent,
inventory::player_inventory::PlayerInventory,
events::{pickup_item::PickupItemEvent, inventory_changed::PlayerInventoryChangedEvent},
inventory::{player_inventory::{PlayerInventory, self}, slot::PlayerInventorySlotType},
markers::{
camera::MainCamera,
firearm::{FirearmData, MagazineData},
@ -17,7 +17,7 @@ use crate::{
setup::{
animations::AllFirearmAnimations,
equipment::{Equipment, EquipmentChangeEvent},
load_state::GameLoadState,
load_state::GameLoadState, assets::GltfAssets,
},
ui::game::{game_ui_state::GameUiState, hud::hud::HudState},
utils::{self, rad_deg::radians_from_degrees},
@ -34,6 +34,8 @@ pub struct CaptureHandUsageResourcesParams<'w> {
animation_clips: Res<'w, Assets<AnimationClip>>,
all_firearm_animations: Res<'w, AllFirearmAnimations>,
time: Res<'w, Time>,
assets_gltf: Res<'w, GltfAssets>,
loaded_gltf_assets: Res<'w, Assets<Gltf>>,
}
#[allow(irrefutable_let_patterns)]
@ -41,7 +43,7 @@ pub fn capture_hand_usage(
mut resources: CaptureHandUsageResourcesParams,
mut commands: Commands,
mut hand_query: Query<&mut Transform, With<PlayerHand>>,
mut hand_query: Query<&mut Transform, (With<PlayerHand>, Without<Player>)>,
mut firearm_query: Query<
(
Entity,
@ -51,13 +53,13 @@ pub fn capture_hand_usage(
),
(With<InPlayerHands>, Without<PlayerHand>),
>,
player_query: Query<(&Player, &PlayerInventory, Entity)>,
mut player_firing_info_query: Query<&mut PlayerFiringInfo, With<Player>>,
mut player_query: Query<(&Player, &mut PlayerInventory, Entity, &Transform, &mut PlayerFiringInfo)>,
mut animation_players: Query<(Entity, &mut AnimationPlayer)>,
children: Query<&Children>,
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
mut inventory_changed_events: EventWriter<PlayerInventoryChangedEvent>,
) {
if !resources.game_load_state.player_loaded {
return;
@ -68,41 +70,54 @@ pub fn capture_hand_usage(
// Equipping stuff
// Equipping gun
// Validate player has primary item, and secondary item in inventory
if !resources.game_ui_state.any_window() {
if resources.keyboard_input.just_pressed(KeyCode::Key1) {
if let Some(primary_item) = player_query.single().1.get_primary() {
if let Some(primary_firearm) = primary_item.get_firearm() {
if Equipment::Firearm(primary_firearm.clone())
!= player_query.single().0 .0.equipment
{
equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(primary_firearm)));
for (player, mut player_inventory, _player_entity, player_transform, mut player_firing_info) in player_query.iter_mut() {
// Equipping gun
// Validate player has primary item, and secondary item in inventory
if !resources.game_ui_state.any_window() {
if resources.keyboard_input.just_pressed(KeyCode::Key1) {
if let Some(primary_item) = player_inventory.get_primary() {
if let Some(primary_firearm) = primary_item.get_firearm() {
if Equipment::Firearm(primary_firearm.clone())
!= player.0.equipment
{
equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(primary_firearm)));
player_inventory.current_slot = Some(PlayerInventorySlotType::Primary);
}
}
}
}
} else if resources.keyboard_input.just_pressed(KeyCode::Key2) {
if let Some(secondary_item) = player_query.single().1.get_secondary() {
if let Some(secondary_firearm) = secondary_item.get_firearm() {
if Equipment::Firearm(secondary_firearm.clone())
!= player_query.single().0 .0.equipment
{
equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(secondary_firearm)));
} else if resources.keyboard_input.just_pressed(KeyCode::Key2) {
if let Some(secondary_item) = player_inventory.get_secondary() {
if let Some(secondary_firearm) = secondary_item.get_firearm() {
if Equipment::Firearm(secondary_firearm.clone())
!= player.0.equipment
{
equipment_change_event_writer
.send(EquipmentChangeEvent(Equipment::Firearm(secondary_firearm)));
player_inventory.current_slot = Some(PlayerInventorySlotType::Secondary);
}
}
}
}
} else if resources.keyboard_input.just_pressed(KeyCode::Key3) {
if Equipment::Nothing != player_query.single().0 .0.equipment {
equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing));
} else if resources.keyboard_input.just_pressed(KeyCode::Key3) {
if Equipment::Nothing != player.0.equipment {
equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing));
player_inventory.current_slot = None;
}
} else if resources.keyboard_input.just_pressed(KeyCode::G) {
match player_inventory.current_slot {
Some(current_slot) => {
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);
equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing));
},
None => {},
}
}
}
}
// Firearm stuff
if let Equipment::Firearm(player_firearm) = player_query.single().0 .0.equipment.clone() {
for mut player_firing_info in player_firing_info_query.iter_mut() {
// Firearm stuff
if let Equipment::Firearm(player_firearm) = player.0.equipment.clone() {
player_firing_info
.full_auto_timer
.tick(resources.time.delta());
@ -268,9 +283,13 @@ pub fn capture_hand_usage(
}
}
}
}
}
}
}
/// Method that is run when player hits interact button.

View File

@ -2,10 +2,9 @@ use bevy::{gltf::Gltf, prelude::*};
use crate::{
comps::core::{
events::pickup_item::PickupItemEvent,
inventory::player_inventory::PlayerInventory,
items::item::ItemType,
markers::{firearm::FirearmType, holdable::HoldableObjectType, player::Player},
events::{pickup_item::PickupItemEvent, inventory_changed::PlayerInventoryChangedEvent},
inventory::player_inventory::{PlayerInventory, self},
markers::player::Player,
},
setup::assets::GltfAssets,
};
@ -13,6 +12,7 @@ use crate::{
pub fn update_player_inventory_system(
mut commands: Commands,
mut pickup_item_events: EventReader<PickupItemEvent>,
mut inventory_changed_events: EventWriter<PlayerInventoryChangedEvent>,
mut player_query: Query<(Entity, &mut PlayerInventory, &Transform), With<Player>>,
assets_gltf: Res<GltfAssets>,
loaded_gltf_assets: Res<Assets<Gltf>>,
@ -21,64 +21,15 @@ pub fn update_player_inventory_system(
for (player_entity, mut player_inventory, player_transform) in player_query.iter_mut() {
if player_entity == event.player {
// Get item type and where it should go
match event.item.get_type() {
ItemType::Holdable(holdable_object) => {
match holdable_object {
HoldableObjectType::Firearm(firearm) => {
commands
.entity(event.entity)
.despawn_descendants()
.despawn();
let drop_position = Transform::from_translation(
player_transform.translation
+ player_transform.up() * 3.0
+ player_transform.forward() * 2.0,
);
let drop_impulse = player_transform.translation
+ player_transform.up() * 100.0
+ player_transform.forward() * 30.0;
match firearm.firearm_data().firearm_type {
FirearmType::Primary => {
// Send equipment_changed_event
if let Some(primary_item) = player_inventory.get_primary() {
// Drop this one
primary_item.spawn(
&mut commands,
drop_position,
&assets_gltf,
&loaded_gltf_assets,
drop_impulse,
);
player_inventory.primary.item =
Some(firearm.get_item_box())
} else {
player_inventory.primary.item =
Some(firearm.get_item_box())
}
}
FirearmType::Secondary => {
if let Some(secondary) = player_inventory.get_secondary() {
secondary.spawn(
&mut commands,
drop_position,
&assets_gltf,
&loaded_gltf_assets,
drop_impulse,
);
player_inventory.secondary.item =
Some(firearm.get_item_box())
} else {
player_inventory.secondary.item =
Some(firearm.get_item_box())
}
}
}
}
}
}
ItemType::Equippable => todo!(),
ItemType::Consumable => todo!(),
}
commands
.entity(event.entity)
.despawn_descendants()
.despawn();
player_inventory::drop_slot_in_game_world(&mut commands, player_transform, &mut inventory_changed_events, &mut player_inventory, &assets_gltf, &loaded_gltf_assets, event.item.get_item_slot());
player_inventory.pickup_item(event.item.as_ref(), event.item.get_item_slot());
// TODO: Equip
}
}
}