Inventory UI & system combined. Dropping works, pickup works, work on UI
This commit is contained in:
parent
8c30ba6d9f
commit
6c243e5f4d
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
@ -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() })
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
|
pub mod interactables;
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue