Skip to main content

Architecture Overview

AirPath is designed around three core principles: performance, flexibility, and loose coupling. This page explains how the major systems work together.

System Architecture​

How AirPath Works - Architecture Overview

Data Flow​

When you request a path, here's what happens:

1. Request​

A pathfinding mode (MouseClick or TargetFollow) creates a PathRequest with start/end positions.

User clicks terrain → MouseClickMode → PathRequest created

2. Grid Conversion​

World positions are converted to grid coordinates using GridBoundaryHandler. Out-of-bounds positions are clamped if configured.

World (150, 0, 200) → Grid (9, 12)

3. A* Calculation​

The PathfindingService schedules a Burst-compiled A* job. The job runs on a worker thread using NativeArrays from PathGridData.

Start (9, 12) → A* Algorithm → Path [indices...]

4. Path Conversion​

Grid indices are converted back to world positions with terrain height applied.

Grid path → World path with heights → List<Vector3>

5. Event Publication​

Results are published via PathfindingEventBus. Any subscribed component receives the path.

PathCalculatedEvent → Your agent controller → Agent follows path

Key Components​

PathfindingManager​

The central orchestrator. It:

  • Manages pathfinding modes (MouseClick, TargetFollow)
  • Initializes the PathfindingService
  • Handles mode switching
  • Publishes events for path requests and results

You configure it in the Inspector and rarely interact with it from code.

→ Setup Guide


PathfindingService​

The core pathfinding engine. It:

  • Maintains the pathfinding grid (NativeArrays)
  • Executes Burst-compiled A* jobs
  • Handles coordinate conversion
  • Manages boundary clamping

For direct path calculation without modes, use this class.

→ API Reference


IHeightProvider​

An interface that abstracts terrain data. AirPath doesn't depend on Unity Terrain directly, it asks an IHeightProvider for height data.

Built-in: TerrainHeightProvider for Unity Terrain.

Custom: Implement IHeightProvider for procedural terrain, meshes, or voxels.

→ API Reference


PathfindingEventBus​

A ScriptableObject-based event system. Components communicate through events rather than direct references.

Key events:

  • PathRequestedEvent — Path calculation started
  • PathCalculatedEvent — Path calculation complete
  • PathfindingModeChangedEvent — Mode switched

→ API Reference


Configuration System​

All settings are stored in ScriptableObject assets:

AssetPurpose
PathfindingConfigurationGrid size, cost multipliers, boundary handling
VisualizationConfigurationPath line, cell colors, debug display
PathfindingEventBusEvent system settings

This allows hot-swapping configurations and keeping scenes clean.

Design Principles​

Event-Driven Communication​

Components don't hold direct references to each other. Instead, they:

  • Publish events when something happens
  • Subscribe to events they care about

This makes the system modular — you can remove visualization without breaking pathfinding.

Interface Abstraction​

AirPath uses IHeightProvider instead of depending on Unity Terrain directly. This means:

  • You can use any height source
  • Testing is easier (mock height providers)
  • The core algorithm is terrain-agnostic

DOTS for Performance​

The A* algorithm is:

  • Burst-compiled — Native code performance
  • Job System — Runs on worker threads
  • NativeArrays — No GC allocation during pathfinding

This keeps pathfinding off the main thread and avoids frame hitches.

ScriptableObject Configuration​

Settings live in assets, not scenes. Benefits:

  • Share configurations across scenes
  • Swap presets at runtime
  • Version control friendly
  • No scene modifications for setting changes

Thread Safety​

ComponentThreadNotes
PathfindingManagerMainUnity APIs require main thread
PathfindingServiceMainSchedules jobs, handles results
A* JobWorkerBurst-compiled, no Unity API calls
Event BusMainEvents processed on main thread
Height ProviderMainCalled during initialization

The A* calculation runs on a worker thread, but CalculatePath() blocks until complete. For truly async pathfinding, consider wrapping in a coroutine.

Next Steps​