Use single collider per tile, and fix other off-by-1 errors.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
eae03f8f7a
commit
257e228a7a
147
src/map.rs
147
src/map.rs
|
@ -39,16 +39,6 @@ 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);
|
||||||
|
@ -132,7 +122,6 @@ 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,
|
||||||
|
@ -224,119 +213,29 @@ 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, &SpawnColliderPerTile), Changed<SpawnColliders>>,
|
maps: Query<(Entity, &Map<D>, &SpawnColliders), Changed<SpawnColliders>>,
|
||||||
) {
|
) {
|
||||||
for (map_entity, map, spawn_colliders, spawn_collider_per_tile) in maps.iter() {
|
for (map_entity, map, spawn_colliders) 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);
|
if tile.blocks_motion() {
|
||||||
if tile.blocks_motion() {
|
let id = commands
|
||||||
let id = commands
|
.spawn()
|
||||||
.spawn()
|
.insert(Collider::cuboid(0.5, 0.5))
|
||||||
.insert(Collider::cuboid(0.5, 0.5))
|
.insert(Transform::from_xyz(x as f32 + 0.5, y as f32 + 0.5, 0.))
|
||||||
.insert(Transform::from_xyz(x as f32 + 0.5, y as f32 + 0.5, 0.))
|
.insert(GlobalTransform::default())
|
||||||
.insert(GlobalTransform::default())
|
.insert(MapObstruction)
|
||||||
.insert(MapObstruction)
|
.id();
|
||||||
.id();
|
if tile.blocks_visibility() {
|
||||||
if tile.blocks_visibility() {
|
commands.entity(id).insert(Visible::opaque());
|
||||||
commands.entity(id).insert(Visible::opaque());
|
|
||||||
}
|
|
||||||
commands.entity(map_entity).push_children(&[id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
|
commands.entity(map_entity).push_children(&[id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,8 +303,8 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for portal in portals {
|
for portal in portals {
|
||||||
let x = portal.0 as f32;
|
let x = portal.0 as f32 + 0.5;
|
||||||
let y = portal.1 as f32;
|
let y = portal.1 as f32 + 0.5;
|
||||||
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.)),
|
||||||
|
@ -421,19 +320,15 @@ 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, &Transform), (With<Portal>, Without<Collider>)>,
|
portals: Query<Entity, (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, coordinates) in portals.iter() {
|
for portal_entity 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user