feat: Implemented basic item drag-and-drop

- Added bundle names
- Added system to update bundle names with entity name
This commit is contained in:
Alexey 2026-03-11 22:40:17 +03:00
commit a462c64786
4 changed files with 56 additions and 18 deletions

View file

@ -1,6 +1,6 @@
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}};
@ -9,7 +9,7 @@ const TEMP_ITEM_PATH: &'static str = "sprites/items/choco_bar.png";
#[derive(Component, Reflect)]
#[require(Node)]
pub struct UiInventory;
pub struct UiInventory(Entity);
#[derive(Component, Reflect)]
#[require(Node, ImageNode)]
@ -20,25 +20,48 @@ pub struct UiInventorySlot(UVec2);
pub struct UiItem(Entity);
fn on_item_drag_drop(
event: On<Pointer<DragDrop>>,
ui_item_query: Query<&UiItem>,
slot_query: Query<(&UiInventorySlot, Option<&Children>)>,
mut event: On<Pointer<DragDrop>>,
mut commands: Commands,
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) = ui_item_query.get(event.dropped) else {
let Ok((ui_item_entity, UiItem(item_entity))) = ui_item_query.get(event.dropped) else {
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;
};
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(
inventory: &Inventory,
inventory_entity: Entity,
window_size: &Res<WindowSize>,
_slot_id: ComponentId,
) -> impl Bundle {
let window_ratio = window_size.aspect_ratio();
let (width, height) = {
@ -49,7 +72,7 @@ fn ui_inventory_bundle(
}
};
(
UiInventory,
UiInventory(inventory_entity),
Node {
align_self: AlignSelf::Center,
align_content: AlignContent::Center,
@ -63,8 +86,8 @@ fn ui_inventory_bundle(
},
Pickable::IGNORE,
GlobalZIndex::default(),
Observer::new(on_item_drag_drop)
// .with_component(slot_id),
Observer::new(on_item_drag_drop),
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,
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,
is_hoverable: true,
},
Name::new(format!("UiItem ({},{})",
item.position.unwrap_or_default().x,
item.position.unwrap_or_default().y,
)),
)
}
pub fn setup_ui_inventory(
mut commands: Commands,
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>,
root_query: Query<Entity, With<UiRoot>>,
slot_id: ComponentIdFor<UiInventorySlot>,
window_size: Res<WindowSize>,
) {
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 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 {
Some(children) => {
children.iter().filter_map(|item_entity| {
@ -162,7 +189,7 @@ pub fn setup_ui_inventory(
}
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| {
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()));