PART 1: CORE | PART 2: MEMORY | PART 3: PRO | PART 4: EXTREME | PART 5: GAME | PART 6: TOOLKIT

Spatial Hashing
Masterclass.

Architecting O(1) performance for Unity games. A deep dive from brute-force chaos to million-particle optimization.

Trent Sterling By Trent Sterling Feb 14, 2026 High-Performance Technical Series
START LEARNING DOWNLOAD API
PART ONE

The Core Concept

Understanding the geometry of optimization.

Step 0: The Web of Death

The Brute Force Nightmare

In a standard, naive collision or proximity system, every object checks every other object. This is O(N²) complexity. At small scales, it's fine. At game-scale, it's a death sentence.

Active Checks: 1,770 O(N²) COMPLEXITY

Toggle the Spatial Hash mode above. Watch the lines collapse. By only checking objects in the same "neighborhood," we reduce the workload from thousands of checks to a handful of clustered tests.

Step 1: The O(N²) Trap

Visualization of Proximity

Imagine 1,000 bullets and 100 enemies. A brute-force system doesn't care if a bullet is 1,000 meters away; it still runs the distance math. Spatial Hashing filters out the irrelevant noise before the math even starts.

Point Cloud: 150 Units Narrow-Phase Filter: ACTIVE
Step 2: Spatial Partitioning

The Grid Strategy

By dividing the world into a fixed grid of "buckets," we can map any 3D coordinate to a specific bucket in constant time. This is the foundation of almost every modern physics engine.

Cell = floor(Position / CellSize)
60
AABBs: 150 Hash Lookups: 0 Optimization: 0%

Tuning the Cell Size is critical. If cells are too small, objects span many buckets. If they are too large, we check too many irrelevant objects. The goal is to maximize the Optimization % shown above.

PART TWO

Memory & Efficiency

Solving the Garbage Collection nightmare in Unity.

Step 3: Zero-GC Patterns

Bucket Pooling

In C#, calling new List<T>() in an Update loop creates "Garbage." When Unity's Garbage Collector runs to clean this up, your game stutters. We solve this by recycling memory.

The Lifecycle of a Pooled Bucket

  1. Request: When an object enters a new cell, we grab a list from a Stack<List<T>>.
  2. Recycle: When a cell becomes empty, we Clear() the list and push it back onto the stack.
  3. Result: Zero allocations. Smooth frames.
// The internal pooling logic
private Stack<List<T>> _pool = new();

private List<T> GetNewList() {
    return _pool.Count > 0 ? _pool.Pop() : new List<T>();
}

private void RecycleList(List<T> list) {
    list.Clear(); // Critical: keep the capacity, dump the items
    _pool.Push(list);
}
Visualizer: Bucket Density

The Density Heatmap

Watch how the hash populates buckets in real-time. The intensity of the color represents how many entities are fighting for attention in that specific memory address.

Entities: 200 Max Bucket Depth: 0
PART THREE

Professional Grade

Data-Oriented Design and Cache Locality.

Step 4: The Müller Pattern

Flattened Arrays & Prefix Sums

For the ultimate performance (as seen in Matthias Müller's Ten Minute Physics), we ditch Dictionaries entirely. We move to Flat Arrays.

1. Count Phase

Iterate all objects once to count how many fall into each cell. No allocations, just integer increments.

2. Prefix Sum Phase

Calculate starting offsets for every cell. This creates a "Map" of contiguous memory for your objects.

Why this wins? Cache Locality.

When you use List<T>, your data is scattered across RAM. The CPU has to "jump" around to find it. When you use Spatial Sorting, your data is lined up perfectly. The CPU pre-fetches the data before you even ask for them.

// Contiguous memory structure
NativeArray<int> cellStart;  // Offsets into the object array
NativeArray<int> sortedObjects; // Objects sorted by their CellID

// Reading a cell is now a single, contiguous memory sweep:
int start = cellStart[cellID];
int end = cellStart[cellID + 1];
for (int i = start; i < end; i++) {
    Process(sortedObjects[i]); // Ultra-fast!
}
PART FOUR

Unity Extreme

Burst, Jobs, and Parallel Power.

Parallel Architecture

Burst & Job System

Spatial hashing is embarrassingly parallel. By using Unity's NativeMultiHashMap and the Burst Compiler, you can move these checks off the main thread and into high-speed C++ level machine code.

Parallel Writing

Use NativeMultiHashMap.ParallelWriter to populate the grid across all CPU cores simultaneously.

Burst Query Kernels

The compiler optimizes the spatial math into SIMD instructions, checking multiple objects per CPU cycle.

[BurstCompile]
struct SpatialQueryJob : IJobParallelFor {
    [ReadOnly] public NativeMultiHashMap<int, EntityData> hash;
    public void Execute(int index) {
        // Run proximity checks at 100x speed
    }
}
PART FIVE

The Arena

Pixel Pickup: A real-time stress test.

PIXELS PICKED: 0
TOTAL PIXELS: 0
AVG PER BUCKET: 0
SPATIAL HASH: ACTIVE (O(N))

PIXEL PICKUP

The Final Exam. Move mouse to steer ship.
Watch the grid flash as the hash calculates collisions.

Tutorial Review:

Every floating pixel and enemy in the arena above is registered into a custom Spatial Hash. The ship queries its local cells to attract pixels (Magnet) and bullets query their cells to destroy enemies. The result is a chaotic experience running at a solid 60fps.

PART SIX

The Toolkit

Ready-to-use API and modules for your Unity projects.

SpatialHash.cs

CORE API

The generic, non-allocating 3D hash engine. Support for AABBs, Sphere queries, and Bucket Pooling.

VIEW SOURCE →

NetworkAOI.cs

A plug-and-play module for PurrNet, FishNet, and Mirror. Optimized Area of Interest management.

VIEW SOURCE →

RoomManager.cs

The logic behind CellGen. Handle portal-based visibility and room-to-room state synchronization.

VIEW SOURCE →

Samples Package

Complete Unity samples including the Collision, Pathfinding, and World Streaming demos from this tutorial.

BROWSE SAMPLES →

Clone the Repository

Get the entire Masterclass project, including the visualizers and the game arena code.

git clone https://github.com/TrentSterling/spatialhash.git
Summary

Real-World Power

Netcode AOI

Perfect for PurrNet. Synchronize only the entities in a player's spatial "bubble." Save 90% of your network bandwidth.

Room Sync

Solve Mikkel's "Room Connectivity" problem. Instantly find "Which room am I in?" and propagate state through connected portals in $O(1)$.