More collider-based visibility work.

This commit is contained in:
Nolan Darilek 2021-09-21 12:58:57 -05:00
parent 42912e59a8
commit 4e9fcef178

View File

@ -86,6 +86,12 @@ pub enum VisibilityChanged {
Lost { viewer: Entity, viewed: Entity }, Lost { viewer: Entity, viewed: Entity },
} }
#[derive(Clone, Debug, Default, Deref, DerefMut)]
struct VisibilityColliderToViewshed(HashMap<Entity, Entity>);
#[derive(Clone, Debug, Default, Deref, DerefMut)]
struct ViewshedToVisibilityCollider(HashMap<Entity, Entity>);
impl PointLike for Coord { impl PointLike for Coord {
fn x(&self) -> f32 { fn x(&self) -> f32 {
self.x as f32 self.x as f32
@ -112,87 +118,76 @@ fn add_visibility_indices(
} }
} }
fn viewshed_added(mut commands: Commands, query: Query<Entity, Added<Viewshed>>) { fn viewshed_added(
mut commands: Commands,
mut collider_to_viewshed: ResMut<VisibilityColliderToViewshed>,
mut viewshed_to_collider: ResMut<ViewshedToVisibilityCollider>,
query: Query<Entity, Added<Viewshed>>,
) {
for entity in query.iter() { for entity in query.iter() {
let id = commands.spawn().insert(VisibilityCollider).id(); let id = commands
commands.entity(entity).push_children(&[id]); .spawn_bundle(ColliderBundle {
collider_type: ColliderType::Sensor,
flags: ColliderFlags {
active_collision_types: ActiveCollisionTypes::all(),
active_events: ActiveEvents::INTERSECTION_EVENTS,
..Default::default()
},
..Default::default()
})
.insert(VisibilityCollider)
.id();
viewshed_to_collider.insert(entity, id);
collider_to_viewshed.insert(id, entity);
} }
} }
fn viewshed_changed( fn viewshed_changed(
mut commands: Commands, mut commands: Commands,
viewshed_to_collider: Res<ViewshedToVisibilityCollider>,
query: Query<(Entity, &Viewshed, &RigidBodyPosition), Changed<Viewshed>>, query: Query<(Entity, &Viewshed, &RigidBodyPosition), Changed<Viewshed>>,
mut collider_data: Query< mut collider_data: Query<
(&Parent, Entity, Option<&mut ColliderShape>), (Option<&mut ColliderShape>, Option<&mut ColliderPosition>),
With<VisibilityCollider>, With<VisibilityCollider>,
>, >,
) { ) {
for (entity, viewshed, position) in query.iter() { for (entity, viewshed, position) in query.iter() {
for (parent, child_entity, collider_shape) in collider_data.iter_mut() { if let Some(collider_entity) = viewshed_to_collider.get(&entity) {
if **parent != entity { if let Ok((collider_shape, collider_position)) = collider_data.get_mut(*collider_entity)
continue; {
}
if viewshed.visible_points.len() < 2 { if viewshed.visible_points.len() < 2 {
commands.entity(child_entity).remove::<ColliderShape>(); println!("Too few points, removing");
commands.entity(*collider_entity).remove::<ColliderShape>();
} else { } else {
let position = position.position; let translation = position.position.translation;
let mut points = vec![]; let mut points = vec![];
for p in &viewshed.visible_points { for p in &viewshed.visible_points {
points.push(point!( points.push(point!(p.x() - translation.x, p.y() - translation.y));
position.translation.x - p.x(),
position.translation.y - p.y()
));
} }
if let Some(shape) = ColliderShape::convex_hull(&points) { if let Some(shape) = ColliderShape::convex_hull(&points) {
//println!("Shape for {:?}", points); if let (Some(mut collider_shape), Some(mut collider_position)) =
if let Some(mut collider_shape) = collider_shape { (collider_shape, collider_position)
{
*collider_shape = shape; *collider_shape = shape;
} else { *collider_position = translation.into();
//println!("Creating collider at {:?}", coordinates.i32());
commands.entity(child_entity).insert_bundle(ColliderBundle {
collider_type: ColliderType::Sensor,
shape,
flags: ActiveEvents::INTERSECTION_EVENTS.into(),
..Default::default()
});
} }
} }
} }
} }
} }
} }
fn lock_rotation(
mut query: Query<(&Parent, &mut ColliderPosition), With<VisibilityCollider>>,
positions: Query<&RigidBodyPosition>,
) {
for (parent, mut position) in query.iter_mut() {
if let Ok(parent_position) = positions.get(**parent) {
let delta = parent_position
.position
.rotation
.angle_to(&UnitComplex::new(0.));
println!("Syncing: {:?}", delta);
position.rotation = UnitComplex::new(delta);
}
}
} }
fn viewshed_removed( fn viewshed_removed(
mut commands: Commands, mut collider_to_viewshed: ResMut<VisibilityColliderToViewshed>,
mut viewshed_to_collider: ResMut<ViewshedToVisibilityCollider>,
query: RemovedComponents<Viewshed>, query: RemovedComponents<Viewshed>,
children: Query<&Children>,
collider_shapes: Query<Entity, With<VisibilityCollider>>,
) { ) {
for entity in query.iter() { for entity in query.iter() {
if let Ok(children) = children.get(entity) { if let Some(collider) = viewshed_to_collider.get(&entity) {
for child in children.iter() { collider_to_viewshed.remove(&collider);
if collider_shapes.get(*child).is_ok() {
commands.entity(*child).despawn_recursive();
break;
}
}
} }
viewshed_to_collider.remove(&entity);
} }
} }
@ -245,10 +240,9 @@ fn update_viewshed(
|handle| { |handle| {
if let Ok(blocks_visibility) = blocks_visibility.get(handle.entity()) { if let Ok(blocks_visibility) = blocks_visibility.get(handle.entity()) {
opacity = **blocks_visibility; opacity = **blocks_visibility;
false
} else { } else {
true
} }
true
}, },
); );
opacity opacity
@ -373,38 +367,35 @@ fn update_visible_and_revealed_tiles(
fn intersection( fn intersection(
mut events: EventReader<IntersectionEvent>, mut events: EventReader<IntersectionEvent>,
colliders: Query<&Parent, With<VisibilityCollider>>, collider_to_viewshed: Res<VisibilityColliderToViewshed>,
colliders: Query<Entity, With<VisibilityCollider>>,
mut viewers: Query<&mut VisibleEntities>, mut viewers: Query<&mut VisibleEntities>,
names: Query<&Name>,
parents: Query<&Parent>,
mut visibility_changed: EventWriter<VisibilityChanged>, mut visibility_changed: EventWriter<VisibilityChanged>,
) { ) {
for event in events.iter() { for event in events.iter() {
println!("{:?}", event);
if let Some((visibility_collider, other)) = if let Some((visibility_collider, other)) =
target_and_other(event.collider1.entity(), event.collider2.entity(), |v| { target_and_other(event.collider1.entity(), event.collider2.entity(), |v| {
colliders.get(v).is_ok() colliders.get(v).is_ok()
}) })
{ {
if let Ok(parent) = colliders.get(visibility_collider) { if let Some(viewshed_entity) = collider_to_viewshed.get(&visibility_collider) {
if let Ok(mut visible_entities) = viewers.get_mut(**parent) { if let Ok(mut visible_entities) = viewers.get_mut(*viewshed_entity) {
if event.intersecting { if event.intersecting {
println!("{:?} is visible: {:?}", other, names.get(other));
if let Ok(p) = parents.get(other) {
println!("{:?}", names.get(**p));
}
visibility_changed.send(VisibilityChanged::Gained { visibility_changed.send(VisibilityChanged::Gained {
viewer: **parent, viewer: *viewshed_entity,
viewed: other, viewed: other,
}); });
visible_entities.insert(other); visible_entities.insert(other);
} else { } else {
println!("{:?} is not visible", other);
visibility_changed.send(VisibilityChanged::Lost { visibility_changed.send(VisibilityChanged::Lost {
viewer: **parent, viewer: *viewshed_entity,
viewed: other, viewed: other,
}); });
if visible_entities.contains(&other) {
visible_entities.remove(&other); visible_entities.remove(&other);
} else {
println!("Making invisible something that was never visible");
}
} }
} }
} }
@ -413,68 +404,45 @@ fn intersection(
} }
fn log_visible( fn log_visible(
time: Res<Time>, // time: Res<Time>,
mut recently_lost: Local<HashMap<Entity, Timer>>, // mut recently_lost: Local<HashMap<Entity, Timer>>,
mut events: EventReader<IntersectionEvent>, mut events: EventReader<VisibilityChanged>,
mut log: Query<&mut Log>, mut log: Query<&mut Log>,
viewer_colliders: Query<&Parent, With<VisibilityCollider>>,
viewers: Query<(Entity, &Coordinates, &Transform), (With<Player>, With<Viewshed>)>, viewers: Query<(Entity, &Coordinates, &Transform), (With<Player>, With<Viewshed>)>,
viewed: Query< vieweds: Query<
( (&Name, Option<&RigidBodyPosition>, Option<&ColliderPosition>),
Entity,
&Name,
Option<&RigidBodyPosition>,
Option<&ColliderPosition>,
),
Without<DontLogWhenVisible>, Without<DontLogWhenVisible>,
>, >,
) { ) {
for timer in recently_lost.values_mut() { /*for timer in recently_lost.values_mut() {
timer.tick(time.delta()); timer.tick(time.delta());
} }*/
recently_lost.retain(|_entity, timer| !timer.finished()); //recently_lost.retain(|_entity, timer| !timer.finished());
for event in events.iter() { for event in events.iter() {
if let Some((viewer_collider, other)) = if let VisibilityChanged::Gained { viewer, viewed } = event {
target_and_other(event.collider1.entity(), event.collider2.entity(), |v| { if let Ok((viewer_entity, viewer_coordinates, viewer_transform)) = viewers.get(*viewer)
viewer_colliders.get(v).is_ok()
})
{ {
if let Ok((viewed_entity, name, rigid_body_position, collider_position)) = if *viewed == viewer_entity {
viewed.get(other)
{
if event.intersecting {
if recently_lost.contains_key(&viewed_entity) {
recently_lost.remove(&viewed_entity);
} else {
if let Ok(parent) = viewer_colliders.get(viewer_collider) {
if let Ok((viewer_entity, coordinates, transform)) =
viewers.get(**parent)
{
if viewer_entity == viewed_entity {
continue; continue;
} }
if let Ok((name, body_position, collider_position)) = vieweds.get(*viewed) {
if let Ok(mut log) = log.single_mut() { if let Ok(mut log) = log.single_mut() {
let viewed_coordinates = if let Some(p) = rigid_body_position { let viewed_coordinates = if let Some(p) = body_position {
(p.position.translation.x, p.position.translation.y) (p.position.translation.x, p.position.translation.y)
} else if let Some(p) = collider_position { } else if let Some(p) = collider_position {
(p.translation.x, p.translation.y) (p.translation.x, p.translation.y)
} else { } else {
(0., 0.) (0., 0.)
}; };
let forward = transform.local_x(); let forward = viewer_transform.local_x();
let yaw = Angle::Radians(forward.y.atan2(forward.x)); let yaw = Angle::Radians(forward.y.atan2(forward.x));
let location = coordinates let location = viewer_coordinates
.direction_and_distance(&viewed_coordinates, Some(yaw)); .direction_and_distance(&viewed_coordinates, Some(yaw));
log.push(format!("{}: {}", **name, location)); log.push(format!("{}: {}", **name, location));
} }
} }
} }
} }
} else {
recently_lost.insert(viewed_entity, Timer::from_seconds(2., false));
}
}
}
} }
} }
@ -484,11 +452,12 @@ pub struct VisibilityPlugin;
impl Plugin for VisibilityPlugin { impl Plugin for VisibilityPlugin {
fn build(&self, app: &mut AppBuilder) { fn build(&self, app: &mut AppBuilder) {
app.add_event::<VisibilityChanged>() app.init_resource::<VisibilityColliderToViewshed>()
.init_resource::<ViewshedToVisibilityCollider>()
.add_event::<VisibilityChanged>()
.add_system(add_visibility_indices.system()) .add_system(add_visibility_indices.system())
.add_system(viewshed_added.system()) .add_system(viewshed_added.system())
.add_system(viewshed_changed.system()) .add_system(viewshed_changed.system())
.add_system(lock_rotation.system())
.add_system_to_stage(CoreStage::PostUpdate, viewshed_removed.system()) .add_system_to_stage(CoreStage::PostUpdate, viewshed_removed.system())
.add_system(update_viewshed_for_coordinates.system()) .add_system(update_viewshed_for_coordinates.system())
.add_system(update_viewshed_for_start.system()) .add_system(update_viewshed_for_start.system())