mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Switch agent target search to use a spatial grid, add convience method for querying the aabr of a circle
This commit is contained in:
parent
a76fdbc325
commit
e750c9d570
@ -52,8 +52,6 @@ impl SpatialGrid {
|
||||
/// provided axis aligned bounding region
|
||||
/// NOTE: for best optimization of the iterator use `for_each` rather than a
|
||||
/// for loop
|
||||
// TODO: a circle would be tighter (how efficient would it be to query the cells
|
||||
// intersecting a circle?)
|
||||
pub fn in_aabr<'a>(&'a self, aabr: Aabr<i32>) -> impl Iterator<Item = specs::Entity> + 'a {
|
||||
let iter = |max_entity_radius, grid: &'a hashbrown::HashMap<_, _>, lg2_cell_size| {
|
||||
// Add buffer for other entity radius
|
||||
@ -76,6 +74,32 @@ impl SpatialGrid {
|
||||
))
|
||||
}
|
||||
|
||||
/// Get an iterator over the entities overlapping the
|
||||
/// axis aligned bounding region that contains the provided circle
|
||||
/// NOTE: for best optimization of the iterator use `for_each` rather than a
|
||||
/// for loop
|
||||
// TODO: using the circle directly would be tighter (how efficient would it be
|
||||
// to query the cells intersecting a circle?) (note: if doing this rename
|
||||
// the function)
|
||||
pub fn in_circle_aabr<'a>(
|
||||
&'a self,
|
||||
center: Vec2<f32>,
|
||||
radius: f32,
|
||||
) -> impl Iterator<Item = specs::Entity> + 'a {
|
||||
let center = center.map(|e| e as i32);
|
||||
let radius = radius.ceil() as i32;
|
||||
// From conversion of center above
|
||||
const CENTER_TRUNCATION_ERROR: i32 = 1;
|
||||
let max_dist = radius + CENTER_TRUNCATION_ERROR;
|
||||
|
||||
let aabr = Aabr {
|
||||
min: center - max_dist,
|
||||
max: center + max_dist,
|
||||
};
|
||||
|
||||
self.in_aabr(aabr)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.grid.clear();
|
||||
self.large_grid.clear();
|
||||
|
@ -206,6 +206,7 @@ impl State {
|
||||
ecs.insert(EventBus::<LocalEvent>::default());
|
||||
ecs.insert(game_mode);
|
||||
ecs.insert(Vec::<common::outcome::Outcome>::new());
|
||||
ecs.insert(common::CachedSpatialGrid::default());
|
||||
|
||||
let slow_limit = thread_pool.current_num_threads().max(2) as u64;
|
||||
let slow_limit = slow_limit / 2 + slow_limit / 4;
|
||||
|
@ -144,7 +144,7 @@ pub struct PhysicsRead<'a> {
|
||||
#[derive(SystemData)]
|
||||
pub struct PhysicsWrite<'a> {
|
||||
physics_metrics: WriteExpect<'a, PhysicsMetrics>,
|
||||
cached_spatial_grid: WriteExpect<'a, common::CachedSpatialGrid>,
|
||||
cached_spatial_grid: Write<'a, common::CachedSpatialGrid>,
|
||||
physics_states: WriteStorage<'a, PhysicsState>,
|
||||
positions: WriteStorage<'a, Pos>,
|
||||
velocities: WriteStorage<'a, Vel>,
|
||||
@ -343,27 +343,17 @@ impl<'a> PhysicsData<'a> {
|
||||
let mut entity_entity_collision_checks = 0;
|
||||
let mut entity_entity_collisions = 0;
|
||||
|
||||
let aabr = {
|
||||
let center = previous_cache.center.xy().map(|e| e as i32);
|
||||
let radius = previous_cache.collision_boundary.ceil() as i32;
|
||||
// From conversion of center above
|
||||
const CENTER_TRUNCATION_ERROR: i32 = 1;
|
||||
let max_dist = radius + CENTER_TRUNCATION_ERROR;
|
||||
|
||||
Aabr {
|
||||
min: center - max_dist,
|
||||
max: center + max_dist,
|
||||
}
|
||||
};
|
||||
let query_center = previous_cache.center.xy();
|
||||
let query_radius = previous_cache.collision_boundary;
|
||||
|
||||
spatial_grid
|
||||
.in_aabr(aabr)
|
||||
.in_circle_aabr(query_center, query_radius)
|
||||
.filter_map(|entity| {
|
||||
read.uids
|
||||
.get(entity)
|
||||
.zip(positions.get(entity))
|
||||
.zip(previous_phys_cache.get(entity))
|
||||
.zip(read.masses.get(entity))
|
||||
.and_then(|l| positions.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| previous_phys_cache.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| read.masses.get(entity).map(|r| (l, r)))
|
||||
.map(|(((uid, pos), previous_cache), mass)| {
|
||||
(
|
||||
entity,
|
||||
@ -886,27 +876,17 @@ impl<'a> PhysicsData<'a> {
|
||||
}
|
||||
};
|
||||
// Collide with terrain-like entities
|
||||
let aabr = {
|
||||
let center = path_sphere.center.xy().map(|e| e as i32);
|
||||
let radius = path_sphere.radius.ceil() as i32;
|
||||
// From conversion of center above
|
||||
const CENTER_TRUNCATION_ERROR: i32 = 1;
|
||||
let max_dist = radius + CENTER_TRUNCATION_ERROR;
|
||||
|
||||
Aabr {
|
||||
min: center - max_dist,
|
||||
max: center + max_dist,
|
||||
}
|
||||
};
|
||||
let query_center = path_sphere.center.xy();
|
||||
let query_radius = path_sphere.radius;
|
||||
voxel_collider_spatial_grid
|
||||
.in_aabr(aabr)
|
||||
.in_circle_aabr(query_center, query_radius)
|
||||
.filter_map(|entity| {
|
||||
positions
|
||||
.get(entity)
|
||||
.zip(velocities.get(entity))
|
||||
.zip(previous_phys_cache.get(entity))
|
||||
.zip(read.colliders.get(entity))
|
||||
.zip(orientations.get(entity))
|
||||
.and_then(|l| velocities.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| previous_phys_cache.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| read.colliders.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| orientations.get(entity).map(|r| (l, r)))
|
||||
.map(|((((pos, vel), previous_cache), collider), ori)| {
|
||||
(entity, pos, vel, previous_cache, collider, ori)
|
||||
})
|
||||
|
@ -68,6 +68,7 @@ struct AgentData<'a> {
|
||||
is_gliding: bool,
|
||||
health: Option<&'a Health>,
|
||||
char_state: &'a CharacterState,
|
||||
cached_spatial_grid: &'a common::CachedSpatialGrid,
|
||||
}
|
||||
|
||||
#[derive(SystemData)]
|
||||
@ -76,6 +77,7 @@ pub struct ReadData<'a> {
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
time: Read<'a, Time>,
|
||||
cached_spatial_grid: Read<'a, common::CachedSpatialGrid>,
|
||||
group_manager: Read<'a, group::GroupManager>,
|
||||
energies: ReadStorage<'a, Energy>,
|
||||
positions: ReadStorage<'a, Pos>,
|
||||
@ -284,6 +286,7 @@ impl<'a> System<'a> for Sys {
|
||||
is_gliding,
|
||||
health: read_data.healths.get(entity),
|
||||
char_state,
|
||||
cached_spatial_grid: &read_data.cached_spatial_grid,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
@ -1374,10 +1377,19 @@ impl<'a> AgentData<'a> {
|
||||
) {
|
||||
agent.action_timer = 0.0;
|
||||
|
||||
// Search for new targets (this looks expensive, but it's only run occasionally)
|
||||
// TODO: Replace this with a better system that doesn't consider *all* entities
|
||||
let target = (&read_data.entities, &read_data.positions, &read_data.healths, &read_data.stats, &read_data.inventories, read_data.alignments.maybe(), read_data.char_states.maybe())
|
||||
.join()
|
||||
// Search area
|
||||
let target = self.cached_spatial_grid.0
|
||||
.in_circle_aabr(self.pos.0.xy(), SEARCH_DIST)
|
||||
.filter_map(|entity| {
|
||||
read_data.positions
|
||||
.get(entity)
|
||||
.and_then(|l| read_data.healths.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| read_data.stats.get(entity).map(|r| (l, r)))
|
||||
.and_then(|l| read_data.inventories.get(entity).map(|r| (l, r)))
|
||||
.map(|(((pos, health), stats), inventory)| {
|
||||
(entity, pos, health, stats, inventory, read_data.alignments.get(entity), read_data.char_states.get(entity))
|
||||
})
|
||||
})
|
||||
.filter(|(e, e_pos, e_health, e_stats, e_inventory, e_alignment, char_state)| {
|
||||
let mut search_dist = SEARCH_DIST;
|
||||
let mut listen_dist = LISTEN_DIST;
|
||||
@ -1436,6 +1448,7 @@ impl<'a> AgentData<'a> {
|
||||
|
||||
})
|
||||
// Can we even see them?
|
||||
// TODO: limit ray cast distance to the amount needed to tell if we can see the entity
|
||||
.filter(|(_, e_pos, _, _, _, _, _)| read_data.terrain
|
||||
.ray(self.pos.0 + Vec3::unit_z(), e_pos.0 + Vec3::unit_z())
|
||||
.until(Block::is_opaque)
|
||||
@ -1443,15 +1456,12 @@ impl<'a> AgentData<'a> {
|
||||
.0 >= e_pos.0.distance(self.pos.0))
|
||||
.min_by_key(|(_, e_pos, _, _, _, _, _)| (e_pos.0.distance_squared(self.pos.0) * 100.0) as i32) // TODO choose target by more than just distance
|
||||
.map(|(e, _, _, _, _, _, _)| e);
|
||||
if let Some(target) = target {
|
||||
agent.target = Some(Target {
|
||||
target,
|
||||
hostile: true,
|
||||
selected_at: read_data.time.0,
|
||||
})
|
||||
} else {
|
||||
agent.target = None;
|
||||
}
|
||||
|
||||
agent.target = target.map(|target| Target {
|
||||
target,
|
||||
hostile: true,
|
||||
selected_at: read_data.time.0,
|
||||
});
|
||||
}
|
||||
|
||||
fn jump_if(&self, controller: &mut Controller, condition: bool) {
|
||||
|
Loading…
Reference in New Issue
Block a user