use bevy::prelude::*;
pub mod algorithms;
mod spatial_query;
mod spatial_query_iterator;
pub mod prelude {
pub use crate::spatial_query::SpatialQuery;
pub use crate::spatial_query_iterator::SpatialQueryIterator;
pub use crate::{SpatialLookupAlgorithm, SpatialLookupState, SpatialQueriesPlugin};
}
pub struct SpatialQueriesPlugin;
#[derive(SystemSet, Clone, Debug, Hash, PartialEq, Eq)]
pub struct PrepareSpatialLookup;
impl Plugin for SpatialQueriesPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(SpatialLookupState::default())
.add_systems(First, prepare_spatial_lookup.in_set(PrepareSpatialLookup));
}
}
pub trait SpatialLookupAlgorithm {
fn prepare(&mut self, entities: &[(Entity, Vec3)]);
fn entities_in_radius(&self, sample_point: Vec3, radius: f32) -> Vec<Entity>;
fn debug_gizmos(&self, _gizmos: &mut Gizmos) {}
}
#[derive(Resource)]
pub struct SpatialLookupState {
entities: Vec<(Entity, Vec3)>,
pub algorithm: Box<dyn SpatialLookupAlgorithm + Send + Sync>,
}
impl Default for SpatialLookupState {
fn default() -> Self {
SpatialLookupState {
entities: Vec::new(),
algorithm: Box::new(algorithms::Naive::default()),
}
}
}
impl SpatialLookupState {
pub fn with_algorithm<T: SpatialLookupAlgorithm + Send + Sync + 'static>(algorithm: T) -> Self {
Self {
entities: vec![],
algorithm: Box::new(algorithm),
}
}
pub fn entities_in_radius(&self, sample_point: Vec3, radius: f32) -> Vec<Entity> {
self.algorithm.entities_in_radius(sample_point, radius)
}
fn prepare_algorithm(&mut self) {
self.algorithm.prepare(&self.entities);
}
}
pub fn prepare_spatial_lookup(
all_entities: Query<(Entity, &GlobalTransform)>,
mut lookup_state: ResMut<SpatialLookupState>,
) {
lookup_state.entities.clear();
for (entity, transform) in &all_entities {
lookup_state
.entities
.push((entity, transform.translation()));
}
lookup_state.prepare_algorithm();
}
pub fn draw_spatial_lookup_gizmos(lookup_state: Res<SpatialLookupState>, mut gizmos: Gizmos) {
lookup_state.algorithm.debug_gizmos(&mut gizmos);
}