Inventory backend

This commit is contained in:
Franklin 2023-11-11 19:03:11 -04:00
parent 26d03de52e
commit 3f95e2cd5a
15 changed files with 219 additions and 24 deletions

View File

@ -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<InventoryItem>
}
#[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<Storage = SparseStorage>,
) {
// 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<Storage = SparseStorage>) -> 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<Storage = SparseStorage>) -> Vec<UGrid> {
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<Storage = SparseStorage>,
) -> bool {
let item_bounds = position + item.inventory_size();
!(item_bounds.width > self.size.width || item_bounds.height > self.size.height)
}
}

22
src/comps/core/grid.rs Normal file
View File

@ -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 }
}
}

View File

@ -0,0 +1,39 @@
use bevy::ecs::component::SparseStorage;
use super::{item::Item, grid::UGrid};
//#[derive()]
pub struct InventoryItem {
item: Box<dyn Item<Storage = SparseStorage>>,
/// Coordinates that this InventoryItem occupies inside an AnyInventory
occupied_spots: Vec<UGrid>,
rotated: Option<bool>,
}
#[allow(unused)]
impl InventoryItem {
pub fn item(&self) -> &dyn Item<Storage = SparseStorage> {
self.item.as_ref()
}
pub fn rotated(&self) -> Option<bool> {
self.rotated
}
pub fn new(
item: impl Item<Storage = SparseStorage>,
occupied_spots: Vec<UGrid>,
) -> 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<UGrid>) -> bool {
for occupied_spot in self.occupied_spots.iter() {
if spots_to_occupy.contains(occupied_spot) {
return true
}
}
false
}
}

20
src/comps/core/item.rs Normal file
View File

@ -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<u32>;
fn inventory_size(&self) -> UGrid;
fn inventory_rotatable(&self) -> bool;
fn inventory_title(&self) -> String;
}

View File

@ -0,0 +1,10 @@
use bevy::prelude::Component;
#[allow(unused)]
#[derive(Component)]
pub enum Interactable {
Holdable,
Lootable,
}

View File

@ -4,3 +4,4 @@ pub mod holdable;
pub mod player; pub mod player;
pub mod muzzle_flash; pub mod muzzle_flash;
pub mod bullet; pub mod bullet;
pub mod interactable;

View File

@ -1,2 +1,6 @@
pub mod controller; pub mod controller;
pub mod markers; pub mod markers;
pub mod any_inventory;
pub mod item;
pub mod grid;
pub mod inventory_item;

View File

@ -2,7 +2,7 @@ use bevy::prelude::*;
use crate::{ use crate::{
comps::core::markers::{firearm::{FirearmData, MagazineData}, holdable::InPlayerHands, player::{PlayerHand, Player}}, 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( pub fn capture_hand_usage(
@ -23,7 +23,7 @@ pub fn capture_hand_usage(
animation_clips: Res<Assets<AnimationClip>>, animation_clips: Res<Assets<AnimationClip>>,
game_load_state: Res<GameLoadState>, game_load_state: Res<GameLoadState>,
#[allow(unused)]
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>, mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
settings_screen_config: Res<SettingsScreenUIConfiguration>, settings_screen_config: Res<SettingsScreenUIConfiguration>,
@ -36,7 +36,23 @@ pub fn capture_hand_usage(
if player_query.iter().len() == 0 { if player_query.iter().len() == 0 {
return; 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() { 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(time.delta());
@ -87,12 +103,7 @@ pub fn capture_hand_usage(
(time.delta_seconds() / firearm_data.rebound_time_seconds).clamp(0.0, 1.0), (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 // SHOOTING & RECOIL
if mouse_buttons.pressed(MouseButton::Left) && !settings_screen_config.settings_menu_shown { if mouse_buttons.pressed(MouseButton::Left) && !settings_screen_config.settings_menu_shown {
if player_firing_info.full_auto_timer.finished() { 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(
) {
}

View File

@ -1,3 +1,4 @@
#![feature(step_trait)]
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use scenes::scene1; use scenes::scene1;

View File

@ -1,8 +1,8 @@
use bevy::prelude::*; 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) { 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 }) });
} }

View File

@ -9,9 +9,11 @@ use super::assets::{GltfAssets, GltfAssetType};
#[derive(Event)] #[derive(Event)]
pub struct EquipmentChangeEvent(pub Equipment); pub struct EquipmentChangeEvent(pub Equipment);
/// Foundation for inventory System. /// Foundation for inventory System.
#[derive(Component, Clone, Default, Reflect)] #[derive(Component, Clone, Default, Reflect, PartialEq, PartialOrd)]
pub struct Equipment { pub enum Equipment {
pub primary_firearm: Option<Firearm>, Firearm(Firearm),
#[default]
Nothing,
} }
/// Called whenever player wants to change equipment /// Called whenever player wants to change equipment
@ -25,22 +27,21 @@ pub fn change_equipment(
loaded_gltf_assets: Res<Assets<Gltf>>, loaded_gltf_assets: Res<Assets<Gltf>>,
) { ) {
for equipment_change_event in equipment_change_event_reader.read() { 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 { let Ok((mut player, player_firing_info)) = player_query.get_single_mut() else {
return; return;
} ; } ;
// Primary firearm change // 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(); 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 commands.entity(player_hands).despawn_descendants(); // TODO: Don't do this without keeping the state from the last mag
if let Some(new_firearm) = equipment_change_event.0.primary_firearm.clone() { 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); 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 // 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"); println!("Equipment change done");
} }

View File

@ -0,0 +1,12 @@
use bevy::prelude::*;
//use crate::comps::core::any_inventory::AnyInventory;
#[allow(unused)]
pub fn setup_inventory_screen(
mut commands: Commands,
) {
}

View File

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

View File

@ -3,3 +3,4 @@ pub mod plugin;
pub mod fps_counter; pub mod fps_counter;
pub mod settings; pub mod settings;
pub mod settings_screen; pub mod settings_screen;
pub mod inventory;

View File

@ -2,7 +2,7 @@ use bevy::prelude::*;
use crate::ui::game::settings::GameConfiguration; 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; pub struct MainGameUIPlugin;
@ -12,7 +12,9 @@ impl Plugin for MainGameUIPlugin {
app.insert_resource(SettingsScreenUIConfiguration::default()); app.insert_resource(SettingsScreenUIConfiguration::default());
app.add_systems(Startup, ( app.add_systems(Startup, (
settings_screen::setup_settings_screen, settings_screen::setup_settings_screen,
fps_counter::setup_fps_counter)); fps_counter::setup_fps_counter,
inventory::menu::setup_inventory_screen,
));
app.add_systems(Update, ( app.add_systems(Update, (
settings_screen::toggle_settings_screen, settings_screen::toggle_settings_screen,
settings_screen::handle_settings_button_click, settings_screen::handle_settings_button_click,