From 3084d02f6605b98bba32d9b1384af038014e1fb1 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Wed, 26 May 2021 14:57:55 -0500 Subject: [PATCH] Separate viewshed updates based on coordinate and visibility_blocked. --- src/visibility.rs | 116 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 25 deletions(-) diff --git a/src/visibility.rs b/src/visibility.rs index ecaba02..26ff09b 100644 --- a/src/visibility.rs +++ b/src/visibility.rs @@ -23,7 +23,7 @@ pub struct DontLogWhenVisible; #[reflect(Component)] pub struct RevealedTiles(pub Vec); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Viewshed { pub visible: HashSet<(i32, i32)>, pub range: u32, @@ -100,11 +100,11 @@ pub(crate) fn set_visibility_blocked( } #[derive(Default, Deref, DerefMut)] -struct PreviousIndex(HashMap); +struct PrevIndex(HashMap); fn map_visibility_indexing( mut map: Query<(&Map, &mut VisibilityBlocked)>, - mut prev_index: ResMut, + mut prev_index: ResMut, query: Query< (Entity, &Coordinates), ( @@ -135,7 +135,7 @@ fn map_visibility_indexing( } fn remove_blocks_visibility( - mut prev_index: ResMut, + mut prev_index: ResMut, mut map: Query<(&Map, &mut VisibilityBlocked)>, removed: RemovedComponents, coordinates: Query<&Coordinates>, @@ -184,33 +184,89 @@ impl InputGrid for VisibilityGrid { } fn update_viewshed( - mut viewers: Query< - (&mut Viewshed, &Coordinates), - Or<(Changed, Changed)>, - >, + viewshed: &mut Viewshed, + start: &Coordinates, + map: &Map, + visibility_blocked: &VisibilityBlocked, +) { + let mut context: Context = Context::default(); + let vision_distance = vision_distance::Circle::new(viewshed.range); + let coord = Coord::new(start.x_i32(), start.y_i32()); + viewshed.visible.clear(); + let visibility_grid = VisibilityGrid(map.clone(), visibility_blocked.clone()); + context.for_each_visible( + coord, + &visibility_grid, + &visibility_grid, + vision_distance, + 255, + |coord, _directions, _visibility| { + viewshed.visible.insert((coord.x, coord.y)); + }, + ); +} + +fn update_viewshed_for_coordinates( + mut viewers: Query<(&mut Viewshed, &Coordinates), Changed>, map: Query<(&Map, &VisibilityBlocked)>, ) { for (mut viewshed, start) in viewers.iter_mut() { for (map, visibility_blocked) in map.iter() { - let mut context: Context = Context::default(); - let vision_distance = vision_distance::Circle::new(viewshed.range); - let coord = Coord::new(start.x_i32(), start.y_i32()); - viewshed.visible.clear(); - let visibility_grid = VisibilityGrid(map.clone(), visibility_blocked.clone()); - context.for_each_visible( - coord, - &visibility_grid, - &visibility_grid, - vision_distance, - 255, - |coord, _directions, _visibility| { - viewshed.visible.insert((coord.x, coord.y)); - }, - ); + update_viewshed(&mut viewshed, start, &map, &visibility_blocked); } } } +#[derive(Clone, Debug, Default, Deref, DerefMut)] +struct PrevVisibilityBlocked(Vec); + +fn visibility_blocked_added(mut prev_visibility_blocked: ResMut, added: Query<&VisibilityBlocked, Added>) { + for visibility_blocked in added.iter() { + **prev_visibility_blocked = visibility_blocked.to_vec(); + } +} + +fn visibility_blocked_removed(mut prev_visibility_blocked: ResMut, removed: RemovedComponents) { + for _ in removed.iter() { + prev_visibility_blocked.clear(); + } +} + +fn update_viewshed_for_visibility_blocked( + mut prev_visibility_blocked: ResMut, + map: Query<(&Map, &VisibilityBlocked), Changed>, + mut queryset: QuerySet<( + Query<(Entity, &Viewshed)>, + Query<(&mut Viewshed, &Coordinates)>, + )>, +) { + for (map, visibility_blocked) in map.iter() { + let mut to_check = vec![]; + for (index, new) in visibility_blocked.iter().enumerate() { + let changed = if let Some(prev) = prev_visibility_blocked.get(index) { + prev != new + } else { + true + }; + if changed { + let coords = (index % map.width(), index / map.width()); + for (entity, viewshed) in queryset.q0().iter() { + if viewshed.is_visible(&coords) { + to_check.push(entity); + } + } + } + } + to_check.dedup(); + for entity in to_check { + if let Ok((mut viewshed, coordinates)) = queryset.q1_mut().get_mut(entity) { + update_viewshed(&mut viewshed, coordinates, &map, &visibility_blocked); + } + } + **prev_visibility_blocked = visibility_blocked.to_vec(); + } +} + fn update_visible_and_revealed_tiles( mut map: Query< (&Map, &mut RevealedTiles, &mut VisibleTiles), @@ -301,7 +357,10 @@ impl Plugin for VisibilityPlugin { const UPDATE_VISIBILITY_INDEX: &str = "UPDATE_VISIBILITY_INDEX"; const UPDATE_VIEWSHED: &str = "UPDATE_VIEWSHED"; const MAP_VISIBILITY: &str = "MAP_VISIBILITY"; - app.insert_resource(PreviousIndex::default()) + app.init_resource::() + .init_resource::() + .add_system(visibility_blocked_added.system()) + .add_system_to_stage(CoreStage::PostUpdate, visibility_blocked_removed.system()) .add_system(add_visibility_indices.system()) .add_system_to_stage( CoreStage::PostUpdate, @@ -324,7 +383,14 @@ impl Plugin for VisibilityPlugin { ) .add_system_to_stage( CoreStage::PostUpdate, - update_viewshed + update_viewshed_for_coordinates + .system() + .label(UPDATE_VIEWSHED) + .after(UPDATE_VISIBILITY_INDEX), + ) + .add_system_to_stage( + CoreStage::PostUpdate, + update_viewshed_for_visibility_blocked .system() .label(UPDATE_VIEWSHED) .after(UPDATE_VISIBILITY_INDEX),