From 3f95e2cd5a02b840329f293d7d711a3eb43689e8 Mon Sep 17 00:00:00 2001 From: Franklin Date: Sat, 11 Nov 2023 19:03:11 -0400 Subject: [PATCH] Inventory backend --- src/comps/core/any_inventory.rs | 61 ++++++++++++++++++++++++++ src/comps/core/grid.rs | 22 ++++++++++ src/comps/core/inventory_item.rs | 39 ++++++++++++++++ src/comps/core/item.rs | 20 +++++++++ src/comps/core/markers/interactable.rs | 10 +++++ src/comps/core/markers/mod.rs | 3 +- src/comps/core/mod.rs | 4 ++ src/logic/core/player/hands.rs | 38 ++++++++++++---- src/main.rs | 1 + src/scenes/scene1/spawn_points.rs | 4 +- src/setup/equipment.rs | 19 ++++---- src/ui/game/inventory/menu.rs | 12 +++++ src/ui/game/inventory/mod.rs | 1 + src/ui/game/mod.rs | 3 +- src/ui/game/plugin.rs | 6 ++- 15 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 src/comps/core/any_inventory.rs create mode 100644 src/comps/core/grid.rs create mode 100644 src/comps/core/inventory_item.rs create mode 100644 src/comps/core/item.rs create mode 100644 src/comps/core/markers/interactable.rs create mode 100644 src/ui/game/inventory/menu.rs create mode 100644 src/ui/game/inventory/mod.rs diff --git a/src/comps/core/any_inventory.rs b/src/comps/core/any_inventory.rs new file mode 100644 index 0000000..921daf4 --- /dev/null +++ b/src/comps/core/any_inventory.rs @@ -0,0 +1,61 @@ +use bevy::{prelude::*, ecs::component::SparseStorage}; + +use super::{item::Item, inventory_item::InventoryItem, grid::UGrid}; + +#[derive(Component)] +pub struct AnyInventory { + size: UGrid, + items: Vec +} + +#[allow(unused)] +impl AnyInventory { + pub fn new(size: UGrid) -> Self { + Self { size, items: Vec::new() } + } + pub fn add_item_at( + &mut self, + position: UGrid, + item: impl Item, + ) { + // Is Item bigger than inventory? + // Does position + item size exceed bounds? + if !self.valid_item_and_size_for_inventory(position, &item) { + return; + } + // Is there an item in any of those places already? + if !self.item_fits_at(position, &item) { + return; + } + let spots_to_occupy = Self::get_spots_from_item_at_pos(position, &item); + self.items.push(InventoryItem::new(item, spots_to_occupy)); + } + // Is there any items in inventory that are in any of the spots that this new item will be in + pub fn item_fits_at(&self, position: UGrid, item: &impl Item) -> bool { + let spots_to_occupy = Self::get_spots_from_item_at_pos(position, item); + for inventory_item in self.items.iter() { + if inventory_item.is_in_range(&spots_to_occupy) { + return false + } + } + true + } + pub fn get_spots_from_item_at_pos(position: UGrid, item: &impl Item) -> Vec { + let end_position = position + item.inventory_size(); + let mut spots = Vec::new(); + for pos_width in position.width..end_position.width { + for pos_height in position.height..end_position.height { + spots.push(UGrid { width: pos_width, height: pos_height }); + } + } + spots + } + pub fn valid_item_and_size_for_inventory( + &self, + position: UGrid, + item: &impl Item, + ) -> bool { + let item_bounds = position + item.inventory_size(); + !(item_bounds.width > self.size.width || item_bounds.height > self.size.height) + } +} \ No newline at end of file diff --git a/src/comps/core/grid.rs b/src/comps/core/grid.rs new file mode 100644 index 0000000..a48fbf8 --- /dev/null +++ b/src/comps/core/grid.rs @@ -0,0 +1,22 @@ + +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct UGrid { + pub width: u32, + pub height: u32, +} + +impl std::ops::Add for UGrid { + type Output = UGrid; + + fn add(self, rhs: Self) -> Self::Output { + Self { width: self.width + rhs.width, height: self.height + rhs.height } + } +} + +impl std::ops::Sub for UGrid { + type Output = UGrid; + + fn sub(self, rhs: Self) -> Self::Output { + Self { width: self.width - rhs.width, height: self.height - rhs.height } + } +} diff --git a/src/comps/core/inventory_item.rs b/src/comps/core/inventory_item.rs new file mode 100644 index 0000000..c7ddcce --- /dev/null +++ b/src/comps/core/inventory_item.rs @@ -0,0 +1,39 @@ +use bevy::ecs::component::SparseStorage; + +use super::{item::Item, grid::UGrid}; + + +//#[derive()] +pub struct InventoryItem { + item: Box>, + /// Coordinates that this InventoryItem occupies inside an AnyInventory + occupied_spots: Vec, + rotated: Option, +} + +#[allow(unused)] +impl InventoryItem { + pub fn item(&self) -> &dyn Item { + self.item.as_ref() + } + pub fn rotated(&self) -> Option { + self.rotated + } + pub fn new( + item: impl Item, + occupied_spots: Vec, + ) -> Self { + let size = item.inventory_size(); + let rotated = item.inventory_rotatable().then(|| false); + Self { item: Box::new(item), occupied_spots, rotated } + } + /// Returns true if there is overlap between both + pub fn is_in_range(&self, spots_to_occupy: &Vec) -> bool { + for occupied_spot in self.occupied_spots.iter() { + if spots_to_occupy.contains(occupied_spot) { + return true + } + } + false + } +} \ No newline at end of file diff --git a/src/comps/core/item.rs b/src/comps/core/item.rs new file mode 100644 index 0000000..6a2996b --- /dev/null +++ b/src/comps/core/item.rs @@ -0,0 +1,20 @@ +use bevy::prelude::*; + +use super::grid::UGrid; + + +pub enum ItemType { + Holdable, + Equippable, + Consumable, +} + +pub trait Item: Component { + fn get_type(&self) -> ItemType; + fn asset_path(&self) -> &str; + /// Optional Stackable. If value is Some(x) x is the max quantity per stack + fn stackable(&self) -> Option; + fn inventory_size(&self) -> UGrid; + fn inventory_rotatable(&self) -> bool; + fn inventory_title(&self) -> String; +} \ No newline at end of file diff --git a/src/comps/core/markers/interactable.rs b/src/comps/core/markers/interactable.rs new file mode 100644 index 0000000..41d28e0 --- /dev/null +++ b/src/comps/core/markers/interactable.rs @@ -0,0 +1,10 @@ +use bevy::prelude::Component; + + + +#[allow(unused)] +#[derive(Component)] +pub enum Interactable { + Holdable, + Lootable, +} \ No newline at end of file diff --git a/src/comps/core/markers/mod.rs b/src/comps/core/markers/mod.rs index e83341c..f7b324a 100644 --- a/src/comps/core/markers/mod.rs +++ b/src/comps/core/markers/mod.rs @@ -3,4 +3,5 @@ pub mod firearm; pub mod holdable; pub mod player; pub mod muzzle_flash; -pub mod bullet; \ No newline at end of file +pub mod bullet; +pub mod interactable; \ No newline at end of file diff --git a/src/comps/core/mod.rs b/src/comps/core/mod.rs index 0f2b937..35791bb 100644 --- a/src/comps/core/mod.rs +++ b/src/comps/core/mod.rs @@ -1,2 +1,6 @@ pub mod controller; pub mod markers; +pub mod any_inventory; +pub mod item; +pub mod grid; +pub mod inventory_item; \ No newline at end of file diff --git a/src/logic/core/player/hands.rs b/src/logic/core/player/hands.rs index 4b0976d..6778b7e 100644 --- a/src/logic/core/player/hands.rs +++ b/src/logic/core/player/hands.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use crate::{ comps::core::markers::{firearm::{FirearmData, MagazineData}, holdable::InPlayerHands, player::{PlayerHand, Player}}, - logic::core::guns::{player_firing::PlayerFiringInfo, firearm::Firearm, shoot::shoot_bullet}, utils::rad_deg::radians_from_degrees, setup::{animations::AllFirearmAnimations, load_state::GameLoadState, equipment::{EquipmentChangeEvent, Equipment}}, ui::game::settings::SettingsScreenUIConfiguration, + logic::core::guns::{player_firing::PlayerFiringInfo, shoot::shoot_bullet}, utils::rad_deg::radians_from_degrees, setup::{animations::AllFirearmAnimations, load_state::GameLoadState, equipment::{EquipmentChangeEvent, Equipment}}, ui::game::settings::SettingsScreenUIConfiguration, }; pub fn capture_hand_usage( @@ -23,7 +23,7 @@ pub fn capture_hand_usage( animation_clips: Res>, game_load_state: Res, - + #[allow(unused)] mut equipment_change_event_writer: EventWriter, settings_screen_config: Res, @@ -36,7 +36,23 @@ pub fn capture_hand_usage( if player_query.iter().len() == 0 { return; } - if let Some(player_firearm) = player_query.single().0.equipment.primary_firearm.clone() { + + // Equipping stuff + + + // Equipping gun + /*if !settings_screen_config.settings_menu_shown { + if keyboard_input.just_pressed(KeyCode::Key1) { + equipment_change_event_writer.send(EquipmentChangeEvent(Equipment { primary_firearm: Some(Firearm::M4A1) } )); + } else if keyboard_input.just_pressed(KeyCode::Key2) { + equipment_change_event_writer.send(EquipmentChangeEvent(Equipment { primary_firearm: Some(Firearm::Glock17) } )); + } else if keyboard_input.just_pressed(KeyCode::Key3) { + equipment_change_event_writer.send(EquipmentChangeEvent(Equipment { primary_firearm: None } )); + } + }*/ + + // Firearm stuff + if let Equipment::Firearm(player_firearm) = player_query.single().0.equipment.clone() { for mut player_firing_info in player_firing_info_query.iter_mut() { player_firing_info.full_auto_timer.tick(time.delta()); @@ -87,12 +103,7 @@ pub fn capture_hand_usage( (time.delta_seconds() / firearm_data.rebound_time_seconds).clamp(0.0, 1.0), ); } - // Equipping gun - if keyboard_input.just_pressed(KeyCode::Key1) && !settings_screen_config.settings_menu_shown { - equipment_change_event_writer.send(EquipmentChangeEvent(Equipment{ primary_firearm: Some(Firearm::M4A1) })); - } else if keyboard_input.just_pressed(KeyCode::Key2) && !settings_screen_config.settings_menu_shown { - equipment_change_event_writer.send(EquipmentChangeEvent(Equipment{ primary_firearm: Some(Firearm::Glock17) })); - } + // SHOOTING & RECOIL if mouse_buttons.pressed(MouseButton::Left) && !settings_screen_config.settings_menu_shown { if player_firing_info.full_auto_timer.finished() { @@ -149,3 +160,12 @@ pub fn capture_hand_usage( } } + +#[allow(unused)] +/// Method that is run when player hits interact button. +/// Should raycast where the player is looking and scan for interactable +pub fn interact_action( + +) { + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f63167e..8738d2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +#![feature(step_trait)] use bevy::prelude::*; use bevy_rapier3d::prelude::*; use scenes::scene1; diff --git a/src/scenes/scene1/spawn_points.rs b/src/scenes/scene1/spawn_points.rs index 80d8f0d..fb3a88e 100644 --- a/src/scenes/scene1/spawn_points.rs +++ b/src/scenes/scene1/spawn_points.rs @@ -1,8 +1,8 @@ use bevy::prelude::*; -use crate::{setup::{spawn::SpawnPoint, equipment::Equipment}, comps::core::markers::player::{Player, PlayerData}, logic::core::guns::firearm::Firearm}; +use crate::{setup::{spawn::SpawnPoint, equipment::Equipment}, comps::core::markers::player::{Player, PlayerData}}; pub fn set_spawn_points(mut commands: Commands) { - commands.spawn(SpawnPoint { at: Transform::from_xyz(3.0, 5.0, 2.0), what: Player(PlayerData{ equipment: Equipment { primary_firearm: Some(Firearm::Glock17) }}) }); + commands.spawn(SpawnPoint { at: Transform::from_xyz(3.0, 5.0, 2.0), what: Player(PlayerData { equipment: Equipment::Nothing }) }); } \ No newline at end of file diff --git a/src/setup/equipment.rs b/src/setup/equipment.rs index effe3eb..92c602f 100644 --- a/src/setup/equipment.rs +++ b/src/setup/equipment.rs @@ -9,9 +9,11 @@ use super::assets::{GltfAssets, GltfAssetType}; #[derive(Event)] pub struct EquipmentChangeEvent(pub Equipment); /// Foundation for inventory System. -#[derive(Component, Clone, Default, Reflect)] -pub struct Equipment { - pub primary_firearm: Option, +#[derive(Component, Clone, Default, Reflect, PartialEq, PartialOrd)] +pub enum Equipment { + Firearm(Firearm), + #[default] + Nothing, } /// Called whenever player wants to change equipment @@ -25,22 +27,21 @@ pub fn change_equipment( loaded_gltf_assets: Res>, ) { for equipment_change_event in equipment_change_event_reader.read() { - // TODO: Equipment change let Ok((mut player, player_firing_info)) = player_query.get_single_mut() else { return; } ; // Primary firearm change - if equipment_change_event.0.primary_firearm != player.0.equipment.primary_firearm { + if equipment_change_event.0 != player.0.equipment { let player_hands = player_hands_query.single_mut(); - commands.entity(player_hands).despawn_descendants(); // Don't do this without keeping the state from the last mag - if let Some(new_firearm) = equipment_change_event.0.primary_firearm.clone() { + commands.entity(player_hands).despawn_descendants(); // TODO: Don't do this without keeping the state from the last mag + if let Equipment::Firearm(new_firearm) = equipment_change_event.0.clone() { spawn_firearm_on_player_hands(&mut commands, player_firing_info, player_hands, &assets_gltf, &loaded_gltf_assets, new_firearm); } - + // Set the player's equipment to the newly spawned equipment - player.0.equipment.primary_firearm = equipment_change_event.0.primary_firearm.clone(); + player.0.equipment = equipment_change_event.0.clone(); println!("Equipment change done"); } diff --git a/src/ui/game/inventory/menu.rs b/src/ui/game/inventory/menu.rs new file mode 100644 index 0000000..ee7b767 --- /dev/null +++ b/src/ui/game/inventory/menu.rs @@ -0,0 +1,12 @@ +use bevy::prelude::*; + +//use crate::comps::core::any_inventory::AnyInventory; + + +#[allow(unused)] +pub fn setup_inventory_screen( + mut commands: Commands, + +) { + +} \ No newline at end of file diff --git a/src/ui/game/inventory/mod.rs b/src/ui/game/inventory/mod.rs new file mode 100644 index 0000000..915a9fa --- /dev/null +++ b/src/ui/game/inventory/mod.rs @@ -0,0 +1 @@ +pub mod menu; \ No newline at end of file diff --git a/src/ui/game/mod.rs b/src/ui/game/mod.rs index ec9d210..2cebe68 100644 --- a/src/ui/game/mod.rs +++ b/src/ui/game/mod.rs @@ -2,4 +2,5 @@ pub mod plugin; pub mod fps_counter; pub mod settings; -pub mod settings_screen; \ No newline at end of file +pub mod settings_screen; +pub mod inventory; \ No newline at end of file diff --git a/src/ui/game/plugin.rs b/src/ui/game/plugin.rs index bdf829a..006ac6b 100644 --- a/src/ui/game/plugin.rs +++ b/src/ui/game/plugin.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use crate::ui::game::settings::GameConfiguration; -use super::{fps_counter, settings_screen, settings::SettingsScreenUIConfiguration}; +use super::{fps_counter, settings_screen, settings::SettingsScreenUIConfiguration, inventory}; pub struct MainGameUIPlugin; @@ -12,7 +12,9 @@ impl Plugin for MainGameUIPlugin { app.insert_resource(SettingsScreenUIConfiguration::default()); app.add_systems(Startup, ( settings_screen::setup_settings_screen, - fps_counter::setup_fps_counter)); + fps_counter::setup_fps_counter, + inventory::menu::setup_inventory_screen, + )); app.add_systems(Update, ( settings_screen::toggle_settings_screen, settings_screen::handle_settings_button_click,