Minimize number of colliders by tracing walls.
This commit is contained in:
parent
3de4b69030
commit
48e6b9ff61
144
src/map.rs
144
src/map.rs
|
@ -34,6 +34,10 @@ pub struct MapObstruction;
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct Portal;
|
pub struct Portal;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deref, DerefMut, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct SpawnColliderPerTile(pub bool);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deref, DerefMut, Reflect)]
|
#[derive(Clone, Debug, Deref, DerefMut, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct SpawnColliders(pub bool);
|
pub struct SpawnColliders(pub bool);
|
||||||
|
@ -113,6 +117,7 @@ impl Default for PortalBundle {
|
||||||
pub struct MapBundle {
|
pub struct MapBundle {
|
||||||
pub map: Map,
|
pub map: Map,
|
||||||
pub spawn_colliders: SpawnColliders,
|
pub spawn_colliders: SpawnColliders,
|
||||||
|
pub spawn_collider_per_tile: SpawnColliderPerTile,
|
||||||
pub spawn_portals: SpawnPortals,
|
pub spawn_portals: SpawnPortals,
|
||||||
pub children: Children,
|
pub children: Children,
|
||||||
pub transform: Transform,
|
pub transform: Transform,
|
||||||
|
@ -193,32 +198,135 @@ impl MapFilter for GridBuilder {
|
||||||
|
|
||||||
fn spawn_colliders(
|
fn spawn_colliders(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
maps: Query<(Entity, &Map, &SpawnColliders), Changed<SpawnColliders>>,
|
maps: Query<(Entity, &Map, &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.entity(map_entity).remove::<SpawnColliders>();
|
commands.entity(map_entity).remove::<SpawnColliders>();
|
||||||
|
commands.entity(map_entity).remove::<SpawnColliderPerTile>();
|
||||||
commands.entity(map_entity).insert_bundle(RigidBodyBundle {
|
commands.entity(map_entity).insert_bundle(RigidBodyBundle {
|
||||||
body_type: RigidBodyType::Static,
|
body_type: RigidBodyType::Static,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
for x in 0..map.width {
|
if **spawn_collider_per_tile {
|
||||||
for y in 0..map.height {
|
for y in 0..map.height {
|
||||||
let tile = map.at(x, y);
|
for x in 0..map.width {
|
||||||
if tile.blocks_motion() {
|
let tile = map.at(x, y);
|
||||||
let id = commands
|
if tile.blocks_motion() {
|
||||||
.spawn_bundle(ColliderBundle {
|
let id = commands
|
||||||
shape: ColliderShape::cuboid(0.5, 0.5),
|
.spawn_bundle(ColliderBundle {
|
||||||
..Default::default()
|
shape: ColliderShape::cuboid(0.5, 0.5),
|
||||||
})
|
..Default::default()
|
||||||
.insert(ColliderParent {
|
})
|
||||||
handle: map_entity.handle(),
|
.insert(ColliderParent {
|
||||||
pos_wrt_parent: Vec2::new(x as f32 + 0.5, y as f32 + 0.5).into(),
|
handle: map_entity.handle(),
|
||||||
})
|
pos_wrt_parent: Vec2::new(x as f32 + 0.5, y as f32 + 0.5)
|
||||||
.insert(MapObstruction)
|
.into(),
|
||||||
.id();
|
})
|
||||||
if tile.blocks_visibility() {
|
.insert(MapObstruction)
|
||||||
commands.entity(id).insert(BlocksVisibility);
|
.id();
|
||||||
|
if tile.blocks_visibility() {
|
||||||
|
commands.entity(id).insert(BlocksVisibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut has_body = vec![vec![false; map.height as usize]; map.width as usize];
|
||||||
|
let mut bottom_left = None;
|
||||||
|
let mut bottom_right = None;
|
||||||
|
for y in 0..map.height {
|
||||||
|
for x in 0..map.width {
|
||||||
|
// println!("Checking ({}, {})", x, y);
|
||||||
|
if bottom_left.is_some() {
|
||||||
|
if has_body[x][y] {
|
||||||
|
// println!("Hit another body, setting bottom right");
|
||||||
|
bottom_right = Some((x, y));
|
||||||
|
} else if map.at(x, y).is_walkable() {
|
||||||
|
/*println!(
|
||||||
|
"Hit an empty tile, setting bottom right to ({}, {})",
|
||||||
|
x - 1,
|
||||||
|
y
|
||||||
|
);*/
|
||||||
|
bottom_right = Some((x - 1, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if map.at(x, y).is_blocked() && !has_body[x][y] {
|
||||||
|
//println!("Blocked, setting has_body");
|
||||||
|
has_body[x][y] = true;
|
||||||
|
if bottom_left.is_none() {
|
||||||
|
//println!("Setting bottom left");
|
||||||
|
bottom_left = Some((x, y));
|
||||||
|
}
|
||||||
|
if bottom_left.is_some() && x == map.width - 1 {
|
||||||
|
//println!("Hit right edge, setting bottom right");
|
||||||
|
bottom_right = Some((x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (Some(bl), Some(br)) = (bottom_left, bottom_right) {
|
||||||
|
//println!("Got bottom, checking if can extend up");
|
||||||
|
let mut top_left = bl.clone();
|
||||||
|
let mut top_right = br.clone();
|
||||||
|
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 {
|
||||||
|
//println!("Extension check: ({}, {})", x, y);
|
||||||
|
if map.at(x, y).is_walkable() {
|
||||||
|
//println!("Can't, empty tile");
|
||||||
|
can_extend_up = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if can_extend_up {
|
||||||
|
//println!("Can extend up, setting has_body");
|
||||||
|
top_left.1 += 1;
|
||||||
|
top_right.1 += 1;
|
||||||
|
for x in top_left.0..=top_right.0 {
|
||||||
|
has_body[x][top_left.1] = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut width = br.0 as f32 - bl.0 as f32;
|
||||||
|
if width == 0. {
|
||||||
|
width = 1.;
|
||||||
|
}
|
||||||
|
let half_width = width / 2.;
|
||||||
|
let mut height = top_left.1 as f32 - bl.1 as f32;
|
||||||
|
if height == 0. {
|
||||||
|
height = 1.;
|
||||||
|
}
|
||||||
|
let half_height = height / 2.;
|
||||||
|
/*println!(
|
||||||
|
"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);
|
||||||
|
let x = center.0;
|
||||||
|
let y = center.1;
|
||||||
|
/*println!(
|
||||||
|
"Create shape at {:?} of width {} and height {}",
|
||||||
|
center, width, height
|
||||||
|
);*/
|
||||||
|
let id = commands
|
||||||
|
.spawn_bundle(ColliderBundle {
|
||||||
|
shape: ColliderShape::cuboid(half_width, half_height),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(ColliderParent {
|
||||||
|
handle: map_entity.handle(),
|
||||||
|
pos_wrt_parent: Vec2::new(x, y).into(),
|
||||||
|
})
|
||||||
|
.insert(MapObstruction)
|
||||||
|
.id();
|
||||||
|
if map.at(x as usize, y as usize).blocks_visibility() {
|
||||||
|
commands.entity(id).insert(BlocksVisibility);
|
||||||
|
}
|
||||||
|
bottom_left = None;
|
||||||
|
bottom_right = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user