Repository navigation
PathfindingEngine
Alexandre Mondaini Calvão edited this page Dec 3, 2025
·
1 revision
The PathfindingEngine is a self-contained pathfinding system that owns entity positions internally. This is the recommended way to use the library.
Unlike traditional approaches where the game owns positions and pathfinding is a separate service, PathfindingEngine manages everything:
- Node graph - Waypoints and their connections
- Entity positions - Where each entity currently is
- Movement - Automatically moves entities along paths
- Spatial indexing - Fast queries for nearby entities/nodes
The engine uses comptime configuration:
const Config = struct {
pub const Entity = u64; // Your entity ID type
pub const Context = *Game; // Passed to callbacks
};
const Engine = pathfinding.PathfindingEngine(Config);// Create
var engine = try Engine.init(allocator);
defer engine.deinit();
// Build graph
try engine.addNode(0, 0, 0);
try engine.addNode(1, 100, 0);
try engine.connectNodes(.{ .omnidirectional = .{ .max_distance = 150, .max_connections = 4 } });
try engine.rebuildPaths();
// Register entities
try engine.registerEntity(player_id, 0, 0, 100.0);
// Game loop
while (running) {
engine.tick(&game, delta_time);
}// Manual ID
try engine.addNode(0, 100, 200); // id=0, x=100, y=200
// Auto-generated ID
const id = try engine.addNodeAuto(100, 200); // returns assigned ID
// Bulk add
const points = [_]pathfinding.NodePoint{
.{ .id = 0, .x = 0, .y = 0 },
.{ .id = 1, .x = 100, .y = 0 },
.{ .id = 2, .x = 200, .y = 0 },
};
try engine.addNodesFromPoints(&points);// Omnidirectional (top-down games)
try engine.connectNodes(.{
.omnidirectional = .{
.max_distance = 150, // Only connect nodes within this distance
.max_connections = 4, // Max edges per node
},
});
// Directional (platformers)
try engine.connectNodes(.{
.directional = .{
.horizontal_range = 60, // Left/right connection range
.vertical_range = 60, // Up/down connection range
},
});// Bidirectional edge
try engine.addEdge(0, 1, true);
// One-way edge (e.g., drop-down platform)
try engine.addEdge(top_node, bottom_node, false);After changing the graph, rebuild Floyd-Warshall:
try engine.rebuildPaths();// Register at position with speed
try engine.registerEntity(entity_id, x, y, speed);
// Remove
engine.unregisterEntity(entity_id);// Position
if (engine.getPosition(entity)) |pos| {
draw(pos.x, pos.y);
}
// Current node
const node = engine.getCurrentNode(entity);
// Speed
const speed = engine.getSpeed(entity);
engine.setSpeed(entity, new_speed);
// Movement state
const moving = engine.isMoving(entity);try engine.requestPath(entity, target_node);engine.cancelPath(entity);// Teleport entity
engine.setPosition(entity, new_x, new_y);Call every frame to update entity positions:
engine.tick(&game_context, delta_time);This:
- Moves all entities along their paths
- Updates spatial indices
- Fires callbacks (node reached, path completed, path blocked)
| Method | Description |
|---|---|
init(allocator) |
Create engine (fallible) |
deinit() |
Free resources |
addNode(id, x, y) |
Add waypoint |
addNodeAuto(x, y) |
Add with auto ID |
addNodesFromPoints(points) |
Bulk add |
removeNode(id) |
Remove waypoint |
addEdge(from, to, bidirectional) |
Add connection |
connectNodes(mode) |
Auto-connect |
rebuildPaths() |
Recompute Floyd-Warshall |
registerEntity(id, x, y, speed) |
Add entity |
unregisterEntity(id) |
Remove entity |
requestPath(entity, node) |
Start moving |
cancelPath(entity) |
Stop moving |
tick(ctx, delta) |
Update frame |
getPosition(entity) |
Get x, y |
setPosition(entity, x, y) |
Teleport |
getSpeed(entity) |
Get speed |
setSpeed(entity, speed) |
Set speed |
isMoving(entity) |
Check if moving |
getCurrentNode(entity) |
Get node ID |
getNodeCount() |
Number of nodes |
getEntityCount() |
Number of entities |