Skip to main content

SpatialHash

Struct SpatialHash 

Source
pub struct SpatialHash { /* private fields */ }
Expand description

Spatial hash for broad phase collision detection.

Divides 2D space into a uniform grid of cells. Entities are mapped to cells based on their AABBs. This enables O(1) insertion/removal and efficient querying of potential collision pairs.

§Performance

  • Insertion: O(k) where k = number of cells occupied by AABB
  • Removal: O(k)
  • Query pairs: O(n^2) where n = average entities per cell
  • Total query: O(m * n^2) where m = number of occupied cells

§Cell Size Selection

The cell size should be roughly equal to the average object size:

  • Too small: Objects span many cells, increasing overhead
  • Too large: Too many objects per cell, increasing pair checks

For games with mixed object sizes, use the size of the most common objects.

§Examples

use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);

// Insert entities
let player = Entity::new(0, 0);
let enemy = Entity::new(1, 0);

hash.insert(player, Rect::new(0.0, 0.0, 32.0, 32.0));
hash.insert(enemy, Rect::new(50.0, 0.0, 32.0, 32.0));

// Query potential collisions
let pairs = hash.query_pairs();
assert_eq!(pairs.len(), 1);  // Player and enemy are close

Implementations§

Source§

impl SpatialHash

Source

pub fn query_pairs(&mut self) -> Vec<(Entity, Entity)>

Queries for all potential collision pairs.

Returns a list of entity pairs that share at least one cell. These are candidates for narrow phase collision testing.

§Returns

A vector of (Entity, Entity) pairs where the first entity has a lower index than the second (no duplicate pairs).

§Performance

O(m * n^2) where m = number of occupied cells, n = average entities per cell.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);

let e1 = Entity::new(0, 0);
let e2 = Entity::new(1, 0);

hash.insert(e1, Rect::new(0.0, 0.0, 32.0, 32.0));
hash.insert(e2, Rect::new(30.0, 0.0, 32.0, 32.0));

let pairs = hash.query_pairs();
assert_eq!(pairs.len(), 1);  // Overlapping cells
Source

pub fn query_point(&self, point: Vec2) -> Vec<Entity>

Queries for entities near a specific point.

Returns all entities whose AABBs occupy the same cell as the point.

§Arguments
  • point - The query point
§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::{Rect, Vec2};

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));

let nearby = hash.query_point(Vec2::new(10.0, 10.0));
assert_eq!(nearby.len(), 1);
Source

pub fn query_aabb(&self, aabb: Rect) -> Vec<Entity>

Queries for entities overlapping an AABB.

Returns all entities whose AABBs occupy any cell overlapped by the query AABB.

§Arguments
  • aabb - The query AABB
§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));

let nearby = hash.query_aabb(Rect::new(-10.0, -10.0, 50.0, 50.0));
assert_eq!(nearby.len(), 1);
Source

pub fn query_circle(&self, center: Vec2, radius: f32) -> Vec<Entity>

Queries for entities overlapping a circle.

Returns all entities in cells that overlap the circle’s bounding square. This is a conservative estimate - narrow phase should verify actual overlap.

§Arguments
  • center - Circle center position
  • radius - Circle radius
§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::{Rect, Vec2};

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));

let nearby = hash.query_circle(Vec2::new(16.0, 16.0), 20.0);
assert_eq!(nearby.len(), 1);
Source

pub fn cell_size(&self) -> f32

Returns the cell size.

Source

pub fn entity_count(&self) -> usize

Returns the number of entities in the hash.

Source

pub fn cell_count(&self) -> usize

Returns the number of occupied cells.

Source

pub fn is_empty(&self) -> bool

Returns whether the hash is empty.

Source

pub fn contains(&self, entity: Entity) -> bool

Returns whether an entity is in the hash.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

assert!(!hash.contains(entity));
hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));
assert!(hash.contains(entity));
Source

pub fn get_aabb(&self, entity: Entity) -> Option<Rect>

Returns the AABB for an entity, if present.

Source

pub fn stats(&self) -> &SpatialHashStats

Returns a reference to the current statistics.

Source§

impl SpatialHash

Source

pub fn new(cell_size: f32) -> Self

Creates a new spatial hash with the specified cell size.

§Arguments
  • cell_size - Size of each grid cell in world units (e.g., pixels)
§Panics

Panics if cell_size is not positive and finite.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;

// 64-pixel cells (good for medium-sized objects)
let hash = SpatialHash::new(64.0);

// 128-pixel cells (larger objects)
let hash = SpatialHash::new(128.0);
Source

pub fn with_capacity(cell_size: f32, capacity: usize) -> Self

Creates a spatial hash with the specified cell size and initial capacity.

Pre-allocates memory for the specified number of entities, reducing allocations during insertion.

§Arguments
  • cell_size - Size of each grid cell
  • capacity - Expected number of entities
§Examples
use goud_engine::ecs::broad_phase::SpatialHash;

// Pre-allocate for 1000 entities
let hash = SpatialHash::with_capacity(64.0, 1000);
Source

pub fn insert(&mut self, entity: Entity, aabb: Rect)

Inserts an entity with its AABB into the spatial hash.

The entity is added to all cells that its AABB overlaps. If the entity was already in the hash, it is first removed before re-insertion.

§Arguments
  • entity - The entity to insert
  • aabb - The entity’s axis-aligned bounding box
§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);
let aabb = Rect::new(0.0, 0.0, 32.0, 32.0);

hash.insert(entity, aabb);
assert!(hash.contains(entity));
Source

pub fn remove(&mut self, entity: Entity) -> bool

Removes an entity from the spatial hash.

§Arguments
  • entity - The entity to remove
§Returns

true if the entity was present and removed, false otherwise.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));
assert!(hash.remove(entity));
assert!(!hash.contains(entity));
Source

pub fn update(&mut self, entity: Entity, new_aabb: Rect) -> bool

Updates an entity’s AABB in the spatial hash.

This is more efficient than remove + insert when the entity hasn’t moved much, as it can avoid cell changes.

§Arguments
  • entity - The entity to update
  • new_aabb - The entity’s new AABB
§Returns

true if the entity was present and updated, false otherwise.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
let entity = Entity::new(0, 0);

hash.insert(entity, Rect::new(0.0, 0.0, 32.0, 32.0));
hash.update(entity, Rect::new(10.0, 10.0, 32.0, 32.0));
Source

pub fn clear(&mut self)

Clears all entities from the spatial hash.

§Examples
use goud_engine::ecs::broad_phase::SpatialHash;
use goud_engine::ecs::Entity;
use goud_engine::core::math::Rect;

let mut hash = SpatialHash::new(64.0);
hash.insert(Entity::new(0, 0), Rect::new(0.0, 0.0, 32.0, 32.0));

hash.clear();
assert_eq!(hash.entity_count(), 0);

Trait Implementations§

Source§

impl Clone for SpatialHash

Source§

fn clone(&self) -> SpatialHash

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SpatialHash

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for SpatialHash

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> Event for T
where T: Send + Sync + 'static,

Source§

impl<T> QueryState for T
where T: Send + Sync + Clone + 'static,

Source§

impl<T> Resource for T
where T: Send + Sync + 'static,