Refactor visibility to be collider and event-based.
This commit is contained in:
parent
8f5b1b8f08
commit
42912e59a8
|
@ -95,7 +95,7 @@ where
|
||||||
let (x, y) = **coordinates;
|
let (x, y) = **coordinates;
|
||||||
let x = x as i32;
|
let x = x as i32;
|
||||||
let y = y as i32;
|
let y = y as i32;
|
||||||
if viewshed.visible.contains(&(x, y)) {
|
if viewshed.is_point_visible(&(x, y)) {
|
||||||
types.push(*t);
|
types.push(*t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,7 +176,7 @@ where
|
||||||
let (x, y) = ***coordinates;
|
let (x, y) = ***coordinates;
|
||||||
let x = x as i32;
|
let x = x as i32;
|
||||||
let y = y as i32;
|
let y = y as i32;
|
||||||
viewshed.visible.contains(&(x, y))
|
viewshed.is_point_visible(&(x, y))
|
||||||
})
|
})
|
||||||
.collect::<Vec<(&Coordinates, &ExplorationType)>>();
|
.collect::<Vec<(&Coordinates, &ExplorationType)>>();
|
||||||
features.sort_by(|(c1, _), (c2, _)| c1.partial_cmp(c2).unwrap());
|
features.sort_by(|(c1, _), (c2, _)| c1.partial_cmp(c2).unwrap());
|
||||||
|
|
25
src/sound.rs
25
src/sound.rs
|
@ -8,7 +8,7 @@ use rand::random;
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{Coordinates, CoreConfig, Player, PointLike},
|
core::{Coordinates, CoreConfig, Player, PointLike},
|
||||||
exploration::ExplorationFocused,
|
exploration::ExplorationFocused,
|
||||||
visibility::Viewshed,
|
visibility::{Viewshed, VisibleEntities},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Reflect)]
|
#[derive(Clone, Debug, Reflect)]
|
||||||
|
@ -151,14 +151,14 @@ fn sound_icon<S>(
|
||||||
config: Res<SoundConfig<S>>,
|
config: Res<SoundConfig<S>>,
|
||||||
state: Res<State<S>>,
|
state: Res<State<S>>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
viewers: Query<&Viewshed, With<Player>>,
|
viewers: Query<&VisibleEntities, With<Player>>,
|
||||||
mut icons: Query<(
|
mut icons: Query<(
|
||||||
|
Entity,
|
||||||
&mut SoundIcon,
|
&mut SoundIcon,
|
||||||
Option<&Coordinates>,
|
Option<&Coordinates>,
|
||||||
Option<&Parent>,
|
Option<&Parent>,
|
||||||
&mut Sound,
|
&mut Sound,
|
||||||
)>,
|
)>,
|
||||||
coordinates_storage: Query<&Coordinates>,
|
|
||||||
buffers: Res<Assets<Buffer>>,
|
buffers: Res<Assets<Buffer>>,
|
||||||
) where
|
) where
|
||||||
S: Component + Clone + Debug + Eq + Hash,
|
S: Component + Clone + Debug + Eq + Hash,
|
||||||
|
@ -168,18 +168,14 @@ fn sound_icon<S>(
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for viewer in viewers.iter() {
|
for visible in viewers.iter() {
|
||||||
for (mut icon, coordinates, parent, mut sound) in icons.iter_mut() {
|
for (icon_entity, mut icon, coordinates, parent, mut sound) in icons.iter_mut() {
|
||||||
let coords = if let Some(coordinates) = coordinates {
|
let entity = if coordinates.is_some() {
|
||||||
*coordinates
|
icon_entity
|
||||||
} else if let Some(parent) = parent {
|
|
||||||
*coordinates_storage
|
|
||||||
.get(**parent)
|
|
||||||
.expect("If `SoundIcon` is a child, its parent must have `Coordinates`")
|
|
||||||
} else {
|
} else {
|
||||||
panic!("No `Coordinates` on `SoundIcon` or parent");
|
**parent.unwrap()
|
||||||
};
|
};
|
||||||
if viewer.is_visible(&coords) {
|
if visible.contains(&entity) {
|
||||||
let looping = sound.looping;
|
let looping = sound.looping;
|
||||||
if looping {
|
if looping {
|
||||||
sound.state = SoundState::Playing;
|
sound.state = SoundState::Playing;
|
||||||
|
@ -193,7 +189,6 @@ fn sound_icon<S>(
|
||||||
let buffer = buffers.get_handle(icon.sound);
|
let buffer = buffers.get_handle(icon.sound);
|
||||||
sound.looping = icon.interval.is_none();
|
sound.looping = icon.interval.is_none();
|
||||||
if sound.buffer != buffer {
|
if sound.buffer != buffer {
|
||||||
sound.stop();
|
|
||||||
sound.buffer = buffer;
|
sound.buffer = buffer;
|
||||||
}
|
}
|
||||||
sound.gain = icon.gain;
|
sound.gain = icon.gain;
|
||||||
|
@ -201,6 +196,8 @@ fn sound_icon<S>(
|
||||||
sound.reference_distance = icon.reference_distance;
|
sound.reference_distance = icon.reference_distance;
|
||||||
sound.max_distance = icon.max_distance;
|
sound.max_distance = icon.max_distance;
|
||||||
sound.rolloff_factor = icon.rolloff_factor;
|
sound.rolloff_factor = icon.rolloff_factor;
|
||||||
|
} else {
|
||||||
|
sound.state = SoundState::Stopped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy_rapier2d::na::UnitComplex;
|
||||||
use coord_2d::{Coord, Size};
|
use coord_2d::{Coord, Size};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use shadowcast::{vision_distance, Context, InputGrid};
|
use shadowcast::{vision_distance, Context, InputGrid};
|
||||||
|
@ -10,6 +11,7 @@ use crate::{
|
||||||
core::{Angle, Coordinates, Player, PointLike},
|
core::{Angle, Coordinates, Player, PointLike},
|
||||||
log::Log,
|
log::Log,
|
||||||
map::{ITileType, Map, MapConfig},
|
map::{ITileType, Map, MapConfig},
|
||||||
|
utils::target_and_other,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deref, DerefMut, Reflect)]
|
#[derive(Clone, Copy, Debug, Deref, DerefMut, Reflect)]
|
||||||
|
@ -21,6 +23,7 @@ impl Default for BlocksVisibility {
|
||||||
Self(u8::MAX)
|
Self(u8::MAX)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Reflect)]
|
#[derive(Clone, Copy, Debug, Default, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct DontLogWhenVisible;
|
pub struct DontLogWhenVisible;
|
||||||
|
@ -31,29 +34,58 @@ pub struct RevealedTiles(pub Vec<bool>);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Viewshed {
|
pub struct Viewshed {
|
||||||
pub visible: HashSet<(i32, i32)>,
|
|
||||||
pub range: u32,
|
pub range: u32,
|
||||||
|
pub visible_points: HashSet<(i32, i32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Viewshed {
|
impl Default for Viewshed {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
range: 15,
|
range: 15,
|
||||||
visible: HashSet::new(),
|
visible_points: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Viewshed {
|
impl Viewshed {
|
||||||
pub fn is_visible(&self, point: &dyn PointLike) -> bool {
|
pub fn is_point_visible(&self, point: &dyn PointLike) -> bool {
|
||||||
self.visible.contains(&point.into())
|
self.visible_points.contains(&point.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Reflect)]
|
||||||
|
struct VisibilityCollider;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, Deref, DerefMut)]
|
||||||
|
pub struct VisibleEntities(HashSet<Entity>);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deref, DerefMut, Reflect)]
|
#[derive(Clone, Debug, Default, Deref, DerefMut, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct VisibleTiles(pub Vec<bool>);
|
pub struct VisibleTiles(pub Vec<bool>);
|
||||||
|
|
||||||
|
#[derive(Bundle, Default)]
|
||||||
|
pub struct ViewshedBundle {
|
||||||
|
pub viewshed: Viewshed,
|
||||||
|
pub visible_entities: VisibleEntities,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewshedBundle {
|
||||||
|
pub fn new(range: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
viewshed: Viewshed {
|
||||||
|
range,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum VisibilityChanged {
|
||||||
|
Gained { viewer: Entity, viewed: Entity },
|
||||||
|
Lost { viewer: Entity, viewed: 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
|
||||||
|
@ -80,6 +112,90 @@ fn add_visibility_indices(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn viewshed_added(mut commands: Commands, query: Query<Entity, Added<Viewshed>>) {
|
||||||
|
for entity in query.iter() {
|
||||||
|
let id = commands.spawn().insert(VisibilityCollider).id();
|
||||||
|
commands.entity(entity).push_children(&[id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn viewshed_changed(
|
||||||
|
mut commands: Commands,
|
||||||
|
query: Query<(Entity, &Viewshed, &RigidBodyPosition), Changed<Viewshed>>,
|
||||||
|
mut collider_data: Query<
|
||||||
|
(&Parent, Entity, Option<&mut ColliderShape>),
|
||||||
|
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()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct VisibilityGrid<'a, F>(pub &'a Map, pub F);
|
pub struct VisibilityGrid<'a, F>(pub &'a Map, pub F);
|
||||||
|
|
||||||
impl<'a, F> InputGrid for VisibilityGrid<'a, F>
|
impl<'a, F> InputGrid for VisibilityGrid<'a, F>
|
||||||
|
@ -128,7 +244,6 @@ fn update_viewshed(
|
||||||
Some(&|v| v.entity() != *viewer_entity && blocks_visibility.get(v.entity()).is_ok()),
|
Some(&|v| v.entity() != *viewer_entity && blocks_visibility.get(v.entity()).is_ok()),
|
||||||
|handle| {
|
|handle| {
|
||||||
if let Ok(blocks_visibility) = blocks_visibility.get(handle.entity()) {
|
if let Ok(blocks_visibility) = blocks_visibility.get(handle.entity()) {
|
||||||
// println!("Visibility blocked at {:?}", coord);
|
|
||||||
opacity = **blocks_visibility;
|
opacity = **blocks_visibility;
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
|
@ -149,8 +264,8 @@ fn update_viewshed(
|
||||||
new_visible.insert((coord.x, coord.y));
|
new_visible.insert((coord.x, coord.y));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if viewshed.visible != new_visible {
|
if viewshed.visible_points != new_visible {
|
||||||
viewshed.visible = new_visible;
|
viewshed.visible_points = new_visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,14 +323,18 @@ fn update_viewshed_for_start(
|
||||||
|
|
||||||
fn remove_blocks_visibility(
|
fn remove_blocks_visibility(
|
||||||
removed: RemovedComponents<BlocksVisibility>,
|
removed: RemovedComponents<BlocksVisibility>,
|
||||||
mut viewers: Query<(Entity, &mut Viewshed, &Coordinates)>,
|
mut viewers: Query<(Entity, &mut Viewshed, &mut VisibleEntities, &Coordinates)>,
|
||||||
map: Query<&Map>,
|
map: Query<&Map>,
|
||||||
query_pipeline: Res<QueryPipeline>,
|
query_pipeline: Res<QueryPipeline>,
|
||||||
collider_query: QueryPipelineColliderComponentsQuery,
|
collider_query: QueryPipelineColliderComponentsQuery,
|
||||||
blocks_visibility: Query<&BlocksVisibility>,
|
blocks_visibility: Query<&BlocksVisibility>,
|
||||||
) {
|
) {
|
||||||
for _ in removed.iter() {
|
for removed in removed.iter() {
|
||||||
for (viewer_entity, mut viewshed, start) in viewers.iter_mut() {
|
for (viewer_entity, mut viewshed, mut visible_entities, start) in viewers.iter_mut() {
|
||||||
|
if !visible_entities.contains(&removed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
visible_entities.remove(&removed);
|
||||||
if let Ok(map) = map.single() {
|
if let Ok(map) = map.single() {
|
||||||
update_viewshed(
|
update_viewshed(
|
||||||
&viewer_entity,
|
&viewer_entity,
|
||||||
|
@ -240,7 +359,7 @@ fn update_visible_and_revealed_tiles(
|
||||||
for t in visible_tiles.iter_mut() {
|
for t in visible_tiles.iter_mut() {
|
||||||
*t = false
|
*t = false
|
||||||
}
|
}
|
||||||
for v in viewshed.visible.iter() {
|
for v in viewshed.visible_points.iter() {
|
||||||
let idx = v.to_index(map.width);
|
let idx = v.to_index(map.width);
|
||||||
if idx >= revealed_tiles.len() || idx >= visible_tiles.len() {
|
if idx >= revealed_tiles.len() || idx >= visible_tiles.len() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -252,73 +371,111 @@ fn update_visible_and_revealed_tiles(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intersection(
|
||||||
|
mut events: EventReader<IntersectionEvent>,
|
||||||
|
colliders: Query<&Parent, 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 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,
|
||||||
|
viewed: other,
|
||||||
|
});
|
||||||
|
visible_entities.insert(other);
|
||||||
|
} else {
|
||||||
|
println!("{:?} is not visible", other);
|
||||||
|
visibility_changed.send(VisibilityChanged::Lost {
|
||||||
|
viewer: **parent,
|
||||||
|
viewed: other,
|
||||||
|
});
|
||||||
|
visible_entities.remove(&other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn log_visible(
|
fn log_visible(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut seen: Local<HashSet<Entity>>,
|
|
||||||
mut recently_lost: Local<HashMap<Entity, Timer>>,
|
mut recently_lost: Local<HashMap<Entity, Timer>>,
|
||||||
query_pipeline: Res<QueryPipeline>,
|
mut events: EventReader<IntersectionEvent>,
|
||||||
collider_query: QueryPipelineColliderComponentsQuery,
|
|
||||||
mut log: Query<&mut Log>,
|
mut log: Query<&mut Log>,
|
||||||
viewers: Query<(Entity, &Viewshed, &Coordinates, &Transform), With<Player>>,
|
viewer_colliders: Query<&Parent, With<VisibilityCollider>>,
|
||||||
names: Query<&Name>,
|
viewers: Query<(Entity, &Coordinates, &Transform), (With<Player>, With<Viewshed>)>,
|
||||||
dont_log_when_visible: Query<&DontLogWhenVisible>,
|
viewed: Query<
|
||||||
|
(
|
||||||
|
Entity,
|
||||||
|
&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());
|
timer.tick(time.delta());
|
||||||
}
|
}
|
||||||
recently_lost.retain(|_, v| !v.finished());
|
recently_lost.retain(|_entity, timer| !timer.finished());
|
||||||
let mut new_seen = HashSet::new();
|
for event in events.iter() {
|
||||||
if let Ok(mut log) = log.single_mut() {
|
if let Some((viewer_collider, other)) =
|
||||||
for (viewer_entity, viewshed, coordinates, transform) in viewers.iter() {
|
target_and_other(event.collider1.entity(), event.collider2.entity(), |v| {
|
||||||
let collider_set = QueryPipelineColliderComponentsSet(&collider_query);
|
viewer_colliders.get(v).is_ok()
|
||||||
let shape = Cuboid::new(Vec2::new(0.49, 0.49).into());
|
})
|
||||||
for viewed_coordinates in &viewshed.visible {
|
{
|
||||||
if coordinates.distance(viewed_coordinates) >= viewshed.range as f32 - 0.1 {
|
if let Ok((viewed_entity, name, rigid_body_position, collider_position)) =
|
||||||
continue;
|
viewed.get(other)
|
||||||
}
|
{
|
||||||
let shape_pos = (
|
if event.intersecting {
|
||||||
Vec2::new(viewed_coordinates.x() + 0.5, viewed_coordinates.y() + 0.5),
|
if recently_lost.contains_key(&viewed_entity) {
|
||||||
0.0,
|
recently_lost.remove(&viewed_entity);
|
||||||
)
|
} else {
|
||||||
.into();
|
if let Ok(parent) = viewer_colliders.get(viewer_collider) {
|
||||||
query_pipeline.intersections_with_shape(
|
if let Ok((viewer_entity, coordinates, transform)) =
|
||||||
&collider_set,
|
viewers.get(**parent)
|
||||||
&shape_pos,
|
|
||||||
&shape,
|
|
||||||
InteractionGroups::all(),
|
|
||||||
Some(&|v| v.entity() != viewer_entity),
|
|
||||||
|handle| {
|
|
||||||
let entity = handle.entity();
|
|
||||||
if recently_lost.contains_key(&entity) {
|
|
||||||
new_seen.insert(entity);
|
|
||||||
recently_lost.remove(&entity);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if let Ok(name) = names.get(entity) {
|
|
||||||
if !seen.contains(&entity)
|
|
||||||
&& !new_seen.contains(&entity)
|
|
||||||
&& dont_log_when_visible.get(entity).is_err()
|
|
||||||
{
|
{
|
||||||
let name = name.to_string();
|
if viewer_entity == viewed_entity {
|
||||||
let forward = transform.local_x();
|
continue;
|
||||||
let yaw = Angle::Radians(forward.y.atan2(forward.x));
|
}
|
||||||
let location = coordinates
|
if let Ok(mut log) = log.single_mut() {
|
||||||
.direction_and_distance(viewed_coordinates, Some(yaw));
|
let viewed_coordinates = if let Some(p) = rigid_body_position {
|
||||||
log.push(format!("{}: {}", name, location));
|
(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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
new_seen.insert(entity);
|
|
||||||
}
|
}
|
||||||
true
|
}
|
||||||
},
|
} else {
|
||||||
);
|
recently_lost.insert(viewed_entity, Timer::from_seconds(2., false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let recently_lost_entities = seen.difference(&new_seen);
|
|
||||||
for entity in recently_lost_entities {
|
|
||||||
recently_lost.insert(*entity, Timer::from_seconds(2., false));
|
|
||||||
}
|
|
||||||
*seen = new_seen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LOG_VISIBLE_LABEL: &str = "LOG_VISIBLE";
|
pub const LOG_VISIBLE_LABEL: &str = "LOG_VISIBLE";
|
||||||
|
@ -327,17 +484,20 @@ 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_system(add_visibility_indices.system())
|
app.add_event::<VisibilityChanged>()
|
||||||
.add_system_to_stage(
|
.add_system(add_visibility_indices.system())
|
||||||
CoreStage::PostUpdate,
|
.add_system(viewshed_added.system())
|
||||||
update_viewshed_for_coordinates.system(),
|
.add_system(viewshed_changed.system())
|
||||||
)
|
.add_system(lock_rotation.system())
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, update_viewshed_for_start.system())
|
.add_system_to_stage(CoreStage::PostUpdate, viewshed_removed.system())
|
||||||
|
.add_system(update_viewshed_for_coordinates.system())
|
||||||
|
.add_system(update_viewshed_for_start.system())
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, remove_blocks_visibility.system())
|
.add_system_to_stage(CoreStage::PostUpdate, remove_blocks_visibility.system())
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
CoreStage::PostUpdate,
|
CoreStage::PostUpdate,
|
||||||
update_visible_and_revealed_tiles.system(),
|
update_visible_and_revealed_tiles.system(),
|
||||||
)
|
)
|
||||||
|
.add_system(intersection.system())
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, log_visible.system());
|
.add_system_to_stage(CoreStage::PostUpdate, log_visible.system());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user