feat: unfinished item drag and drop

This commit is contained in:
Alexey 2026-03-11 17:29:27 +03:00
commit 0add3e4c20
9 changed files with 191 additions and 15 deletions

View file

@ -2,7 +2,7 @@ use std::mem::swap;
use bevy::prelude::*;
#[derive(Component, Clone, Debug)]
#[derive(Component, Clone, Debug, Reflect)]
pub struct Item {
pub size: UVec2,
pub position: Option<UVec2>,

View file

@ -3,13 +3,13 @@ use bevy::prelude::*;
pub mod item;
pub mod ui;
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct Inventory {
pub size: UVec2,
}
/// Marker that this inventory will show up when UI is built
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct ActiveInventory;
impl Inventory {

View file

@ -1,25 +1,45 @@
use std::f32::consts::FRAC_PI_2;
use bevy::prelude::*;
use bevy::{ecs::component::{ComponentId, ComponentIdFor}, prelude::*};
use crate::{inventory::{ActiveInventory, Inventory, item::Item}, ui::{UiRoot, WindowSize}};
const UI_SLOT_ASSET_PATH: &'static str = "sprites/ui/inventory_slot.png";
const TEMP_ITEM_PATH: &'static str = "sprites/items/choco_bar.png";
#[derive(Component)]
#[derive(Component, Reflect)]
#[require(Node)]
pub struct UiInventory;
#[derive(Component)]
#[derive(Component, Reflect)]
#[require(Node, ImageNode)]
pub struct UiInventorySlot(UVec2);
#[derive(Component)]
#[derive(Component, Reflect)]
#[require(Node, ImageNode)]
pub struct UiItem(Entity);
fn ui_inventory_bundle(inventory: &Inventory, window_size: &Res<WindowSize>) -> impl Bundle {
fn on_item_drag_drop(
event: On<Pointer<DragDrop>>,
ui_item_query: Query<&UiItem>,
slot_query: Query<(&UiInventorySlot, Option<&Children>)>,
) {
info!("dragdrop {} {}", event.dropped, event.event_target());
let Ok(ui_item) = ui_item_query.get(event.dropped) else {
return;
};
let Ok((slot, _)) = slot_query.get(event.event_target()) else {
return;
};
info!("Item {:?} dropped on {:?}", ui_item.0, slot.0);
}
fn ui_inventory_bundle(
inventory: &Inventory,
window_size: &Res<WindowSize>,
_slot_id: ComponentId,
) -> impl Bundle {
let window_ratio = window_size.aspect_ratio();
let (width, height) = {
if window_ratio >= 1. {
@ -41,6 +61,10 @@ fn ui_inventory_bundle(inventory: &Inventory, window_size: &Res<WindowSize>) ->
grid_auto_rows: vec![GridTrack::percent(100. / inventory.size.y as f32)],
..default()
},
Pickable::IGNORE,
GlobalZIndex::default(),
Observer::new(on_item_drag_drop)
// .with_component(slot_id),
)
}
@ -60,6 +84,10 @@ fn inventory_slot_bundle(x: u32, y: u32, image: Handle<Image>) -> impl Bundle {
align_items: AlignItems::Start,
..default()
},
Pickable {
should_block_lower: true,
is_hoverable: true,
},
)
}
@ -97,6 +125,10 @@ fn ui_item_bundle(item: &Item, item_entity: Entity, image: Handle<Image>) -> imp
BackgroundColor(Color::hsla(0., 0., 0., 0.5)),
ui_transform,
GlobalZIndex(1),
Pickable {
should_block_lower: false,
is_hoverable: true,
},
)
}
@ -106,6 +138,7 @@ pub fn setup_ui_inventory(
inventory_query: Query<(&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 {
@ -129,7 +162,7 @@ pub fn setup_ui_inventory(
}
None => Vec::new(),
};
let inventory_entity = commands.spawn(ui_inventory_bundle(inventory, &window_size))
let inventory_entity = commands.spawn(ui_inventory_bundle(inventory, &window_size, slot_id.get()))
.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()));
@ -139,7 +172,8 @@ pub fn setup_ui_inventory(
}
} }
}).id();
commands.entity(root).add_child(inventory_entity);
commands.entity(root)
.add_child(inventory_entity);
// for simplicity we'll show only first inventory
break;

View file

@ -73,6 +73,12 @@ impl Plugin for ExpeditionPlugin {
ui::update_window_size,
))
.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)
.register_type::<inventory::Inventory>()
.register_type::<inventory::ActiveInventory>()
.register_type::<inventory::item::Item>()
.register_type::<inventory::ui::UiItem>()
.register_type::<inventory::ui::UiInventorySlot>()
.register_type::<inventory::ui::UiInventory>();
}
}

View file

@ -1,4 +1,4 @@
use bevy::prelude::*;
use bevy::{prelude::*, remote::{RemotePlugin, http::RemoteHttpPlugin}};
use expedition_demo::ExpeditionPlugin;
@ -6,5 +6,7 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(ExpeditionPlugin)
.add_plugins(RemotePlugin::default())
.add_plugins(RemoteHttpPlugin::default())
.run();
}

View file

@ -3,7 +3,7 @@ use leafwing_input_manager::prelude::*;
use crate::{GameState, InputAction as Action, inventory::{ActiveInventory, Inventory, item::Item}};
#[derive(Component)]
#[derive(Component, Reflect)]
pub struct Player {
// px/s
speed: f32,

View file

@ -1,6 +1,6 @@
use bevy::{prelude::*, window::WindowResized};
#[derive(Component)]
#[derive(Component, Reflect)]
#[require(Node)]
pub struct UiRoot;
@ -24,6 +24,7 @@ impl UiRoot {
justify_self: JustifySelf::Center,
..default()
},
Pickable::IGNORE,
)
}
}