diff --git a/src/map.rs b/src/map.rs index 480f36f..f4284e5 100644 --- a/src/map.rs +++ b/src/map.rs @@ -34,6 +34,26 @@ pub struct MapObstruction; #[reflect(Component)] pub struct Portal; +#[derive(Clone, Debug, Deref, DerefMut, Reflect)] +#[reflect(Component)] +pub struct SpawnColliders(pub bool); + +impl Default for SpawnColliders { + fn default() -> Self { + Self(true) + } +} + +#[derive(Clone, Debug, Deref, DerefMut, Reflect)] +#[reflect(Component)] +pub struct SpawnPortals(pub bool); + +impl Default for SpawnPortals { + fn default() -> Self { + Self(true) + } +} + pub trait ITileType { fn blocks_motion(&self) -> bool; fn blocks_visibility(&self) -> bool; @@ -51,7 +71,6 @@ impl ITileType for Tile { #[derive(Clone, Debug)] pub struct MapConfig { - pub autospawn_portals: bool, pub describe_undescribed_areas: bool, pub speak_area_descriptions: bool, pub start_revealed: bool, @@ -60,7 +79,6 @@ pub struct MapConfig { impl Default for MapConfig { fn default() -> Self { Self { - autospawn_portals: true, describe_undescribed_areas: false, speak_area_descriptions: true, start_revealed: false, @@ -94,6 +112,8 @@ impl Default for PortalBundle { #[derive(Bundle, Clone, Default)] pub struct MapBundle { pub map: Map, + pub spawn_colliders: SpawnColliders, + pub spawn_portals: SpawnPortals, pub children: Children, pub transform: Transform, pub global_transform: GlobalTransform, @@ -171,61 +191,67 @@ impl MapFilter for GridBuilder { } } -fn add_map_colliders(mut commands: Commands, maps: Query<(Entity, &Map), Added>) { - for (map_entity, map) in maps.iter() { - commands.entity(map_entity).insert_bundle(RigidBodyBundle { - body_type: RigidBodyType::Static, - ..Default::default() - }); - for x in 0..map.width { - for y in 0..map.height { - let tile = map.at(x, y); - if tile.blocks_motion() { - let id = commands - .spawn_bundle(ColliderBundle { - shape: ColliderShape::cuboid(0.5, 0.5), - ..Default::default() - }) - .insert(ColliderParent { - handle: map_entity.handle(), - pos_wrt_parent: Vec2::new(x as f32 + 0.5, y as f32 + 0.5).into(), - }) - .insert(MapObstruction) - .id(); - if tile.blocks_visibility() { - commands.entity(id).insert(BlocksVisibility); +fn spawn_colliders( + mut commands: Commands, + maps: Query<(Entity, &Map, &SpawnColliders), Changed>, +) { + for (map_entity, map, spawn_colliders) in maps.iter() { + if **spawn_colliders { + commands.entity(map_entity).remove::(); + commands.entity(map_entity).insert_bundle(RigidBodyBundle { + body_type: RigidBodyType::Static, + ..Default::default() + }); + for x in 0..map.width { + for y in 0..map.height { + let tile = map.at(x, y); + if tile.blocks_motion() { + let id = commands + .spawn_bundle(ColliderBundle { + shape: ColliderShape::cuboid(0.5, 0.5), + ..Default::default() + }) + .insert(ColliderParent { + handle: map_entity.handle(), + pos_wrt_parent: Vec2::new(x as f32 + 0.5, y as f32 + 0.5).into(), + }) + .insert(MapObstruction) + .id(); + if tile.blocks_visibility() { + commands.entity(id).insert(BlocksVisibility); + } } } } - } - for room in &map.rooms { - let shape = - ColliderShape::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32); - let position = Vec2::new(room.center().x(), room.center().y()).into(); - commands - .spawn_bundle(ColliderBundle { - collider_type: ColliderType::Sensor, - shape: shape.clone(), - flags: ActiveEvents::INTERSECTION_EVENTS.into(), - ..Default::default() - }) - .insert(ColliderParent { - handle: map_entity.handle(), - pos_wrt_parent: position, - }) - .insert(shape.compute_aabb(&position)) - .insert(AreaTag); + for room in &map.rooms { + let shape = + ColliderShape::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32); + let position = Vec2::new(room.center().x(), room.center().y()).into(); + commands + .spawn_bundle(ColliderBundle { + collider_type: ColliderType::Sensor, + shape: shape.clone(), + flags: ActiveEvents::INTERSECTION_EVENTS.into(), + ..Default::default() + }) + .insert(ColliderParent { + handle: map_entity.handle(), + pos_wrt_parent: position, + }) + .insert(shape.compute_aabb(&position)) + .insert(AreaTag); + } } } } -fn portal_spawner( +fn spawn_portals( mut commands: Commands, - map: Query<(Entity, &Map), Added>, - config: Res, + map: Query<(Entity, &Map, &SpawnPortals), Changed>, ) { - for (entity, map) in map.iter() { - if config.autospawn_portals { + for (entity, map, spawn_portals) in map.iter() { + if **spawn_portals { + commands.entity(entity).remove::(); let mut portals: Vec<(f32, f32)> = vec![]; for x in 1..map.width { for y in 1..map.height { @@ -267,6 +293,23 @@ fn portal_spawner( coordinates, ..Default::default() }) + .id(); + commands.entity(entity).push_children(&[portal]); + } + } + } +} + +fn spawn_portal_colliders( + mut commands: Commands, + map: Query<(Entity, &SpawnColliders), With>, + portals: Query<(Entity, &Coordinates), Without>, +) { + for (map_entity, spawn_colliders) in map.iter() { + if **spawn_colliders { + for (portal_entity, coordinates) in portals.iter() { + commands + .entity(portal_entity) .insert_bundle(ColliderBundle { collider_type: ColliderType::Sensor, shape: ColliderShape::cuboid(0.5, 0.5), @@ -275,11 +318,10 @@ fn portal_spawner( }) .insert(ColliderPositionSync::Discrete) .insert(ColliderParent { - handle: entity.handle(), - pos_wrt_parent: Vec2::new(x + 0.5, y + 0.5).into(), - }) - .id(); - commands.entity(entity).push_children(&[portal]); + handle: map_entity.handle(), + pos_wrt_parent: Vec2::new(coordinates.x() + 0.5, coordinates.y() + 0.5) + .into(), + }); } } } @@ -331,8 +373,9 @@ impl Plugin for MapPlugin { } let config = app.world().get_resource::().unwrap().clone(); app.register_type::() - .add_system(add_map_colliders.system()) - .add_system(portal_spawner.system()); + .add_system(spawn_colliders.system()) + .add_system(spawn_portals.system()) + .add_system(spawn_portal_colliders.system()); if config.speak_area_descriptions { app.add_system_to_stage(CoreStage::PostUpdate, area_description.system()); }