More tweaks to pathfinding and visibility.

This commit is contained in:
Nolan Darilek 2021-06-16 11:28:06 -05:00
parent 2e805b3b8b
commit 98bca77f66
2 changed files with 128 additions and 44 deletions

View File

@ -45,7 +45,7 @@ fn calculate_path(
mut commands: Commands,
pool: Res<AsyncComputeTaskPool>,
mut calculating: Local<HashMap<Entity, Receiver<Path>>>,
query: Query<(Entity, &Destination, &Coordinates), Changed<Destination>>,
query: Query<(Entity, &Destination, &Coordinates), Without<Path>>,
destinations: Query<&Destination>,
map: Query<&Map>,
) {
@ -55,6 +55,8 @@ fn calculate_path(
if let Ok(path) = rx.try_recv() {
commands.entity(*entity).insert(path);
calculating.remove(&entity);
} else {
commands.entity(*entity).remove::<Destination>();
}
} else {
calculating.remove(&entity);
@ -104,7 +106,13 @@ fn negotiate_path(
if let Some(upcoming) = iter.next() {
new_path = vec![start_i32];
new_path.append(&mut upcoming.to_vec());
} else {
commands.entity(entity).remove::<Path>();
velocity.linvel = Vec2::ZERO.into();
}
} else {
commands.entity(entity).remove::<Path>();
velocity.linvel = Vec2::ZERO.into();
}
**path = new_path;
if path.len() >= 2 {
@ -113,7 +121,7 @@ fn negotiate_path(
position.position.translation.y,
);
let next = path[1];
let next = Vec2::new(next.0 as f32, next.1 as f32);
let next = Vec2::new(next.0 as f32 + 0.5, next.1 as f32 + 0.5);
if rotation_speed.is_some() {
let v = next - start;
let angle = v.y.atan2(v.x);
@ -121,12 +129,12 @@ fn negotiate_path(
}
let mut direction = next - start;
direction = direction.normalize();
direction *= speed.0;
direction *= **speed;
velocity.linvel = direction.into();
} else {
commands.entity(entity).remove::<Path>();
commands.entity(entity).remove::<Destination>();
velocity.linvel = Vec2::ZERO.into();
commands.entity(entity).remove::<Destination>();
}
}
}

View File

@ -94,7 +94,82 @@ where
}
}
fn update_viewshed<'a>(
fn update_viewshed(
viewer_entity: &Entity,
viewshed: &mut Viewshed,
start: &dyn PointLike,
query_pipeline: &QueryPipeline,
collider_query: &QueryPipelineColliderComponentsQuery,
map: &Map,
blocks_visibility: &Query<&BlocksVisibility>,
) {
let mut context: Context<u8> = 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 shape = Cuboid::new(Vec2::new(0.49, 0.49).into());
let range = viewshed.range as f32;
let collider_set = QueryPipelineColliderComponentsSet(&collider_query);
let visibility_grid = VisibilityGrid(map, |coord: Coord| {
if coord.distance(start) > range {
return 255;
}
let shape_pos = (Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5), 0.);
let mut opacity = 0;
query_pipeline.intersections_with_shape(
&collider_set,
&shape_pos.into(),
&shape,
InteractionGroups::all(),
Some(&|v| v.entity() != *viewer_entity && blocks_visibility.get(v.entity()).is_ok()),
|_| {
opacity = 255;
false
},
);
opacity
});
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<'a>(
visible: Query<(&Coordinates, &BlocksVisibility), Changed<Coordinates>>,
mut viewers: Query<(Entity, &mut Viewshed, &Coordinates)>,
map: Query<&Map>,
query_pipeline: Res<QueryPipeline>,
collider_query: QueryPipelineColliderComponentsQuery,
blocks_visibility: Query<&BlocksVisibility>,
) {
for (coordinates, _) in visible.iter() {
for (viewer_entity, mut viewshed, start) in viewers.iter_mut() {
if coordinates.distance(start) > viewshed.range as f32 {
continue;
}
if let Ok(map) = map.single() {
update_viewshed(
&viewer_entity,
&mut viewshed,
start,
&*query_pipeline,
&collider_query,
map,
&blocks_visibility,
);
}
}
}
}
fn update_viewshed_for_start<'a>(
mut viewers: Query<(Entity, &mut Viewshed, &Coordinates), Changed<Coordinates>>,
map: Query<&Map>,
query_pipeline: Res<QueryPipeline>,
@ -102,49 +177,45 @@ fn update_viewshed<'a>(
blocks_visibility: Query<&BlocksVisibility>,
) {
for (viewer_entity, mut viewshed, start) in viewers.iter_mut() {
for map in map.iter() {
let mut context: Context<u8> = 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 collider_set = QueryPipelineColliderComponentsSet(&collider_query);
let shape = Cuboid::new(Vec2::new(0.49, 0.49).into());
let range = viewshed.range as f32;
let visibility_grid = VisibilityGrid(map, |coord: Coord| {
if coord.distance(start) > range {
return 255;
}
let shape_pos = (Vec2::new(coord.x as f32 + 0.5, coord.y as f32 + 0.5), 0.);
let mut opacity = 0;
query_pipeline.intersections_with_shape(
&collider_set,
&shape_pos.into(),
&shape,
InteractionGroups::all(),
Some(&|v| {
v.entity() != viewer_entity && blocks_visibility.get(v.entity()).is_ok()
}),
|_| {
opacity = 255;
false
},
);
opacity
});
context.for_each_visible(
coord,
&visibility_grid,
&visibility_grid,
vision_distance,
255,
|coord, _directions, _visibility| {
viewshed.visible.insert((coord.x, coord.y));
},
if let Ok(map) = map.single() {
update_viewshed(
&viewer_entity,
&mut viewshed,
start,
&*query_pipeline,
&collider_query,
map,
&blocks_visibility,
);
}
}
}
fn remove_blocks_visibility<'a>(
removed: RemovedComponents<BlocksVisibility>,
mut viewers: Query<(Entity, &mut Viewshed, &Coordinates)>,
map: Query<&Map>,
query_pipeline: Res<QueryPipeline>,
collider_query: QueryPipelineColliderComponentsQuery,
blocks_visibility: Query<&BlocksVisibility>,
) {
for _ in removed.iter() {
for (viewer_entity, mut viewshed, start) in viewers.iter_mut() {
if let Ok(map) = map.single() {
update_viewshed(
&viewer_entity,
&mut viewshed,
start,
&*query_pipeline,
&collider_query,
map,
&blocks_visibility,
);
}
}
}
}
fn update_visible_and_revealed_tiles(
mut map: Query<(&Map, &mut RevealedTiles, &mut VisibleTiles)>,
viewers: Query<&Viewshed, With<Player>>,
@ -241,7 +312,12 @@ pub struct VisibilityPlugin;
impl Plugin for VisibilityPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_system(add_visibility_indices.system())
.add_system_to_stage(CoreStage::PostUpdate, update_viewshed.system())
.add_system_to_stage(
CoreStage::PostUpdate,
update_viewshed_for_coordinates.system(),
)
.add_system_to_stage(CoreStage::PostUpdate, update_viewshed_for_start.system())
.add_system_to_stage(CoreStage::PostUpdate, remove_blocks_visibility.system())
.add_system_to_stage(
CoreStage::PostUpdate,
update_visible_and_revealed_tiles.system(),