More collider-based visibility work.
This commit is contained in:
parent
42912e59a8
commit
4e9fcef178
|
@ -86,6 +86,12 @@ pub enum VisibilityChanged {
|
|||
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 {
|
||||
fn x(&self) -> f32 {
|
||||
self.x as f32
|
||||
|
@ -112,49 +118,59 @@ 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() {
|
||||
let id = commands.spawn().insert(VisibilityCollider).id();
|
||||
commands.entity(entity).push_children(&[id]);
|
||||
let id = commands
|
||||
.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(
|
||||
mut commands: Commands,
|
||||
viewshed_to_collider: Res<ViewshedToVisibilityCollider>,
|
||||
query: Query<(Entity, &Viewshed, &RigidBodyPosition), Changed<Viewshed>>,
|
||||
mut collider_data: Query<
|
||||
(&Parent, Entity, Option<&mut ColliderShape>),
|
||||
(Option<&mut ColliderShape>, Option<&mut ColliderPosition>),
|
||||
With<VisibilityCollider>,
|
||||
>,
|
||||
) {
|
||||
for (entity, viewshed, position) in query.iter() {
|
||||
for (parent, child_entity, collider_shape) in collider_data.iter_mut() {
|
||||
if **parent != entity {
|
||||
continue;
|
||||
}
|
||||
if viewshed.visible_points.len() < 2 {
|
||||
commands.entity(child_entity).remove::<ColliderShape>();
|
||||
} else {
|
||||
let position = position.position;
|
||||
let mut points = vec![];
|
||||
for p in &viewshed.visible_points {
|
||||
points.push(point!(
|
||||
position.translation.x - p.x(),
|
||||
position.translation.y - p.y()
|
||||
));
|
||||
}
|
||||
if let Some(shape) = ColliderShape::convex_hull(&points) {
|
||||
//println!("Shape for {:?}", points);
|
||||
if let Some(mut collider_shape) = collider_shape {
|
||||
*collider_shape = shape;
|
||||
} else {
|
||||
//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()
|
||||
});
|
||||
if let Some(collider_entity) = viewshed_to_collider.get(&entity) {
|
||||
if let Ok((collider_shape, collider_position)) = collider_data.get_mut(*collider_entity)
|
||||
{
|
||||
if viewshed.visible_points.len() < 2 {
|
||||
println!("Too few points, removing");
|
||||
commands.entity(*collider_entity).remove::<ColliderShape>();
|
||||
} else {
|
||||
let translation = position.position.translation;
|
||||
let mut points = vec![];
|
||||
for p in &viewshed.visible_points {
|
||||
points.push(point!(p.x() - translation.x, p.y() - translation.y));
|
||||
}
|
||||
if let Some(shape) = ColliderShape::convex_hull(&points) {
|
||||
if let (Some(mut collider_shape), Some(mut collider_position)) =
|
||||
(collider_shape, collider_position)
|
||||
{
|
||||
*collider_shape = shape;
|
||||
*collider_position = translation.into();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,37 +178,16 @@ fn viewshed_changed(
|
|||
}
|
||||
}
|
||||
|
||||
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(
|
||||
mut commands: Commands,
|
||||
mut collider_to_viewshed: ResMut<VisibilityColliderToViewshed>,
|
||||
mut viewshed_to_collider: ResMut<ViewshedToVisibilityCollider>,
|
||||
query: RemovedComponents<Viewshed>,
|
||||
children: Query<&Children>,
|
||||
collider_shapes: Query<Entity, With<VisibilityCollider>>,
|
||||
) {
|
||||
for entity in query.iter() {
|
||||
if let Ok(children) = children.get(entity) {
|
||||
for child in children.iter() {
|
||||
if collider_shapes.get(*child).is_ok() {
|
||||
commands.entity(*child).despawn_recursive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(collider) = viewshed_to_collider.get(&entity) {
|
||||
collider_to_viewshed.remove(&collider);
|
||||
}
|
||||
viewshed_to_collider.remove(&entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,10 +240,9 @@ fn update_viewshed(
|
|||
|handle| {
|
||||
if let Ok(blocks_visibility) = blocks_visibility.get(handle.entity()) {
|
||||
opacity = **blocks_visibility;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
true
|
||||
},
|
||||
);
|
||||
opacity
|
||||
|
@ -373,38 +367,35 @@ fn update_visible_and_revealed_tiles(
|
|||
|
||||
fn intersection(
|
||||
mut events: EventReader<IntersectionEvent>,
|
||||
colliders: Query<&Parent, With<VisibilityCollider>>,
|
||||
collider_to_viewshed: Res<VisibilityColliderToViewshed>,
|
||||
colliders: Query<Entity, With<VisibilityCollider>>,
|
||||
mut viewers: Query<&mut VisibleEntities>,
|
||||
names: Query<&Name>,
|
||||
parents: Query<&Parent>,
|
||||
mut visibility_changed: EventWriter<VisibilityChanged>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
println!("{:?}", event);
|
||||
if let Some((visibility_collider, other)) =
|
||||
target_and_other(event.collider1.entity(), event.collider2.entity(), |v| {
|
||||
colliders.get(v).is_ok()
|
||||
})
|
||||
{
|
||||
if let Ok(parent) = colliders.get(visibility_collider) {
|
||||
if let Ok(mut visible_entities) = viewers.get_mut(**parent) {
|
||||
if let Some(viewshed_entity) = collider_to_viewshed.get(&visibility_collider) {
|
||||
if let Ok(mut visible_entities) = viewers.get_mut(*viewshed_entity) {
|
||||
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 {
|
||||
viewer: **parent,
|
||||
viewer: *viewshed_entity,
|
||||
viewed: other,
|
||||
});
|
||||
visible_entities.insert(other);
|
||||
} else {
|
||||
println!("{:?} is not visible", other);
|
||||
visibility_changed.send(VisibilityChanged::Lost {
|
||||
viewer: **parent,
|
||||
viewer: *viewshed_entity,
|
||||
viewed: other,
|
||||
});
|
||||
visible_entities.remove(&other);
|
||||
if visible_entities.contains(&other) {
|
||||
visible_entities.remove(&other);
|
||||
} else {
|
||||
println!("Making invisible something that was never visible");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -413,65 +404,42 @@ fn intersection(
|
|||
}
|
||||
|
||||
fn log_visible(
|
||||
time: Res<Time>,
|
||||
mut recently_lost: Local<HashMap<Entity, Timer>>,
|
||||
mut events: EventReader<IntersectionEvent>,
|
||||
// time: Res<Time>,
|
||||
// mut recently_lost: Local<HashMap<Entity, Timer>>,
|
||||
mut events: EventReader<VisibilityChanged>,
|
||||
mut log: Query<&mut Log>,
|
||||
viewer_colliders: Query<&Parent, With<VisibilityCollider>>,
|
||||
viewers: Query<(Entity, &Coordinates, &Transform), (With<Player>, With<Viewshed>)>,
|
||||
viewed: Query<
|
||||
(
|
||||
Entity,
|
||||
&Name,
|
||||
Option<&RigidBodyPosition>,
|
||||
Option<&ColliderPosition>,
|
||||
),
|
||||
vieweds: Query<
|
||||
(&Name, Option<&RigidBodyPosition>, Option<&ColliderPosition>),
|
||||
Without<DontLogWhenVisible>,
|
||||
>,
|
||||
) {
|
||||
for timer in recently_lost.values_mut() {
|
||||
/*for timer in recently_lost.values_mut() {
|
||||
timer.tick(time.delta());
|
||||
}
|
||||
recently_lost.retain(|_entity, timer| !timer.finished());
|
||||
}*/
|
||||
//recently_lost.retain(|_entity, timer| !timer.finished());
|
||||
for event in events.iter() {
|
||||
if let Some((viewer_collider, other)) =
|
||||
target_and_other(event.collider1.entity(), event.collider2.entity(), |v| {
|
||||
viewer_colliders.get(v).is_ok()
|
||||
})
|
||||
{
|
||||
if let Ok((viewed_entity, name, rigid_body_position, collider_position)) =
|
||||
viewed.get(other)
|
||||
if let VisibilityChanged::Gained { viewer, viewed } = event {
|
||||
if let Ok((viewer_entity, viewer_coordinates, viewer_transform)) = viewers.get(*viewer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if let Ok(mut log) = log.single_mut() {
|
||||
let viewed_coordinates = if let Some(p) = rigid_body_position {
|
||||
(p.position.translation.x, p.position.translation.y)
|
||||
} else if let Some(p) = collider_position {
|
||||
(p.translation.x, p.translation.y)
|
||||
} else {
|
||||
(0., 0.)
|
||||
};
|
||||
let forward = transform.local_x();
|
||||
let yaw = Angle::Radians(forward.y.atan2(forward.x));
|
||||
let location = coordinates
|
||||
.direction_and_distance(&viewed_coordinates, Some(yaw));
|
||||
log.push(format!("{}: {}", **name, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
if *viewed == viewer_entity {
|
||||
continue;
|
||||
}
|
||||
if let Ok((name, body_position, collider_position)) = vieweds.get(*viewed) {
|
||||
if let Ok(mut log) = log.single_mut() {
|
||||
let viewed_coordinates = if let Some(p) = body_position {
|
||||
(p.position.translation.x, p.position.translation.y)
|
||||
} else if let Some(p) = collider_position {
|
||||
(p.translation.x, p.translation.y)
|
||||
} else {
|
||||
(0., 0.)
|
||||
};
|
||||
let forward = viewer_transform.local_x();
|
||||
let yaw = Angle::Radians(forward.y.atan2(forward.x));
|
||||
let location = viewer_coordinates
|
||||
.direction_and_distance(&viewed_coordinates, Some(yaw));
|
||||
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 {
|
||||
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(viewshed_added.system())
|
||||
.add_system(viewshed_changed.system())
|
||||
.add_system(lock_rotation.system())
|
||||
.add_system_to_stage(CoreStage::PostUpdate, viewshed_removed.system())
|
||||
.add_system(update_viewshed_for_coordinates.system())
|
||||
.add_system(update_viewshed_for_start.system())
|
||||
|
|
Loading…
Reference in New Issue
Block a user