use bevy::prelude::*; use crate::{ world::{TILE_SIZE, TilePos, WorldMap}, worldgen::WorldGenerated, }; pub struct ItemsPlugin; impl Plugin for ItemsPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, create_item_assets) .add_systems(Update, clear_items.run_if(on_message::)); } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum ItemKind { Wood, } impl ItemKind { pub const ALL: [ItemKind; 1] = [ItemKind::Wood]; fn color(self) -> Color { match self { ItemKind::Wood => Color::srgb_u8(150, 104, 62), } } } #[derive(Component, Debug, Clone, Copy, PartialEq)] #[require(Transform)] pub struct Item { pub kind: ItemKind, pub count: u32, } #[derive(Resource, Default)] pub struct ItemAssets { mesh: Handle, materials: Vec<(ItemKind, Handle)>, } impl ItemAssets { fn material(&self, kind: ItemKind) -> Handle { self.materials .iter() .find(|(k, _)| *k == kind) .map(|(_, m)| m.clone()) .unwrap_or_default() } } fn create_item_assets( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, ) { commands.insert_resource(ItemAssets { mesh: meshes.add(Rectangle::new(TILE_SIZE * 0.7, TILE_SIZE * 0.4)), materials: ItemKind::ALL .iter() .map(|&kind| (kind, materials.add(kind.color()))) .collect(), }); } fn clear_items(mut commands: Commands, items: Query>) { for entity in &items { commands.entity(entity).despawn(); } } pub fn drop_items( commands: &mut Commands, items: &mut Query<(&mut Item, &TilePos)>, assets: &ItemAssets, tile: UVec2, kind: ItemKind, count: u32, ) { if let Some((mut item, _)) = items .iter_mut() .find(|(item, pos)| pos.0 == tile && item.kind == kind) { item.count += count; return; } commands.spawn(( Name::new(format!("{kind:?}")), Item { kind, count }, TilePos(tile), Mesh2d(assets.mesh.clone()), MeshMaterial2d(assets.material(kind)), Transform::from_translation(WorldMap::tile_center(tile).extend(0.7)), )); } pub fn stock<'a>(items: impl Iterator, kind: ItemKind) -> u32 { items.filter(|i| i.kind == kind).map(|i| i.count).sum() } #[cfg(test)] mod tests { use super::*; fn drop_system(mut commands: Commands, mut items: Query<(&mut Item, &TilePos)>) { let assets = ItemAssets::default(); drop_items( &mut commands, &mut items, &assets, UVec2::ONE, ItemKind::Wood, 5, ); } #[test] fn dropping_on_a_tile_with_the_same_item_stacks() { let mut app = App::new(); app.add_systems(Update, drop_system); app.update(); app.update(); let items: Vec = app .world_mut() .query::<&Item>() .iter(app.world()) .copied() .collect(); assert_eq!( items, vec![Item { kind: ItemKind::Wood, count: 10 }] ); } #[test] fn stock_sums_counts_of_one_kind() { let items = [ Item { kind: ItemKind::Wood, count: 3, }, Item { kind: ItemKind::Wood, count: 4, }, ]; assert_eq!(stock(items.iter(), ItemKind::Wood), 7); } }