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 },
|
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())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user