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 {
|
if spawn_portal {
|
||||||
let x = x as f32;
|
let x = x as f32 + 0.5;
|
||||||
let y = y as f32;
|
let y = y as f32 + 0.5;
|
||||||
if !portals.contains(&(x, y)) {
|
if !portals.contains(&(x, y)) {
|
||||||
portals.push((x, y));
|
portals.push((x, y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for portal in portals {
|
for (x, y) in portals {
|
||||||
let x = portal.0 as f32 + 0.5;
|
|
||||||
let y = portal.1 as f32 + 0.5;
|
|
||||||
let portal = commands
|
let portal = commands
|
||||||
.spawn_bundle(PortalBundle {
|
.spawn_bundle(PortalBundle {
|
||||||
transform: Transform::from_translation(Vec3::new(x, y, 0.)),
|
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();
|
let config = app.world.get_resource::<MapConfig>().unwrap().clone();
|
||||||
app.register_type::<Portal>()
|
app.register_type::<Portal>()
|
||||||
.add_system(spawn_colliders::<D>)
|
.add_system_to_stage(
|
||||||
.add_system(spawn_portals::<D>)
|
CoreStage::PreUpdate,
|
||||||
.add_system(spawn_portal_colliders::<D>);
|
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 {
|
if config.speak_area_descriptions {
|
||||||
app.add_system_to_stage(CoreStage::PostUpdate, area_description);
|
app.add_system_to_stage(CoreStage::PostUpdate, area_description);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::{core::FixedTimestep, prelude::*};
|
use bevy::{core::FixedTimestep, prelude::*};
|
||||||
use bevy_rapier2d::na::{self, Point2};
|
|
||||||
use coord_2d::{Coord, Size};
|
use coord_2d::{Coord, Size};
|
||||||
use shadowcast::{vision_distance, Context, InputGrid};
|
use shadowcast::{vision_distance, Context, InputGrid};
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
commands::RunIfExistsExt,
|
commands::RunIfExistsExt,
|
||||||
core::{Angle, Player, PointLike},
|
core::{Angle, Player, PointLike},
|
||||||
log::Log,
|
log::Log,
|
||||||
map::{ITileType, Map, MapConfig},
|
map::{Map, MapConfig, MapObstruction},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
|
#[derive(Component, Clone, Copy, Debug, Default, Reflect)]
|
||||||
|
@ -57,19 +57,20 @@ impl Viewshed {
|
||||||
rapier_context: &RapierContext,
|
rapier_context: &RapierContext,
|
||||||
map: &Map<D>,
|
map: &Map<D>,
|
||||||
visible_query: &Query<&Visible>,
|
visible_query: &Query<&Visible>,
|
||||||
|
obstructions_query: &Query<&MapObstruction>,
|
||||||
events: &mut EventWriter<VisibilityChanged>,
|
events: &mut EventWriter<VisibilityChanged>,
|
||||||
cache: &mut HashMap<Coord, (u8, HashSet<Entity>)>,
|
cache: &mut HashMap<Coord, (u8, HashSet<Entity>)>,
|
||||||
) {
|
) {
|
||||||
let mut context: Context<u8> = Context::default();
|
let mut context: Context<u8> = Context::default();
|
||||||
let vision_distance = vision_distance::Circle::new(self.range);
|
let vision_distance = vision_distance::Circle::new(self.range);
|
||||||
let shape = Collider::cuboid(0.5 - f32::EPSILON, 0.5 - f32::EPSILON);
|
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 mut new_visible_entities = HashSet::new();
|
||||||
|
let size = (map.width as u32, map.height as u32);
|
||||||
let visibility_grid = VisibilityGrid(
|
let visibility_grid = VisibilityGrid(
|
||||||
map,
|
size,
|
||||||
RefCell::new(Box::new(|coord: Coord| {
|
RefCell::new(Box::new(|coord: Coord| {
|
||||||
let dest = Point2::new(coord.x as f32, coord.y as f32);
|
let shape_pos = Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5);
|
||||||
if na::distance(&origin, &dest) >= self.range as f32 {
|
if start.distance(&shape_pos) > self.range as f32 + 1. {
|
||||||
return u8::MAX;
|
return u8::MAX;
|
||||||
}
|
}
|
||||||
if let Some((opacity, entities)) = cache.get(&coord) {
|
if let Some((opacity, entities)) = cache.get(&coord) {
|
||||||
|
@ -82,14 +83,8 @@ impl Viewshed {
|
||||||
return *opacity;
|
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 opacity = 0;
|
||||||
let mut entities = HashSet::new();
|
let mut entities = HashSet::new();
|
||||||
let shape_pos = Vec2::new(dest.x + 0.5, dest.y + 0.5);
|
|
||||||
rapier_context.intersections_with_shape(
|
rapier_context.intersections_with_shape(
|
||||||
shape_pos,
|
shape_pos,
|
||||||
0.,
|
0.,
|
||||||
|
@ -97,20 +92,24 @@ impl Viewshed {
|
||||||
InteractionGroups::all(),
|
InteractionGroups::all(),
|
||||||
Some(&|v| visible_query.get(v).is_ok()),
|
Some(&|v| visible_query.get(v).is_ok()),
|
||||||
|entity| {
|
|entity| {
|
||||||
|
let obstruction = obstructions_query.get(entity).is_ok();
|
||||||
|
if obstruction {
|
||||||
|
entities.clear();
|
||||||
|
}
|
||||||
entities.insert(entity);
|
entities.insert(entity);
|
||||||
if let Ok(visible) = visible_query.get(entity) {
|
if let Ok(visible) = visible_query.get(entity) {
|
||||||
opacity = opacity.max(**visible);
|
opacity = opacity.max(**visible);
|
||||||
}
|
}
|
||||||
true
|
!obstruction
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
for e in &entities {
|
for e in &entities {
|
||||||
new_visible_entities.insert(*e);
|
new_visible_entities.insert(*e);
|
||||||
}
|
}
|
||||||
|
cache.insert(coord, (opacity, entities.clone()));
|
||||||
if entities.contains(viewer_entity) {
|
if entities.contains(viewer_entity) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
cache.insert(coord, (opacity, entities));
|
|
||||||
opacity
|
opacity
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
|
@ -119,9 +118,9 @@ impl Viewshed {
|
||||||
context.for_each_visible(
|
context.for_each_visible(
|
||||||
Coord::new(start.x_i32(), start.y_i32()),
|
Coord::new(start.x_i32(), start.y_i32()),
|
||||||
&visibility_grid,
|
&visibility_grid,
|
||||||
&visibility_grid,
|
&size,
|
||||||
vision_distance,
|
vision_distance,
|
||||||
255,
|
u8::MAX,
|
||||||
|coord, _directions, _visibility| {
|
|coord, _directions, _visibility| {
|
||||||
new_visible.insert((coord.x, coord.y));
|
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 struct VisibilityGrid<F>(pub (u32, u32), pub RefCell<Box<F>>);
|
||||||
pub &'a Map<D>,
|
|
||||||
pub RefCell<Box<F>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<'a, D, F> InputGrid for VisibilityGrid<'a, D, F>
|
impl<F> InputGrid for VisibilityGrid<F>
|
||||||
where
|
where
|
||||||
D: 'static + Clone + Default + Send + Sync,
|
|
||||||
F: FnMut(Coord) -> u8,
|
F: FnMut(Coord) -> u8,
|
||||||
{
|
{
|
||||||
type Grid = VisibilityGrid<'a, D, F>;
|
type Grid = (u32, u32);
|
||||||
|
|
||||||
type Opacity = u8;
|
type Opacity = u8;
|
||||||
|
|
||||||
fn size(&self, grid: &Self::Grid) -> Size {
|
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 {
|
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>)>,
|
Or<(Changed<Transform>, Changed<Visible>)>,
|
||||||
>,
|
>,
|
||||||
visible: Query<&Visible>,
|
visible: Query<&Visible>,
|
||||||
|
obstructions: Query<&MapObstruction>,
|
||||||
mut viewers: Query<(Entity, &mut Viewshed, &mut VisibleEntities, &Transform)>,
|
mut viewers: Query<(Entity, &mut Viewshed, &mut VisibleEntities, &Transform)>,
|
||||||
map: Query<&Map<D>>,
|
map: Query<&Map<D>>,
|
||||||
rapier_context: Res<RapierContext>,
|
rapier_context: Res<RapierContext>,
|
||||||
|
@ -321,6 +317,7 @@ fn update_viewshed<D: 'static + Clone + Default + Send + Sync>(
|
||||||
&*rapier_context,
|
&*rapier_context,
|
||||||
map,
|
map,
|
||||||
&visible,
|
&visible,
|
||||||
|
&obstructions,
|
||||||
&mut changed,
|
&mut changed,
|
||||||
&mut cache,
|
&mut cache,
|
||||||
);
|
);
|
||||||
|
@ -335,6 +332,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
|
||||||
map: Query<&Map<D>>,
|
map: Query<&Map<D>>,
|
||||||
rapier_context: Res<RapierContext>,
|
rapier_context: Res<RapierContext>,
|
||||||
visible: Query<&Visible>,
|
visible: Query<&Visible>,
|
||||||
|
obstructions: Query<&MapObstruction>,
|
||||||
mut changed: EventWriter<VisibilityChanged>,
|
mut changed: EventWriter<VisibilityChanged>,
|
||||||
) {
|
) {
|
||||||
for removed in removed.iter() {
|
for removed in removed.iter() {
|
||||||
|
@ -352,6 +350,7 @@ fn remove_visible<D: 'static + Clone + Default + Send + Sync>(
|
||||||
&*rapier_context,
|
&*rapier_context,
|
||||||
map,
|
map,
|
||||||
&visible,
|
&visible,
|
||||||
|
&obstructions,
|
||||||
&mut changed,
|
&mut changed,
|
||||||
&mut cache,
|
&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> {
|
impl<D: 'static + Clone + Default + Send + Sync> Plugin for VisibilityPlugin<D> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<VisibilityChanged>()
|
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(
|
.add_system_set_to_stage(
|
||||||
CoreStage::PostUpdate,
|
CoreStage::PreUpdate,
|
||||||
SystemSet::new()
|
SystemSet::new()
|
||||||
.with_run_criteria(FixedTimestep::step(0.05))
|
.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, viewshed_removed)
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, remove_visible::<D>)
|
.add_system_to_stage(CoreStage::PostUpdate, remove_visible::<D>)
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, update_revealed_tiles::<D>)
|
.add_system_to_stage(CoreStage::PreUpdate, update_revealed_tiles::<D>)
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, log_visible);
|
.add_system_to_stage(CoreStage::PreUpdate, log_visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user