From a462c64786e11fb581a44ca00289c80a688cbce4 Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Wed, 11 Mar 2026 22:40:17 +0300 Subject: [PATCH] feat: Implemented basic item drag-and-drop - Added bundle names - Added system to update bundle names with entity name --- src/inventory/ui.rs | 61 ++++++++++++++++++++++++++++++++------------- src/lib.rs | 8 ++++++ src/player.rs | 4 ++- src/ui.rs | 1 + 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/inventory/ui.rs b/src/inventory/ui.rs index 2ccbcd9..865b477 100644 --- a/src/inventory/ui.rs +++ b/src/inventory/ui.rs @@ -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>, - ui_item_query: Query<&UiItem>, - slot_query: Query<(&UiInventorySlot, Option<&Children>)>, + mut event: On>, + 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, - _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) -> 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) -> 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, - inventory_query: Query<(&Inventory, Option<&Children>), With>, + inventory_query: Query<(Entity, &Inventory, Option<&Children>), With>, item_query: Query<&Item>, root_query: Query>, - slot_id: ComponentIdFor, window_size: Res, ) { let Ok(root) = root_query.single() else { @@ -147,7 +174,7 @@ pub fn setup_ui_inventory( }; let ui_slot_image: Handle = asset_server.load(UI_SLOT_ASSET_PATH); let temp_item_image: Handle = 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())); diff --git a/src/lib.rs b/src/lib.rs index c45a167..1911306 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,12 @@ impl InputAction { } } +pub fn insert_entity_name(names: Query<(Entity, &mut Name), Added>) { + for (entity, mut name) in names { + name.mutate(|name| name.insert_str(0, format!("{entity}: ").as_str())); + } +} + fn camera_bundle() -> impl Bundle { ( Camera2d, @@ -54,6 +60,7 @@ fn camera_bundle() -> impl Bundle { scale: 1., ..OrthographicProjection::default_2d() }), + Name::new("Camera2d"), ) } @@ -71,6 +78,7 @@ impl Plugin for ExpeditionPlugin { .add_systems(Update, ( player::handle_input, ui::update_window_size, + insert_entity_name, )) .add_systems(OnEnter(GameState::Inventory), inventory::ui::setup_ui_inventory) .add_systems(OnExit(GameState::Inventory), inventory::ui::clear_ui_inventory) diff --git a/src/player.rs b/src/player.rs index 06dfcd0..e295182 100644 --- a/src/player.rs +++ b/src/player.rs @@ -20,6 +20,7 @@ fn player_bundle(asset_server: &Res) -> impl Bundle { Action::default_input_map(), Inventory::new(UVec2::new(4, 4)), ActiveInventory, + Name::new("Player"), ) } @@ -33,6 +34,7 @@ pub fn try_insert_item( inventory_query: Query<(Entity, &Inventory, Option<&Children>)>, ) { 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 { let children = match children { Some(children) => &children[..], @@ -45,7 +47,7 @@ pub fn try_insert_item( } item.position = Some(position); info!("Spawning item {item:?}"); - commands.entity(entity).with_child(item); + commands.entity(entity).with_child((item, name)); }, None => { warn!("Inventory does not have space for {}", item.size); diff --git a/src/ui.rs b/src/ui.rs index 4851272..26add71 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -25,6 +25,7 @@ impl UiRoot { ..default() }, Pickable::IGNORE, + Name::new("UiRoot"), ) } }