Make visibility colliders the single source of truth for calculations.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
6ff5eb15a9
commit
1ff98c9132
17
src/map.rs
17
src/map.rs
|
@ -294,17 +294,15 @@ fn spawn_portals<D: 'static + Clone + Default + Send + Sync>(
|
|||
}
|
||||
}
|
||||
if spawn_portal {
|
||||
let x = x as f32;
|
||||
let y = y as f32;
|
||||
let x = x as f32 + 0.5;
|
||||
let y = y as f32 + 0.5;
|
||||
if !portals.contains(&(x, y)) {
|
||||
portals.push((x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for portal in portals {
|
||||
let x = portal.0 as f32 + 0.5;
|
||||
let y = portal.1 as f32 + 0.5;
|
||||
for (x, y) in portals {
|
||||
let portal = commands
|
||||
.spawn_bundle(PortalBundle {
|
||||
transform: Transform::from_translation(Vec3::new(x, y, 0.)),
|
||||
|
@ -387,9 +385,12 @@ impl<D: 'static + Clone + Default + Send + Sync> Plugin for MapPlugin<D> {
|
|||
}
|
||||
let config = app.world.get_resource::<MapConfig>().unwrap().clone();
|
||||
app.register_type::<Portal>()
|
||||
.add_system(spawn_colliders::<D>)
|
||||
.add_system(spawn_portals::<D>)
|
||||
.add_system(spawn_portal_colliders::<D>);
|
||||
.add_system_to_stage(
|
||||
CoreStage::PreUpdate,
|
||||
spawn_colliders::<D>.before(crate::visibility::UPDATE_VIEWSHED_LABEL),
|
||||
)
|
||||
.add_system_to_stage(CoreStage::PreUpdate, spawn_portals::<D>)
|
||||
.add_system_to_stage(CoreStage::PreUpdate, spawn_portal_colliders::<D>);
|
||||
if config.speak_area_descriptions {
|
||||
app.add_system_to_stage(CoreStage::PostUpdate, area_description);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
};
|
||||
|
||||
use bevy::{core::FixedTimestep, prelude::*};
|
||||
use bevy_rapier2d::na::{self, Point2};
|
||||
|
||||
use coord_2d::{Coord, Size};
|
||||
use shadowcast::{vision_distance, Context, InputGrid};
|
||||
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
|||
commands::RunIfExistsExt,
|
||||
core::{Angle, Player, PointLike},
|
||||
log::Log,
|
||||
map::{ITileType, Map, MapConfig},
|
||||
map::{Map, MapConfig, MapObstruction},
|
||||
};
|
||||
|
||||
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
|
||||
|
@ -57,19 +57,20 @@ impl Viewshed {
|
|||
rapier_context: &RapierContext,
|
||||
map: &Map<D>,
|
||||
visible_query: &Query<&Visible>,
|
||||
obstructions_query: &Query<&MapObstruction>,
|
||||
events: &mut EventWriter<VisibilityChanged>,
|
||||
cache: &mut HashMap<Coord, (u8, HashSet<Entity>)>,
|
||||
) {
|
||||
let mut context: Context<u8> = Context::default();
|
||||
let vision_distance = vision_distance::Circle::new(self.range);
|
||||
let shape = Collider::cuboid(0.5 - f32::EPSILON, 0.5 - f32::EPSILON);
|
||||
let origin = Point2::new(start.x().trunc(), start.y().trunc());
|
||||
let mut new_visible_entities = HashSet::new();
|
||||
let size = (map.width as u32, map.height as u32);
|
||||
let visibility_grid = VisibilityGrid(
|
||||
map,
|
||||
size,
|
||||
RefCell::new(Box::new(|coord: Coord| {
|
||||
let dest = Point2::new(coord.x as f32, coord.y as f32);
|
||||
if na::distance(&origin, &dest) >= self.range as f32 {
|
||||
let shape_pos = Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5);
|
||||
if start.distance(&shape_pos) > self.range as f32 + 1. {
|
||||
return u8::MAX;
|
||||
}
|
||||
if let Some((opacity, entities)) = cache.get(&coord) {
|
||||
|
@ -82,14 +83,8 @@ impl Viewshed {
|
|||
return *opacity;
|
||||
}
|
||||
}
|
||||
let tile = map.at(coord.x as usize, coord.y as usize);
|
||||
if tile.blocks_visibility() {
|
||||
cache.insert(coord, (u8::MAX, HashSet::new()));
|
||||
return u8::MAX;
|
||||
}
|
||||
let mut opacity = 0;
|
||||
let mut entities = HashSet::new();
|
||||
let shape_pos = Vec2::new(dest.x + 0.5, dest.y + 0.5);
|
||||
rapier_context.intersections_with_shape(
|
||||
shape_pos,
|
||||
0.,
|
||||
|
@ -97,20 +92,24 @@ impl Viewshed {
|
|||
InteractionGroups::all(),
|
||||
Some(&|v| visible_query.get(v).is_ok()),
|
||||
|entity| {
|
||||
let obstruction = obstructions_query.get(entity).is_ok();
|
||||
if obstruction {
|
||||
entities.clear();
|
||||
}
|
||||
entities.insert(entity);
|
||||
if let Ok(visible) = visible_query.get(entity) {
|
||||
opacity = opacity.max(**visible);
|
||||
}
|
||||
true
|
||||
!obstruction
|
||||
},
|
||||
);
|
||||
for e in &entities {
|
||||
new_visible_entities.insert(*e);
|
||||
}
|
||||
cache.insert(coord, (opacity, entities.clone()));
|
||||
if entities.contains(viewer_entity) {
|
||||
0
|
||||
} else {
|
||||
cache.insert(coord, (opacity, entities));
|
||||
opacity
|
||||
}
|
||||
})),
|
||||
|
@ -119,9 +118,9 @@ impl Viewshed {
|
|||
context.for_each_visible(
|
||||
Coord::new(start.x_i32(), start.y_i32()),
|
||||
&visibility_grid,
|
||||
&visibility_grid,
|
||||
&size,
|
||||
vision_distance,
|
||||
255,
|
||||
u8::MAX,
|
||||
|coord, _directions, _visibility| {
|
||||
new_visible.insert((coord.x, coord.y));
|
||||
},
|
||||
|
@ -230,22 +229,18 @@ fn viewshed_removed(
|
|||
}
|
||||
}
|
||||
|
||||
pub struct VisibilityGrid<'a, D: 'static + Clone + Default + Send + Sync, F>(
|
||||
pub &'a Map<D>,
|
||||
pub RefCell<Box<F>>,
|
||||
);
|
||||
pub struct VisibilityGrid<F>(pub (u32, u32), pub RefCell<Box<F>>);
|
||||
|
||||
impl<'a, D, F> InputGrid for VisibilityGrid<'a, D, F>
|
||||
impl<F> InputGrid for VisibilityGrid<F>
|
||||
where
|
||||
D: 'static + Clone + Default + Send + Sync,
|
||||
F: FnMut(Coord) -> u8,
|
||||
{
|
||||
type Grid = VisibilityGrid<'a, D, F>;
|
||||
type Grid = (u32, u32);
|
||||
|
||||
type Opacity = u8;
|
||||
|
||||
fn size(&self, grid: &Self::Grid) -> Size {
|
||||
Size::new(grid.0.width as u32, grid.0.height as u32)
|
||||
Size::new(grid.0, grid.1)
|
||||
}
|
||||
|
||||
fn get_opacity(&self, _grid: &Self::Grid, coord: Coord) -> Self::Opacity {
|
||||
|
@ -261,6 +256,7 @@ fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
|
|||
Or<(Changed<Transform>, Changed<Visible>)>,
|
||||
>,
|
||||
visible: Query<&Visible>,
|
||||
obstructions: Query<&MapObstruction>,
|
||||
mut viewers: Query<(Entity, &mut Viewshed, &mut VisibleEntities, &Transform)>,
|
||||
map: Query<&Map<D>>,
|
||||
rapier_context: Res<RapierContext>,
|
||||
|
@ -321,6 +317,7 @@ fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
|
|||
&*rapier_context,
|
||||
map,
|
||||
&visible,
|
||||
&obstructions,
|
||||
&mut changed,
|
||||
&mut cache,
|
||||
);
|
||||
|
@ -335,6 +332,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
|
|||
map: Query<&Map<D>>,
|
||||
rapier_context: Res<RapierContext>,
|
||||
visible: Query<&Visible>,
|
||||
obstructions: Query<&MapObstruction>,
|
||||
mut changed: EventWriter<VisibilityChanged>,
|
||||
) {
|
||||
for removed in removed.iter() {
|
||||
|
@ -352,6 +350,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
|
|||
&*rapier_context,
|
||||
map,
|
||||
&visible,
|
||||
&obstructions,
|
||||
&mut changed,
|
||||
&mut cache,
|
||||
);
|
||||
|
@ -430,19 +429,22 @@ impl<D: 'static + Clone + Default + Send + Sync> Default for VisibilityPlugin<D>
|
|||
}
|
||||
}
|
||||
|
||||
pub const UPDATE_VIEWSHED_LABEL: &str = "UPDATE_VIEWSHED";
|
||||
|
||||
impl<D: 'static + Clone + Default + Send + Sync> Plugin for VisibilityPlugin<D> {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_event::<VisibilityChanged>()
|
||||
.add_system(add_visibility_indices::<D>)
|
||||
.add_system_to_stage(CoreStage::PreUpdate, add_visibility_indices::<D>)
|
||||
.add_system_set_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
CoreStage::PreUpdate,
|
||||
SystemSet::new()
|
||||
.with_run_criteria(FixedTimestep::step(0.05))
|
||||
.with_system(update_viewshed::<D>),
|
||||
.with_system(update_viewshed::<D>)
|
||||
.label(UPDATE_VIEWSHED_LABEL),
|
||||
)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, viewshed_removed)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, remove_visible::<D>)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, update_revealed_tiles::<D>)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, log_visible);
|
||||
.add_system_to_stage(CoreStage::PreUpdate, update_revealed_tiles::<D>)
|
||||
.add_system_to_stage(CoreStage::PreUpdate, log_visible);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user