ui: Beginning of UI-related stuff

- UiRoot component
- WindowSize resource and update_window_size system
- UiInventory and UiInventorySlot components
- UiInventory now shows player inventory slots
This commit is contained in:
Alexey 2026-03-09 13:59:51 +03:00
commit ab993be476
6 changed files with 183 additions and 10 deletions

93
src/inventory/ui.rs Normal file
View file

@ -0,0 +1,93 @@
use bevy::prelude::*;
use crate::{inventory::{ActiveInventory, Inventory}, ui::{UiRoot, WindowSize}};
const UI_SLOT_ASSET_PATH: &'static str = "sprites/ui/inventory_slot.png";
#[derive(Component)]
#[require(Node)]
pub struct UiInventory;
#[derive(Component)]
#[require(Node, ImageNode)]
pub struct UiInventorySlot(UVec2);
fn ui_inventory_bundle(inventory: &Inventory, window_size: &Res<WindowSize>) -> impl Bundle {
let window_ratio = window_size.aspect_ratio();
let (width, height) = {
if window_ratio >= 1. {
(auto(), percent(100))
} else {
(percent(100), auto())
}
};
(
UiInventory,
Node {
align_self: AlignSelf::Center,
align_content: AlignContent::Center,
display: Display::Grid,
width,
height,
aspect_ratio: Some(inventory.size.x as f32 / inventory.size.y as f32),
grid_auto_columns: vec![GridTrack::percent(100. / inventory.size.x as f32)],
grid_auto_rows: vec![GridTrack::percent(100. / inventory.size.y as f32)],
..default()
},
)
}
fn inventory_slot_bundle(x: u32, y: u32, width: u32, height: u32, image: Handle<Image>) -> impl Bundle {
(
UiInventorySlot(UVec2::new(x, y)),
ImageNode {
image,
image_mode: NodeImageMode::Stretch,
..default()
},
Node {
width: percent(100.),
height: percent(100.),
grid_column: GridPlacement::start(x as i16 + 1),
grid_row: GridPlacement::start(y as i16 + 1),
..default()
},
)
}
pub fn setup_ui_inventory(
mut commands: Commands,
asset_server: Res<AssetServer>,
inventory_query: Query<(&Inventory, Option<&Children>), With<ActiveInventory>>,
root_query: Query<Entity, With<UiRoot>>,
window_size: Res<WindowSize>,
) {
let Ok(root) = root_query.single() else {
error!("Query contains more than one UiRoot");
return;
};
let ui_slot_image: Handle<Image> = asset_server.load(UI_SLOT_ASSET_PATH);
for (inventory, _children) in inventory_query {
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()));
}
}
}).id();
commands.entity(root).add_child(inventory_entity);
// for simplicity we'll show only first inventory
break;
}
}
pub fn clear_ui_inventory(
mut commands: Commands,
inventory_query: Query<Entity, With<UiInventory>>,
) {
for entity in inventory_query {
commands.entity(entity).despawn();
}
}