diff --git a/src/layout/container.rs b/src/layout/container.rs index 68850af..ac41a5b 100644 --- a/src/layout/container.rs +++ b/src/layout/container.rs @@ -20,7 +20,7 @@ const CRATE_CLOSED_ASSET: &'static str = "sprites/interactive/crate_closed.png"; #[require(Sprite, InteractiveObject, Inventory)] pub struct Container; -fn on_container_interact( +pub fn on_container_interact( event: On, mut commands: Commands, locked_query: Query<(), With>, @@ -42,7 +42,7 @@ pub fn container_bundle( asset_server: &Res, position: Vec2, inventory_size: UVec2, - items: Vec + items: Vec, ) -> impl Bundle { let image = asset_server.load(CRATE_CLOSED_ASSET); ( @@ -50,7 +50,6 @@ pub fn container_bundle( Transform::from_xyz(position.x, position.y - meters(0.5), 0.), Sprite::from_image(image), Inventory::new(inventory_size), - Observer::new(on_container_interact), Children::spawn(( SpawnIter(items.into_iter()), Spawn(( @@ -59,5 +58,6 @@ pub fn container_bundle( Transform::from_xyz(0., meters(0.5), 0.), )), )), + Name::new(format!("Container {}x{}", inventory_size.x, inventory_size.y)), ) } diff --git a/src/layout/door.rs b/src/layout/door.rs index 9d46f7b..1dc5fe2 100644 --- a/src/layout/door.rs +++ b/src/layout/door.rs @@ -19,7 +19,7 @@ impl Default for Door { } } -fn on_door_interact( +pub fn on_door_interact( event: On, mut commands: Commands, locked_query: Query<(), With>, @@ -69,7 +69,6 @@ pub fn door_bundle(asset_server: &Res, position: Vec2, facing_left: Transform::from_xyz(position.x, position.y, 0.), Name::new(format!("Door ({}, {})", position.x, position.y)), door_collider(), - Observer::new(on_door_interact), children![ ( Collider::cuboid(meters(0.5), meters(1.)), diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 3f5a457..36ae455 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -2,6 +2,7 @@ use bevy::prelude::*; pub mod container; pub mod door; +pub mod stairs; pub mod systems; pub mod tilemap; diff --git a/src/layout/stairs.rs b/src/layout/stairs.rs new file mode 100644 index 0000000..104c7fd --- /dev/null +++ b/src/layout/stairs.rs @@ -0,0 +1,98 @@ +use bevy::{ecs::relationship::RelatedSpawner, prelude::*}; +use bevy_rapier2d::prelude::*; + +use crate::{meters, player::Player}; + +use super::*; + +#[derive(Component, Debug, PartialEq, Eq, Default, Clone, Copy, Reflect)] +#[reflect(Component, Debug, PartialEq, Default, Clone)] +#[require(InteractiveObject, Collider, Sensor)] +pub enum StairCollider { + #[default] + Up, + Down, +} + +#[derive(Component, Clone, Copy, Default, Reflect, Debug, PartialEq)] +#[reflect(Component, Clone, Default, Debug, PartialEq)] +#[require(Transform)] +pub struct Stairs { + pub up: Option, + pub down: Option, +} + +pub fn on_stairs_interact( + event: On, + collider_query: Query<(&ChildOf, &StairCollider)>, + stairs_query: Query<&Stairs>, + mut player_query: Query<&mut Transform, With>, +) { + let Ok((parent, collider_type)) = collider_query.get(event.entity) else { + return; + }; + let Ok(stairs) = stairs_query.get(parent.0) else { + error!("StairCollider does not have Stairs parent"); + return; + }; + let Ok(mut player_transform) = player_query.single_mut() else { + error!("Player is not single"); + return; + }; + + let offset = match collider_type { + StairCollider::Up => { + let Some(offset) = stairs.up else { + error!("StairCollider::Up triggered but Stairs.up is None"); + return; + }; + offset + }, + StairCollider::Down => { + let Some(offset) = stairs.down else { + error!("StairCollider::Down triggered but Stairs.down is None"); + return; + }; + offset + }, + }; + + player_transform.translation.x += offset.x; + player_transform.translation.y += offset.y; +} + +pub fn stairs_bundle( + _asset_server: &Res, + position: Vec2, + up_position: Option, + down_position: Option, +) -> impl Bundle { + let (has_up, has_down) = (up_position.is_some(), down_position.is_some()); + ( + Stairs { + up: up_position, + down: down_position, + }, + Transform::from_xyz(position.x, position.y, -1.), + Children::spawn( + SpawnWith(move |parent: &mut RelatedSpawner| { + if has_up { + parent.spawn(( + StairCollider::Up, + Collider::cuboid(meters(1.), meters(1.)), + Transform::from_xyz(meters(-1.), 0., 0.), + )); + } + + if has_down { + parent.spawn(( + StairCollider::Down, + Collider::cuboid(meters(1.), meters(1.)), + Transform::from_xyz(meters(1.), 0., 0.), + )); + } + }) + ), + Name::new(format!("Stairs ({},{})", position.x, position.y)) + ) +} diff --git a/src/layout/systems.rs b/src/layout/systems.rs index 3a0859e..0c36a82 100644 --- a/src/layout/systems.rs +++ b/src/layout/systems.rs @@ -115,7 +115,7 @@ pub fn setup_world( vec2(meters(15.5), meters(-4.5))), // 2F (Collider::cuboid(meters(0.5), meters(1.5)), - vec2(meters(0.5), meters(0.5))), + vec2(meters(0.5), meters(-0.5))), (Collider::cuboid(meters(0.5), meters(1.5)), vec2(meters(15.5), meters(-0.5))), ]; @@ -123,6 +123,25 @@ pub fn setup_world( commands.spawn(door::door_bundle(&asset_server, vec2(meters(1.5), 0.), true)); commands.spawn(door::door_bundle(&asset_server, vec2(meters(3.5), 0.), false)); commands.spawn(door::door_bundle(&asset_server, vec2(meters(5.5), 0.), false)).insert(Locked); - commands.spawn(container::container_bundle(&asset_server, vec2(meters(-2.), 0.), uvec2(8, 8), items)); + commands.spawn(container::container_bundle(&asset_server, vec2(meters(-2.), 0.), uvec2(8, 8), items.clone())); + commands.spawn(container::container_bundle(&asset_server, vec2(meters(2.), meters(4.)), uvec2(10, 8), items.clone())); commands.spawn(tilemap::tilemap_bundle(&asset_server, uvec2(16, 16), tiles, colliders)); + commands.spawn(stairs::stairs_bundle( + &asset_server, + vec2(meters(-5.), 0.), + Some(vec2(meters(2.), meters(4.))), + None, + )); + commands.spawn(stairs::stairs_bundle( + &asset_server, + vec2(meters(-5.), meters(4.)), + Some(vec2(meters(2.), meters(4.))), + Some(vec2(meters(-2.), meters(-4.))), + )); + commands.spawn(stairs::stairs_bundle( + &asset_server, + vec2(meters(-5.), meters(8.)), + None, + Some(vec2(meters(-2.), meters(-4.))), + )); } diff --git a/src/lib.rs b/src/lib.rs index d8f4dd8..5c8bff3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,6 +99,9 @@ impl Plugin for ExpeditionPlugin { )) .add_systems(OnEnter(GameState::Inventory), ui::inventory::systems::setup_ui_inventory) .add_systems(OnExit(GameState::Inventory), ui::inventory::systems::clear_ui_inventory) - .add_observer(ui::inventory::observers::on_ui_rotate); + .add_observer(ui::inventory::observers::on_ui_rotate) + .add_observer(layout::container::on_container_interact) + .add_observer(layout::door::on_door_interact) + .add_observer(layout::stairs::on_stairs_interact); } } diff --git a/src/player/mod.rs b/src/player/mod.rs index c512c55..8e99702 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -18,7 +18,7 @@ pub struct Player { impl Default for Player { fn default() -> Self { - Self { speed: meters(0.8) } + Self { speed: meters(4.) } } }