Repository navigation
Callbacks
Alexandre Mondaini Calvão edited this page Dec 3, 2025
·
1 revision
The PathfindingEngine supports callbacks to notify your game when path-related events occur.
| Callback | Triggered When |
|---|---|
on_node_reached |
Entity arrives at any waypoint along its path |
on_path_completed |
Entity reaches final destination |
on_path_blocked |
No path available to requested destination |
const Config = struct {
pub const Entity = u64;
pub const Context = *Game;
};
const Engine = pathfinding.PathfindingEngine(Config);
fn onNodeReached(game: *Game, entity: u64, node: u32) void {
// Called each time entity reaches a waypoint
}
fn onPathCompleted(game: *Game, entity: u64, node: u32) void {
// Called when entity reaches final destination
game.score += 10;
}
fn onPathBlocked(game: *Game, entity: u64, node: u32) void {
// Called when no path exists
game.showMessage("Can't reach destination!");
}
pub fn main() !void {
var engine = try Engine.init(allocator);
// Assign callbacks
engine.on_node_reached = onNodeReached;
engine.on_path_completed = onPathCompleted;
engine.on_path_blocked = onPathBlocked;
// ...
}All callbacks have the same signature:
fn callback(context: Context, entity: Entity, node: NodeId) void-
context- Your game context (fromConfig.Context) -
entity- The entity that triggered the event -
node- The relevant node ID
Callbacks are fired during tick(), after all entity positions are updated:
engine.tick(&game, delta);
// ^ Callbacks fire here, at the end of tickThis ensures:
- All positions are consistent when callbacks run
- Callbacks can safely query other entities
- No iterator invalidation issues
const PatrolState = struct {
current_target: usize = 0,
patrol_points: []const u32,
};
fn onPatrolNodeReached(game: *Game, entity: u64, node: u32) void {
const patrol = game.getPatrol(entity) orelse return;
// Move to next patrol point
patrol.current_target = (patrol.current_target + 1) % patrol.patrol_points.len;
const next = patrol.patrol_points[patrol.current_target];
game.engine.requestPath(entity, next) catch {};
}fn onNodeReached(game: *Game, entity: u64, node: u32) void {
// Check if this node has a quest trigger
if (game.quest_triggers.get(node)) |quest_id| {
if (game.isPlayer(entity)) {
game.triggerQuest(quest_id);
}
}
}fn onPathCompleted(game: *Game, entity: u64, node: u32) void {
const entity_type = game.getEntityType(entity);
switch (entity_type) {
.player => {
game.score += 10;
game.playSound(.destination_reached);
},
.enemy => {
// Enemy reached its target
game.alertPlayer();
},
else => {},
}
}All callbacks are optional. If not set, nothing happens:
var engine = try Engine.init(allocator);
// No callbacks set - events are silently ignoredCallbacks run after the main update loop, so it's safe to:
- Query entity positions
- Request new paths
- Modify game state
However, avoid:
- Calling
tick()recursively - Removing the entity that triggered the callback (defer to next frame)