generated from 2ndbeam/bevy-template
feat: Implemented basic item drag-and-drop
- Added bundle names - Added system to update bundle names with entity name
This commit is contained in:
parent
0add3e4c20
commit
a462c64786
4 changed files with 56 additions and 18 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use std::f32::consts::FRAC_PI_2;
|
use std::f32::consts::FRAC_PI_2;
|
||||||
|
|
||||||
use bevy::{ecs::component::{ComponentId, ComponentIdFor}, prelude::*};
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::{inventory::{ActiveInventory, Inventory, item::Item}, ui::{UiRoot, WindowSize}};
|
use crate::{inventory::{ActiveInventory, Inventory, item::Item}, ui::{UiRoot, WindowSize}};
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ const TEMP_ITEM_PATH: &'static str = "sprites/items/choco_bar.png";
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[require(Node)]
|
#[require(Node)]
|
||||||
pub struct UiInventory;
|
pub struct UiInventory(Entity);
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[require(Node, ImageNode)]
|
#[require(Node, ImageNode)]
|
||||||
|
|
@ -20,25 +20,48 @@ pub struct UiInventorySlot(UVec2);
|
||||||
pub struct UiItem(Entity);
|
pub struct UiItem(Entity);
|
||||||
|
|
||||||
fn on_item_drag_drop(
|
fn on_item_drag_drop(
|
||||||
event: On<Pointer<DragDrop>>,
|
mut event: On<Pointer<DragDrop>>,
|
||||||
ui_item_query: Query<&UiItem>,
|
mut commands: Commands,
|
||||||
slot_query: Query<(&UiInventorySlot, Option<&Children>)>,
|
ui_item_query: Query<(Entity, &UiItem)>,
|
||||||
|
ui_inventory_query: Query<&UiInventory>,
|
||||||
|
mut item_query: Query<&mut Item>,
|
||||||
|
slot_query: Query<(&ChildOf, &UiInventorySlot, Option<&Children>)>,
|
||||||
|
inventory_query: Query<(&Inventory, Option<&Children>)>,
|
||||||
) {
|
) {
|
||||||
info!("dragdrop {} {}", event.dropped, event.event_target());
|
let Ok((ui_item_entity, UiItem(item_entity))) = ui_item_query.get(event.dropped) else {
|
||||||
let Ok(ui_item) = ui_item_query.get(event.dropped) else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Ok((slot, _)) = slot_query.get(event.event_target()) else {
|
let Ok((slot_parent, UiInventorySlot(new_position), slot_children)) = slot_query.get(event.event_target()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if slot_children.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Ok(UiInventory(inventory_id)) = ui_inventory_query.get(slot_parent.0) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok((inventory, inventory_children)) = inventory_query.get(*inventory_id) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Item {:?} dropped on {:?}", ui_item.0, slot.0);
|
let items = match inventory_children {
|
||||||
|
Some(children) => &children[..],
|
||||||
|
None => &[],
|
||||||
|
};
|
||||||
|
|
||||||
|
if inventory.can_move(item_query.as_readonly(), items, *item_entity, *new_position) {
|
||||||
|
let mut item = item_query.get_mut(*item_entity).unwrap();
|
||||||
|
item.position = Some(*new_position);
|
||||||
|
commands.entity(ui_item_entity).insert(ChildOf(event.event_target()));
|
||||||
|
}
|
||||||
|
|
||||||
|
event.propagate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_inventory_bundle(
|
fn ui_inventory_bundle(
|
||||||
inventory: &Inventory,
|
inventory: &Inventory,
|
||||||
|
inventory_entity: Entity,
|
||||||
window_size: &Res<WindowSize>,
|
window_size: &Res<WindowSize>,
|
||||||
_slot_id: ComponentId,
|
|
||||||
) -> impl Bundle {
|
) -> impl Bundle {
|
||||||
let window_ratio = window_size.aspect_ratio();
|
let window_ratio = window_size.aspect_ratio();
|
||||||
let (width, height) = {
|
let (width, height) = {
|
||||||
|
|
@ -49,7 +72,7 @@ fn ui_inventory_bundle(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
UiInventory,
|
UiInventory(inventory_entity),
|
||||||
Node {
|
Node {
|
||||||
align_self: AlignSelf::Center,
|
align_self: AlignSelf::Center,
|
||||||
align_content: AlignContent::Center,
|
align_content: AlignContent::Center,
|
||||||
|
|
@ -63,8 +86,8 @@ fn ui_inventory_bundle(
|
||||||
},
|
},
|
||||||
Pickable::IGNORE,
|
Pickable::IGNORE,
|
||||||
GlobalZIndex::default(),
|
GlobalZIndex::default(),
|
||||||
Observer::new(on_item_drag_drop)
|
Observer::new(on_item_drag_drop),
|
||||||
// .with_component(slot_id),
|
Name::new(format!("UiInventory ({}x{})", inventory.size.x, inventory.size.y)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +111,7 @@ fn inventory_slot_bundle(x: u32, y: u32, image: Handle<Image>) -> impl Bundle {
|
||||||
should_block_lower: true,
|
should_block_lower: true,
|
||||||
is_hoverable: true,
|
is_hoverable: true,
|
||||||
},
|
},
|
||||||
|
Name::new(format!("UiInventorySlot({x},{y})")),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,16 +153,19 @@ fn ui_item_bundle(item: &Item, item_entity: Entity, image: Handle<Image>) -> imp
|
||||||
should_block_lower: false,
|
should_block_lower: false,
|
||||||
is_hoverable: true,
|
is_hoverable: true,
|
||||||
},
|
},
|
||||||
|
Name::new(format!("UiItem ({},{})",
|
||||||
|
item.position.unwrap_or_default().x,
|
||||||
|
item.position.unwrap_or_default().y,
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_ui_inventory(
|
pub fn setup_ui_inventory(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
inventory_query: Query<(&Inventory, Option<&Children>), With<ActiveInventory>>,
|
inventory_query: Query<(Entity, &Inventory, Option<&Children>), With<ActiveInventory>>,
|
||||||
item_query: Query<&Item>,
|
item_query: Query<&Item>,
|
||||||
root_query: Query<Entity, With<UiRoot>>,
|
root_query: Query<Entity, With<UiRoot>>,
|
||||||
slot_id: ComponentIdFor<UiInventorySlot>,
|
|
||||||
window_size: Res<WindowSize>,
|
window_size: Res<WindowSize>,
|
||||||
) {
|
) {
|
||||||
let Ok(root) = root_query.single() else {
|
let Ok(root) = root_query.single() else {
|
||||||
|
|
@ -147,7 +174,7 @@ pub fn setup_ui_inventory(
|
||||||
};
|
};
|
||||||
let ui_slot_image: Handle<Image> = asset_server.load(UI_SLOT_ASSET_PATH);
|
let ui_slot_image: Handle<Image> = asset_server.load(UI_SLOT_ASSET_PATH);
|
||||||
let temp_item_image: Handle<Image> = asset_server.load(TEMP_ITEM_PATH);
|
let temp_item_image: Handle<Image> = asset_server.load(TEMP_ITEM_PATH);
|
||||||
for (inventory, children) in inventory_query {
|
for (inventory_entity, inventory, children) in inventory_query {
|
||||||
let items = match children {
|
let items = match children {
|
||||||
Some(children) => {
|
Some(children) => {
|
||||||
children.iter().filter_map(|item_entity| {
|
children.iter().filter_map(|item_entity| {
|
||||||
|
|
@ -162,7 +189,7 @@ pub fn setup_ui_inventory(
|
||||||
}
|
}
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
};
|
};
|
||||||
let inventory_entity = commands.spawn(ui_inventory_bundle(inventory, &window_size, slot_id.get()))
|
let inventory_entity = commands.spawn(ui_inventory_bundle(inventory, inventory_entity, &window_size))
|
||||||
.with_children(|commands| {
|
.with_children(|commands| {
|
||||||
for x in 0..inventory.size.x { for y in 0..inventory.size.y {
|
for x in 0..inventory.size.x { for y in 0..inventory.size.y {
|
||||||
let mut slot_commands = commands.spawn(inventory_slot_bundle(x, y, ui_slot_image.clone()));
|
let mut slot_commands = commands.spawn(inventory_slot_bundle(x, y, ui_slot_image.clone()));
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,12 @@ impl InputAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_entity_name(names: Query<(Entity, &mut Name), Added<Name>>) {
|
||||||
|
for (entity, mut name) in names {
|
||||||
|
name.mutate(|name| name.insert_str(0, format!("{entity}: ").as_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn camera_bundle() -> impl Bundle {
|
fn camera_bundle() -> impl Bundle {
|
||||||
(
|
(
|
||||||
Camera2d,
|
Camera2d,
|
||||||
|
|
@ -54,6 +60,7 @@ fn camera_bundle() -> impl Bundle {
|
||||||
scale: 1.,
|
scale: 1.,
|
||||||
..OrthographicProjection::default_2d()
|
..OrthographicProjection::default_2d()
|
||||||
}),
|
}),
|
||||||
|
Name::new("Camera2d"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,6 +78,7 @@ impl Plugin for ExpeditionPlugin {
|
||||||
.add_systems(Update, (
|
.add_systems(Update, (
|
||||||
player::handle_input,
|
player::handle_input,
|
||||||
ui::update_window_size,
|
ui::update_window_size,
|
||||||
|
insert_entity_name,
|
||||||
))
|
))
|
||||||
.add_systems(OnEnter(GameState::Inventory), inventory::ui::setup_ui_inventory)
|
.add_systems(OnEnter(GameState::Inventory), inventory::ui::setup_ui_inventory)
|
||||||
.add_systems(OnExit(GameState::Inventory), inventory::ui::clear_ui_inventory)
|
.add_systems(OnExit(GameState::Inventory), inventory::ui::clear_ui_inventory)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ fn player_bundle(asset_server: &Res<AssetServer>) -> impl Bundle {
|
||||||
Action::default_input_map(),
|
Action::default_input_map(),
|
||||||
Inventory::new(UVec2::new(4, 4)),
|
Inventory::new(UVec2::new(4, 4)),
|
||||||
ActiveInventory,
|
ActiveInventory,
|
||||||
|
Name::new("Player"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,6 +34,7 @@ pub fn try_insert_item(
|
||||||
inventory_query: Query<(Entity, &Inventory, Option<&Children>)>,
|
inventory_query: Query<(Entity, &Inventory, Option<&Children>)>,
|
||||||
) {
|
) {
|
||||||
let mut item = Item::new(UVec2::new(1, 1));
|
let mut item = Item::new(UVec2::new(1, 1));
|
||||||
|
let name = Name::new(format!("Item {}x{}", item.size.x, item.size.y));
|
||||||
for (entity, inventory, children) in inventory_query {
|
for (entity, inventory, children) in inventory_query {
|
||||||
let children = match children {
|
let children = match children {
|
||||||
Some(children) => &children[..],
|
Some(children) => &children[..],
|
||||||
|
|
@ -45,7 +47,7 @@ pub fn try_insert_item(
|
||||||
}
|
}
|
||||||
item.position = Some(position);
|
item.position = Some(position);
|
||||||
info!("Spawning item {item:?}");
|
info!("Spawning item {item:?}");
|
||||||
commands.entity(entity).with_child(item);
|
commands.entity(entity).with_child((item, name));
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
warn!("Inventory does not have space for {}", item.size);
|
warn!("Inventory does not have space for {}", item.size);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ impl UiRoot {
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Pickable::IGNORE,
|
Pickable::IGNORE,
|
||||||
|
Name::new("UiRoot"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue