Compare commits

..

No commits in common. "257e228a7af801cecee4f8959133c64c6b50db83" and "a019e8b5c7a60346884eed4e2329c12967466a7d" have entirely different histories.

2 changed files with 127 additions and 22 deletions

View File

@ -39,6 +39,16 @@ pub struct MapObstruction;
#[reflect(Component)] #[reflect(Component)]
pub struct Portal; pub struct Portal;
#[derive(Component, Clone, Debug, Default, Deref, DerefMut, Reflect)]
#[reflect(Component)]
pub struct SpawnColliderPerTile(pub bool);
impl From<bool> for SpawnColliderPerTile {
fn from(v: bool) -> Self {
Self(v)
}
}
#[derive(Component, Clone, Debug, Deref, DerefMut, Reflect)] #[derive(Component, Clone, Debug, Deref, DerefMut, Reflect)]
#[reflect(Component)] #[reflect(Component)]
pub struct SpawnColliders(pub bool); pub struct SpawnColliders(pub bool);
@ -122,6 +132,7 @@ impl Default for PortalBundle {
pub struct MapBundle<D: 'static + Clone + Default + Send + Sync> { pub struct MapBundle<D: 'static + Clone + Default + Send + Sync> {
pub map: Map<D>, pub map: Map<D>,
pub spawn_colliders: SpawnColliders, pub spawn_colliders: SpawnColliders,
pub spawn_collider_per_tile: SpawnColliderPerTile,
pub spawn_portals: SpawnPortals, pub spawn_portals: SpawnPortals,
pub transform: Transform, pub transform: Transform,
pub global_transform: GlobalTransform, pub global_transform: GlobalTransform,
@ -213,14 +224,16 @@ impl<D: Clone + Default> MapFilter<D> for GridBuilder {
fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>( fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
mut commands: Commands, mut commands: Commands,
maps: Query<(Entity, &Map<D>, &SpawnColliders), Changed<SpawnColliders>>, maps: Query<(Entity, &Map<D>, &SpawnColliders, &SpawnColliderPerTile), Changed<SpawnColliders>>,
) { ) {
for (map_entity, map, spawn_colliders) in maps.iter() { for (map_entity, map, spawn_colliders, spawn_collider_per_tile) in maps.iter() {
if **spawn_colliders { if **spawn_colliders {
commands commands
.entity(map_entity) .entity(map_entity)
.remove::<SpawnColliders>() .remove::<SpawnColliders>()
.remove::<SpawnColliderPerTile>()
.insert(RigidBody::Fixed); .insert(RigidBody::Fixed);
if **spawn_collider_per_tile {
for y in 0..map.height { for y in 0..map.height {
for x in 0..map.width { for x in 0..map.width {
let tile = map.at(x, y); let tile = map.at(x, y);
@ -239,6 +252,94 @@ fn spawn_colliders<D: 'static + Clone + Default + Send + Sync>(
} }
} }
} }
} else {
let mut has_body =
vec![vec![false; map.height as usize + 1]; map.width as usize + 1];
let mut bottom_left = None;
let mut bottom_right = None;
for y in 0..map.height {
for x in 0..map.width {
trace!("Checking ({x}, {y})");
if bottom_left.is_some() {
if has_body[x][y] {
trace!("Hit another body, setting bottom right");
bottom_right = Some((x, y));
} else if map.at(x, y).is_walkable() {
trace!("Hit an empty tile, setting bottom right to ({x}, {y})",);
bottom_right = Some((x, y));
}
}
if map.at(x, y).is_blocked() && !has_body[x][y] {
trace!("Blocked, setting has_body");
has_body[x][y] = true;
if bottom_left.is_none() {
trace!("Setting bottom left");
bottom_left = Some((x, y));
}
if bottom_left.is_some() && x == map.width - 1 {
trace!("Hit right edge, setting bottom right");
bottom_right = Some((x, y));
}
}
if let (Some(bl), Some(br)) = (bottom_left, bottom_right) {
trace!("Got bottom, checking if can extend up");
let mut top_left = (bl.0, bl.1 + 1);
let mut top_right = (br.0, br.1 + 1);
if y != map.height - 1 {
let mut can_extend_up = true;
for y in bl.1 + 1..map.height {
for x in bl.0..br.0 {
trace!("Extension check: ({x}, {y})");
if map.at(x, y).is_walkable() {
trace!("Can't, empty tile");
can_extend_up = false;
break;
}
}
if can_extend_up {
trace!("Can extend up, setting has_body");
for x in top_left.0..=top_right.0 {
has_body[x][top_left.1] = true;
}
top_left.1 += 1;
top_right.1 += 1;
} else {
break;
}
}
}
let width = br.0 as f32 - bl.0 as f32;
let half_width = width / 2.;
let height = top_left.1 as f32 - bl.1 as f32;
let half_height = height / 2.;
trace!(
"Top left: {:?}\ntop right: {:?}\nbottom left: {:?}\nbottom right: {:?}",
top_left, top_right, bl, br
);
let center = (bl.0 as f32 + half_width, br.1 as f32 + half_height);
trace!(
"Create shape at {:?} of width {:?} and height {:?}",
center,
width,
height
);
let id = commands
.spawn()
.insert(Collider::cuboid(half_width, half_height))
.insert(Transform::from_xyz(center.x(), center.y(), 0.))
.insert(GlobalTransform::default())
.insert(MapObstruction)
.id();
if map.at(x as usize, y as usize).blocks_visibility() {
commands.entity(id).insert(Visible::opaque());
}
commands.entity(map_entity).push_children(&[id]);
bottom_left = None;
bottom_right = None;
}
}
}
}
for room in &map.rooms { for room in &map.rooms {
let shape = Collider::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32); let shape = Collider::cuboid((room.width() / 2) as f32, (room.height() / 2) as f32);
let position = let position =
@ -303,8 +404,8 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
} }
} }
for portal in portals { for portal in portals {
let x = portal.0 as f32 + 0.5; let x = portal.0 as f32;
let y = portal.1 as f32 + 0.5; let y = portal.1 as f32;
let portal = commands let portal = commands
.spawn_bundle(PortalBundle { .spawn_bundle(PortalBundle {
transform: Transform::from_translation(Vec3::new(x, y, 0.)), transform: Transform::from_translation(Vec3::new(x, y, 0.)),
@ -320,15 +421,19 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
fn spawn_portal_colliders<D: 'static + Clone + Default + Send + Sync>( fn spawn_portal_colliders<D: 'static + Clone + Default + Send + Sync>(
mut commands: Commands, mut commands: Commands,
map: Query<&SpawnColliders, With<Map<D>>>, map: Query<&SpawnColliders, With<Map<D>>>,
portals: Query<Entity, (With<Portal>, Without<Collider>)>, portals: Query<(Entity, &Transform), (With<Portal>, Without<Collider>)>,
) { ) {
for spawn_colliders in map.iter() { for spawn_colliders in map.iter() {
if **spawn_colliders { if **spawn_colliders {
for portal_entity in portals.iter() { for (portal_entity, coordinates) in portals.iter() {
let position = Vec2::new(coordinates.x() + 0.5, coordinates.y() + 0.5);
commands commands
.entity(portal_entity) .entity(portal_entity)
.insert(Transform::from_xyz(position.x(), position.y(), 0.))
.insert(GlobalTransform::default())
.insert(Collider::cuboid(0.5, 0.5)) .insert(Collider::cuboid(0.5, 0.5))
.insert(Sensor(true)); .insert(Sensor(true))
.insert(ActiveEvents::COLLISION_EVENTS);
} }
} }
} }

View File

@ -75,7 +75,7 @@ fn find_path_for_shape<D: 'static + Clone + Default + Send + Sync>(
if map.at(p.0 as usize, p.1 as usize).is_walkable() { if map.at(p.0 as usize, p.1 as usize).is_walkable() {
for tile in map.get_available_exits(p.0 as usize, p.1 as usize) { for tile in map.get_available_exits(p.0 as usize, p.1 as usize) {
let mut should_push = true; let mut should_push = true;
let shape_pos = Isometry2::new(Vector2::new(tile.0 as f32 + 0.5, tile.1 as f32 + 0.5), 0.); let shape_pos = Isometry2::new(Vector2::new(tile.0 as f32, tile.1 as f32), 0.);
query_pipeline.intersections_with_shape( query_pipeline.intersections_with_shape(
&collider_set, &collider_set,
&shape_pos, &shape_pos,