feat!: Item processing

- Added try_insert_item system
- Added rotated field on Item
- Implemented UI item drawing with scale and rotation

BREAKING CHANGE: Item.swap_size renamed to Item.rotate
    Item.clone_swapped renamed to Item.clone_rotated
This commit is contained in:
Alexey 2026-03-11 14:55:27 +03:00
commit c46fa75e54
3 changed files with 114 additions and 15 deletions

View file

@ -2,19 +2,20 @@ use std::mem::swap;
use bevy::prelude::*;
#[derive(Component, Clone)]
#[derive(Component, Clone, Debug)]
pub struct Item {
pub size: UVec2,
pub position: Option<UVec2>,
pub rotated: bool,
}
impl Item {
pub fn new(size: UVec2) -> Self {
Self { size, position: None }
Self { size, position: None, rotated: false }
}
pub fn new_positioned(size: UVec2, position: UVec2) -> Self {
Self { size, position: Some(position) }
Self { size, position: Some(position), rotated: false }
}
pub fn rect(&self) -> Option<URect> {
@ -36,14 +37,15 @@ impl Item {
}
/// Swap size.x with size.y
pub fn swap_size(&mut self) {
pub fn rotate(&mut self) {
swap(&mut self.size.x, &mut self.size.y);
self.rotated = !self.rotated;
}
/// Get clone of item with swapped size
pub fn clone_swapped(&self) -> Self {
pub fn clone_rotated(&self) -> Self {
let mut new = self.clone();
new.swap_size();
new.rotate();
new
}
}

View file

@ -1,8 +1,11 @@
use std::f32::consts::FRAC_PI_2;
use bevy::prelude::*;
use crate::{inventory::{ActiveInventory, Inventory}, ui::{UiRoot, WindowSize}};
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)]
#[require(Node)]
@ -12,6 +15,10 @@ pub struct UiInventory;
#[require(Node, ImageNode)]
pub struct UiInventorySlot(UVec2);
#[derive(Component)]
#[require(Node, ImageNode)]
pub struct UiItem(Entity);
fn ui_inventory_bundle(inventory: &Inventory, window_size: &Res<WindowSize>) -> impl Bundle {
let window_ratio = window_size.aspect_ratio();
let (width, height) = {
@ -37,7 +44,7 @@ fn ui_inventory_bundle(inventory: &Inventory, window_size: &Res<WindowSize>) ->
)
}
fn inventory_slot_bundle(x: u32, y: u32, width: u32, height: u32, image: Handle<Image>) -> impl Bundle {
fn inventory_slot_bundle(x: u32, y: u32, image: Handle<Image>) -> impl Bundle {
(
UiInventorySlot(UVec2::new(x, y)),
ImageNode {
@ -50,15 +57,54 @@ fn inventory_slot_bundle(x: u32, y: u32, width: u32, height: u32, image: Handle<
height: percent(100.),
grid_column: GridPlacement::start(x as i16 + 1),
grid_row: GridPlacement::start(y as i16 + 1),
align_items: AlignItems::Start,
..default()
},
)
}
fn ui_item_bundle(item: &Item, item_entity: Entity, image: Handle<Image>) -> impl Bundle {
let (left, top, min_width, min_height, ui_transform) = match item.rotated {
true => (
percent(100.),
percent(-100.),
percent(100. * item.size.y as f32),
percent(100. * item.size.x as f32),
UiTransform::from_rotation(Rot2::radians(-FRAC_PI_2)),
),
false => (
auto(),
auto(),
percent(100. * item.size.x as f32),
percent(100. * item.size.y as f32),
UiTransform::default(),
),
};
(
UiItem(item_entity),
ImageNode {
image,
image_mode: NodeImageMode::Stretch,
..default()
},
Node {
left,
top,
min_width,
min_height,
..default()
},
BackgroundColor(Color::hsla(0., 0., 0., 0.5)),
ui_transform,
GlobalZIndex(1),
)
}
pub fn setup_ui_inventory(
mut commands: Commands,
asset_server: Res<AssetServer>,
inventory_query: Query<(&Inventory, Option<&Children>), With<ActiveInventory>>,
item_query: Query<&Item>,
root_query: Query<Entity, With<UiRoot>>,
window_size: Res<WindowSize>,
) {
@ -67,14 +113,31 @@ pub fn setup_ui_inventory(
return;
};
let ui_slot_image: Handle<Image> = asset_server.load(UI_SLOT_ASSET_PATH);
for (inventory, _children) in inventory_query {
let temp_item_image: Handle<Image> = asset_server.load(TEMP_ITEM_PATH);
for (inventory, children) in inventory_query {
let items = match children {
Some(children) => {
children.iter().filter_map(|item_entity| {
match item_query.get(item_entity) {
Ok(item) => Some((item, item_entity)),
Err(err) => {
warn!("Error querying item {item_entity}: {err}");
None
},
}
}).collect::<Vec<(&Item, Entity)>>()
}
None => Vec::new(),
};
let inventory_entity = commands.spawn(ui_inventory_bundle(inventory, &window_size))
.with_children(|commands| {
for x in 0..inventory.size.x {
for y in 0..inventory.size.y {
commands.spawn(inventory_slot_bundle(x, y, inventory.size.x, inventory.size.y, ui_slot_image.clone()));
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()));
if let Some((item, entity)) = items.iter()
.find(|(i, _)| i.position.unwrap_or_default() == UVec2::new(x, y)) {
slot_commands.with_child(ui_item_bundle(item, *entity, temp_item_image.clone()));
}
}
} }
}).id();
commands.entity(root).add_child(inventory_entity);