Inventory UI & system combined. Dropping works, pickup works, work on UI

This commit is contained in:
Franklin 2023-11-15 12:20:01 -04:00
parent 8c30ba6d9f
commit 6c243e5f4d
8 changed files with 205 additions and 14 deletions

View File

@ -52,6 +52,7 @@ impl PlayerInventory {
let mut inventory_slot = match slot { let mut inventory_slot = match slot {
PlayerInventorySlotType::Primary => &mut self.primary, PlayerInventorySlotType::Primary => &mut self.primary,
PlayerInventorySlotType::Secondary => &mut self.secondary, PlayerInventorySlotType::Secondary => &mut self.secondary,
_ => unimplemented!(),
}; };
let Some(firearm) = item.get_firearm() else { return; }; let Some(firearm) = item.get_firearm() else { return; };
inventory_slot.item = Some(firearm.get_item_box()); inventory_slot.item = Some(firearm.get_item_box());
@ -60,6 +61,7 @@ impl PlayerInventory {
match slot { match slot {
PlayerInventorySlotType::Primary => self.primary.item = None, PlayerInventorySlotType::Primary => self.primary.item = None,
PlayerInventorySlotType::Secondary => self.secondary.item = None, PlayerInventorySlotType::Secondary => self.secondary.item = None,
_ => unimplemented!(),
} }
} }
} }
@ -91,6 +93,7 @@ pub fn drop_slot_in_game_world(
PlayerInventorySlotType::Secondary => { PlayerInventorySlotType::Secondary => {
player_inventory.get_secondary_mut() player_inventory.get_secondary_mut()
}, },
_ => { unimplemented!() }
}; };
match &item_inventory_slot.item { match &item_inventory_slot.item {
@ -111,7 +114,7 @@ pub fn drop_slot_in_game_world(
); );
} }
player_inventory.drop_item(PlayerInventorySlotType::Primary); player_inventory.drop_item(PlayerInventorySlotType::Primary);
inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(firearm.get_item_arc()), slot_type: PlayerInventorySlotType::Primary }); inventory_changed_events.send(PlayerInventoryChangedEvent { item: None, slot_type: PlayerInventorySlotType::Primary });
} }
FirearmType::Secondary => { FirearmType::Secondary => {
if let Some(secondary) = player_inventory.get_secondary() { if let Some(secondary) = player_inventory.get_secondary() {
@ -124,7 +127,7 @@ pub fn drop_slot_in_game_world(
); );
} }
player_inventory.drop_item(PlayerInventorySlotType::Secondary); player_inventory.drop_item(PlayerInventorySlotType::Secondary);
inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(firearm.get_item_arc()), slot_type: PlayerInventorySlotType::Secondary }); inventory_changed_events.send(PlayerInventoryChangedEvent { item: None, slot_type: PlayerInventorySlotType::Secondary });
} }
} }
}, },

View File

@ -2,10 +2,23 @@ use bevy::reflect::Reflect;
#[derive(Clone, Copy, Reflect, Default)] #[derive(Clone, Copy, Reflect, Default, PartialEq, Eq, PartialOrd, Ord)]
pub enum PlayerInventorySlotType { pub enum PlayerInventorySlotType {
#[default] #[default]
Primary, Primary,
Secondary, Secondary,
Backpack,
BodyArmor,
//Slots, // TODO: Pass which slot //Slots, // TODO: Pass which slot
} }
impl PlayerInventorySlotType {
pub fn to_slot_title(&self) -> String {
match self {
PlayerInventorySlotType::Primary => String::from("Primary"),
PlayerInventorySlotType::Secondary => String::from("Secondary"),
PlayerInventorySlotType::Backpack => String::from("Backpack"),
PlayerInventorySlotType::BodyArmor => String::from("Body Armor"),
}
}
}

View File

@ -1,4 +1,9 @@
use bevy::ecs::component::Component; use bevy::ecs::component::Component;
use crate::comps::core::inventory::slot::PlayerInventorySlotType;
#[derive(Component)] #[derive(Component)]
pub struct InventoryScreenUiMarker; pub struct InventoryScreenUiMarker;
#[derive(Component, PartialEq, Eq, PartialOrd, Ord)]
pub struct InventorySlotUiMarker(pub PlayerInventorySlotType);

View File

@ -28,8 +28,7 @@ pub fn update_player_inventory_system(
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::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()); player_inventory.pickup_item(event.item.as_ref(), event.item.get_item_slot());
// TODO: Equip inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(event.item.clone()), slot_type: event.item.get_item_slot() })
} }
} }
} }

View File

@ -0,0 +1,22 @@
use bevy::prelude::*;
use crate::comps::core::markers::inventory_screen::InventorySlotUiMarker;
pub fn update_interactable_slot(
//mut commands: Commands,
mut query: Query<(Entity, &Interaction, &mut Style), (Changed<Interaction>, With<InventorySlotUiMarker>)>
) {
for (_, interaction, mut style) in query.iter_mut() {
match *interaction {
Interaction::Pressed => {
println!("Clicked an Inventory Slot");
}
Interaction::Hovered => {
style.border = UiRect::all(Val::Px(1.5));
}
Interaction::None => {
style.border = UiRect::all(Val::Px(0.5));
}
}
}
}

View File

@ -1,7 +1,7 @@
use bevy::{prelude::*, ui::FocusPolicy}; use bevy::{prelude::*, ui::FocusPolicy};
use crate::{ use crate::{
comps::core::markers::inventory_screen::InventoryScreenUiMarker, comps::core::{markers::inventory_screen::{InventoryScreenUiMarker, InventorySlotUiMarker}, inventory::slot::PlayerInventorySlotType, events::inventory_changed::PlayerInventoryChangedEvent},
ui::game::game_ui_state::{GameUiState, GameUiWindow}, ui::game::game_ui_state::{GameUiState, GameUiWindow},
}; };
@ -23,7 +23,7 @@ pub fn setup_inventory_screen(mut commands: Commands) {
..Default::default() ..Default::default()
}, },
visibility: Visibility::Hidden, visibility: Visibility::Hidden,
background_color: BackgroundColor(Color::rgba(0.0, 0.0, 0.0, 0.9)), background_color: BackgroundColor(Color::rgba(0.0, 0.0, 0.0, 0.8)),
focus_policy: FocusPolicy::Block, focus_policy: FocusPolicy::Block,
..Default::default() ..Default::default()
}, },
@ -36,28 +36,30 @@ pub fn setup_inventory_screen(mut commands: Commands) {
.spawn(NodeBundle { .spawn(NodeBundle {
style: Style { style: Style {
display: Display::Flex, display: Display::Flex,
width: Val::Percent(50.0), width: Val::Percent(40.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
justify_content: JustifyContent::Center, justify_content: JustifyContent::SpaceEvenly,
padding: UiRect::all(Val::Percent(5.0)), padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
border: UiRect::all(Val::Px(0.5)),
..Default::default() ..Default::default()
}, },
background_color: BackgroundColor(Color::RED), background_color: BackgroundColor(Color::Rgba { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.86 }),
border_color: BorderColor(Color::WHITE),
..Default::default() ..Default::default()
}) })
.set_parent(background_id) .set_parent(background_id)
.id(); .id();
// Right panel // Right panel
let right_panel_id = commands let _right_panel_id = commands
.spawn(NodeBundle { .spawn(NodeBundle {
style: Style { style: Style {
display: Display::Flex, display: Display::Flex,
width: Val::Percent(50.0), width: Val::Percent(50.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
justify_content: JustifyContent::Center, justify_content: JustifyContent::SpaceEvenly,
padding: UiRect::all(Val::Percent(5.0)), padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
..Default::default() ..Default::default()
@ -66,6 +68,130 @@ pub fn setup_inventory_screen(mut commands: Commands) {
}) })
.set_parent(background_id) .set_parent(background_id)
.id(); .id();
// Inventory Equipment title
let _ = commands.spawn(
TextBundle {
text: Text::from_section("Equipment", TextStyle { font_size: 32.0, color: Color::WHITE, ..Default::default() }),
..Default::default()
}.with_text_alignment(TextAlignment::Center)
).set_parent(left_panel_id);
// First slot (Backpack and knife)
let body_slots_container = commands
.spawn(NodeBundle {
style: Style {
display: Display::Flex,
width: Val::Percent(90.0),
height: Val::Percent(30.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::SpaceBetween,
//padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Row,
..Default::default()
},
..Default::default()
}).set_parent(left_panel_id).id();
// Body Armor container
let body_armor_slot_container = commands
.spawn((NodeBundle {
style: Style {
display: Display::Flex,
width: Val::Percent(47.0),
height: Val::Percent(100.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column,
border: UiRect::all(Val::Px(0.5)),
..Default::default()
},
border_color: BorderColor(Color::WHITE),
background_color: BackgroundColor(Color::Rgba { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.96 }),
..Default::default()
}, Interaction::default(), InventorySlotUiMarker(PlayerInventorySlotType::BodyArmor)
)).set_parent(body_slots_container).id();
// Backpack container
let backpack_slot_container = commands
.spawn((NodeBundle {
style: Style {
display: Display::Flex,
width: Val::Percent(47.0),
height: Val::Percent(100.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column,
border: UiRect::all(Val::Px(0.5)),
..Default::default()
},
border_color: BorderColor(Color::WHITE),
background_color: BackgroundColor(Color::Rgba { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.96 }),
..Default::default()
}, Interaction::default(), InventorySlotUiMarker(PlayerInventorySlotType::Backpack)
)).set_parent(body_slots_container).id();
// Body Armor Text
commands.spawn(TextBundle {
text: Text::from_section("Body Armor", TextStyle { font_size: 28.0, color: Color::WHITE, ..Default::default() }),
..Default::default()
}.with_text_alignment(TextAlignment::Center))
.set_parent(body_armor_slot_container);
// Backpack Text
commands.spawn(TextBundle {
text: Text::from_section("Backpack", TextStyle { font_size: 28.0, color: Color::WHITE, ..Default::default() }),
..Default::default()
}.with_text_alignment(TextAlignment::Center))
.set_parent(backpack_slot_container);
// Primary Slot
let primary_slot = commands
.spawn((NodeBundle {
style: Style {
display: Display::Flex,
width: Val::Percent(90.0),
height: Val::Percent(20.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column,
border: UiRect::all(Val::Px(0.5)),
..Default::default()
},
border_color: BorderColor(Color::WHITE),
background_color: BackgroundColor(Color::Rgba { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.96 }),
..Default::default()
}, Interaction::default(), InventorySlotUiMarker(PlayerInventorySlotType::Primary)
)).set_parent(left_panel_id).id();
// Secondary Slot
let secondary_slot = commands
.spawn((NodeBundle {
style: Style {
display: Display::Flex,
width: Val::Percent(90.0),
height: Val::Percent(20.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
padding: UiRect::all(Val::Percent(5.0)),
flex_direction: FlexDirection::Column,
border: UiRect::all(Val::Px(0.5)),
..Default::default()
},
border_color: BorderColor(Color::WHITE),
background_color: BackgroundColor(Color::Rgba { red: 0.0, green: 0.0, blue: 0.0, alpha: 0.96 }),
..Default::default()
}, Interaction::default(), InventorySlotUiMarker(PlayerInventorySlotType::Secondary)
)).set_parent(left_panel_id).id();
// Primary Slot Text
commands.spawn(TextBundle {
text: Text::from_section("Primary", TextStyle { font_size: 28.0, color: Color::WHITE, ..Default::default() }),
..Default::default()
}.with_text_alignment(TextAlignment::Center))
.set_parent(primary_slot);
// Secondary Slot Text
commands.spawn(TextBundle {
text: Text::from_section("Secondary", TextStyle { font_size: 28.0, color: Color::WHITE, ..Default::default() }),
..Default::default()
}.with_text_alignment(TextAlignment::Center))
.set_parent(secondary_slot);
} }
@ -73,6 +199,9 @@ pub fn update_inventory_screen(
//mut commands: Commands, //mut commands: Commands,
game_ui_state: Res<GameUiState>, game_ui_state: Res<GameUiState>,
mut inventory_screen_query: Query<&mut Visibility, With<InventoryScreenUiMarker>>, mut inventory_screen_query: Query<&mut Visibility, With<InventoryScreenUiMarker>>,
inventory_slot_query: Query<(&InventorySlotUiMarker, &Children)>,
mut inventory_slot_text_query: Query<(&mut Text, Entity)>,
mut inventory_changed_events: EventReader<PlayerInventoryChangedEvent>,
) { ) {
for mut visibility in inventory_screen_query.iter_mut() { for mut visibility in inventory_screen_query.iter_mut() {
if game_ui_state.is_showing_window(GameUiWindow::InventoryMenu) { if game_ui_state.is_showing_window(GameUiWindow::InventoryMenu) {
@ -81,4 +210,23 @@ pub fn update_inventory_screen(
*visibility = Visibility::Hidden; *visibility = Visibility::Hidden;
} }
} }
for event in inventory_changed_events.read() {
for (inventory_slot_ui_marker, children) in inventory_slot_query.iter() {
for (mut text, text_entity) in inventory_slot_text_query.iter_mut() {
for child in children {
if child == &text_entity && event.slot_type == inventory_slot_ui_marker.0 {
// Mutate text
if let Some(section) = text.sections.first_mut() {
section.value = match &event.item {
Some(item) => item.inventory_title(),
None => inventory_slot_ui_marker.0.to_slot_title(),
}
}
}
}
}
}
}
} }

View File

@ -1,2 +1,3 @@
pub mod menu; pub mod menu;
pub mod plugin; pub mod plugin;
pub mod interactables;

View File

@ -1,12 +1,12 @@
use bevy::prelude::*; use bevy::prelude::*;
use super::menu::{setup_inventory_screen, update_inventory_screen}; use super::{menu::{setup_inventory_screen, update_inventory_screen}, interactables::update_interactable_slot};
pub struct InventoryMenuPlugin; pub struct InventoryMenuPlugin;
impl Plugin for InventoryMenuPlugin { impl Plugin for InventoryMenuPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Startup, setup_inventory_screen); app.add_systems(Startup, setup_inventory_screen);
app.add_systems(Update, update_inventory_screen); app.add_systems(Update, (update_inventory_screen, update_interactable_slot));
} }
} }