Pathfinding
advanced scriptingVoxel Play 4 · Scripting / API
VoxelPlayEnvironment. Access via VoxelPlayEnvironment.instance.
Requesting paths
VoxelPathRequest FindPath(Vector3d start, Vector3d end, VoxelPathOptions options = default, Action<VoxelPathRequest> onComplete = null)Requests a path between two positions, resolved asynchronously on worker threads. The callback always fires on the main thread. Waypoints are voxel cell centers at feet level; agents add their own half height.
- start
- Path origin (feet position).
- end
- Path destination.
- options
- Optional search parameters (see VoxelPathOptions below).
- onComplete
- Invoked on the main thread when the request resolves.
void ReleasePathRequest(VoxelPathRequest request)Returns a request to the internal pool. Call it when the request and its path are no longer referenced to avoid allocations.
bool IsPathStillValid(VoxelPathRequest request)Returns false when any chunk crossed by the path corridor changed, unloaded or newly appeared since the path was computed. Agents typically re-request the path when this returns false.
Environment properties
int pathfindingThreadsNumber of worker threads. 0 = automatic based on processor count.
int pathfindingMaxSearchNodesMaximum cells explored per search before returning a partial path (default 6000).
int pathfindingCallbackBudgetMsMilliseconds per frame spent delivering completed path callbacks (default 2).
int pathfindingDefaultWadeDepthFluid cells deep agents wade through by default, counted from the feet (default 1). Requests and agents can override it; the head always stays out of the fluid.
int pathfindingPendingCountNumber of path requests currently queued or computing.
float pathfindingObstacleMemorySeconds a scene collider reported by a blocked agent stays out of path searches (default 5). Every new bump on it renews the time.
int pathfindingObstacleCountNumber of positions currently blocked for path searches, reported by agents or by scripts. Expired timed entries may linger until the next sweep.
Blocking areas
PathfindingBlockHandle PathfindingBlockArea(Bounds area, float lifetime = 0)Keeps every position whose center lies inside the world space volume out of path searches. Lifetime 0 blocks until PathfindingUnblockArea is called; a positive value expires on its own. Movement is not affected: agents already on the way walk through, new paths go around, and the paths that crossed the area are recomputed by their agents.
PathfindingBlockHandle PathfindingBlockPositions(List<Vector3d> positions, float lifetime = 0)Same for a list of world positions, one per voxel position.
PathfindingBlockHandle PathfindingBlockPositions(List<VoxelIndex> indices, float lifetime = 0)Same for a list of voxel indices.
void PathfindingUnblockArea(PathfindingBlockHandle handle)Releases a block. Positions shared with other permanent blocks stay blocked until those are released too; timed entries on the same positions run their own time.
VoxelPathRequest
VoxelPathStatus statusIdle, Queued, Computing, Ready, Failed or Canceled.
List<Vector3d> pathResulting waypoints: voxel cell centers at feet level.
bool isPartialTrue when the search hit its node budget or an unreachable target and the path leads to the closest reachable cell instead.
void Cancel()Cancels the request; if it is already computing, the result is discarded and no callback fires.
VoxelPathOptions
int maxDropMaximum fall height per step (0 = default, 3).
int maxSearchNodesPer-request override of the environment default (0 = use default).
int agentHeightVertical clearance in voxels required by the agent (0 = default, 2).
int maxSnapDownDistance scanned below start and end to find the ground (0 = default, 4).
FluidTraversal fluidTraversalHow the search treats fluids: UseEnvironmentDefault wades up to the environment default depth, Forbidden never enters fluid cells, Wade uses maxWadeDepth, Swim sinks swimDepth cells and floats at the surface of deeper fluid.
int maxWadeDepthWade mode only: fluid cells tolerated from the feet up (0 = environment default). Always capped to agentHeight - 1 so the head stays out.
int swimDepthSwim mode only: body cells under the surface while floating, up to agentHeight (head at the surface); 0 = default (1), negative = whole body above the water. The agent stands on the bed when it is that close and floats otherwise. Submerged start or end points resolve to the float position at the surface of their column.
bool noDiagonalsRestricts movement to the four cardinal directions.
bool noPartialPathsFail instead of returning a partial path when the target is unreachable.
float crowdAvoidanceExtra cost per agent occupying a cell (0 = default 1, negative = disabled). Requires agents publishing their cells, which VoxelPlayPathAgent does automatically.
VoxelPlayPathAgent component
Transform targetTransform the agent chases. Leave empty and call SetDestination for fixed goals.
void SetDestination(Vector3 destination)Sends the agent to a fixed position. Overrides the chase until ClearDestination is called.
void ClearDestination()Cancels a SetDestination order; the agent resumes chasing its target, if any.
void AddKnockback(Vector3 velocity)Applies a horizontal shove. The agent slides with the usual movement rules (stops at walls and forbidden fluids, can fall off ledges) and transfers part of the momentum to agents it rams.
bool hasPathTrue while the agent has waypoints left to follow.
static IReadOnlyList<VoxelPlayPathAgent> ActiveAgentsAll enabled path agents, for custom queries (shoves, selections, effects).
float speed, turnSpeed, stoppingDistance, heightOffset; int maxDrop, agentHeightMovement tuning: walking and turning speed, stop distance to the target, pivot height above the feet, tallest accepted drop and vertical clearance in voxels (path searches use the same height).
float repathInterval, targetMoveRepathDistance, stuckRepathTimeRepath tuning. Agents stagger their checks automatically so large crowds never recompute on the same frame; stuck agents force a new path after some seconds without progress.
FluidTraversal fluidTraversal; int maxWadeDepth, swimDepthFluid behavior for both path searches and movement: wade using the world default depth, never enter fluids, wade down to maxWadeDepth cells, or swim (sink swimDepth cells, default 1, and float over deeper fluid). Floating agents follow the surface when the water level changes.
PathAgentFluidState fluidState; bool isInFluid, nextWaypointInFluidWater situation of the walk cell: Dry, Wading (feet in fluid, standing on the bed) or Floating (Swim mode, carried by the surface). nextWaypointInFluid is true when the upcoming waypoint stands in or floats on fluid, so the plunge can be anticipated. These follow the grid feet, which change slightly before the transform reaches them.
event PathAgentFluidStateEvent OnFluidStateChangedFired on every fluidState transition with (agent, previous state, new state). Fires once after enabling when the agent does not start dry.
event PathAgentStepEvent OnStepUp, OnDropVertical steps of the feet cell with (agent, cells): climbing a step or being pushed up by a block landing on top, and walking or being shoved off a ledge or the floor dug away. They fire when the grid feet change; the transform follows with its climb or fall motion, so a jump animation or a vertical impulse can start right away. Entering or leaving floating water moves the feet too and reports here (use OnFluidStateChanged to tell it apart), and a fall into the void with no floor within 64 cells reports nothing.
event PathAgentEvent OnTargetAcquired, OnTargetLost, OnDestinationReachedChase lifecycle (agent): the target enters perception and the chase starts, the target is lost (out of range, out of sight or removed), and the agent gets within stoppingDistance of its goal (target, fixed destination or home). Arrival fires once per goal and again after a new path when the goal moves.
PathAgentPerceptionState perceptionState; int feetYIdle, Chasing or ReturningHome, and the Y of the cell the feet stand on (the transform sits heightOffset above it and follows it with a short lag).
protected virtual float GetMoveSpeed(), GetTurnSpeed()Speeds used each frame by a derived class; the defaults return speed and turnSpeed. Override them to slow down in water (fluidState), sprint while chasing (perceptionState) or apply any custom condition.
protected virtual Update, UpdateGrounding, UpdatePerception, Acquire, LoseTarget, TargetVisible, TryRepath, OnPathReady, CheckReturnedHome, FollowPath, TryMoveTo, SettleVertical, CheckArrival, UpdateKnockback, UpdateEscapeFromColliders, FindOverlap, BlockedByCollider, ApplySeparation, UpdateFluidState, CheckStuck, ResolveInitialFeetExtension points: every step of the agent update is a protected virtual method and the working state (env, currentFeet, currentPath, waypointIndex, perception, knockback, forceRepath...) is protected, together with the grid helpers CellInfo, IsSolid, IsStandableAt and TryResolveFeet. Derive from VoxelPlayPathAgent, override the piece you need and call the base implementation for the rest.
float detectionRange, loseTargetDistance, loseSightTime; bool requireLineOfSight, returnHomeOptional perception, all off by default (the agent always knows where its target is): acquire targets only within detectionRange, require an unobstructed voxel line of sight to start or keep the chase, give up beyond loseTargetDistance or after loseSightTime seconds hidden, and optionally walk back to the spawn point.
bool separation; float separationRadius, separationStrengthCrowd separation: agents softly push each other apart through a shared spatial grid, with no physics involved. Pushes that would enter a solid column or forbidden fluid are discarded. Scales to thousands of agents.
float crowdAvoidanceExtra path cost per agent standing on a cell. New searches route around crowded corridors when an alternative exists. Negative disables it.
bool blockedByColliders; LayerMask blockingLayers; float colliderStepHeightScene colliders (props, debris, the player) on the blocking layers block movement; colliders reaching no higher than colliderStepHeight above the feet (carpets, pressure plates) are walked over instead. Colliders belonging to other path agents never block, whatever their layer. The voxel terrain itself is always handled by the grid rules. A collider that stops the agent is reported to the shared obstacle table for pathfindingObstacleMemory seconds and the agent replans at once, so it and every other agent route around it (see Blocking areas); the collider of the agent's own target is never reported.
float knockbackDeceleration, knockbackTransferHow quickly a shove loses speed, and how much of it passes on to agents rammed along the way (chain effect).
bool debugTracesPrints repaths, blocked moves and stuck warnings for this agent to the console.
Voxel definition
float pathfindCostNative pathfinding cost, editable in the inspector for terrain voxels, fluids and custom voxels. Ground: 1 = normal, higher = avoided, below 1 = preferred, 0 = impassable. Fluids: wading penalty, 0 = agents never enter (bundled lavas ship with 0). Custom voxels: crossing penalty, 0 = blocks agents.
Examples
Asynchronous path request with a callback:
using VoxelPlay;
VoxelPlayEnvironment env = VoxelPlayEnvironment.instance;
env.FindPath(transform.position, targetPosition, default, request => {
if (request.status == VoxelPathStatus.Ready) {
foreach (Vector3d waypoint in request.path) {
// feed waypoints to your character movement
}
}
env.ReleasePathRequest(request);
});
Spawning a chasing agent entirely from code:
GameObject mob = GameObject.CreatePrimitive(PrimitiveType.Capsule);
Destroy(mob.GetComponent<Collider>()); // agents move kinematically, no physics needed
mob.transform.position = spawnPosition;
VoxelPlayPathAgent agent = mob.AddComponent<VoxelPlayPathAgent>();
agent.target = player; // chases the player and repaths automatically
agent.speed = 4f;
agent.maxDrop = 3; // accepts drops of up to 3 voxels
// or send it to a fixed destination instead:
agent.SetDestination(new Vector3(120, 60, -40));
agent.ClearDestination(); // back to chasing the target
// arrival check
if (!agent.hasPath) {
// no path yet or already arrived
}
Per-voxel walk costs, editable in the inspector or from code:
VoxelDefinition mud = env.GetVoxelDefinition("Mud");
mud.pathfindCost = 6f; // agents prefer routes around mud
VoxelDefinition road = env.GetVoxelDefinition("StonePath");
road.pathfindCost = 0.5f; // agents favor walking on roads
VoxelDefinition lava = env.GetVoxelDefinition("VoxelLava");
lava.pathfindCost = 0f; // impassable for agents
Fluids and perception:
// this agent never steps into water or lava
agent.fluidTraversal = FluidTraversal.Forbidden;
// a tall amphibious agent wading two cells of water
VoxelPathOptions options = new VoxelPathOptions {
agentHeight = 3,
fluidTraversal = FluidTraversal.Wade,
maxWadeDepth = 2
};
env.FindPath(start, end, options, OnPathReady);
// swimmer: crosses deep water floating with the feet one cell under the surface
agent.fluidTraversal = FluidTraversal.Swim;
agent.swimDepth = 1;
agent.OnFluidStateChanged += (a, previous, current) => {
animator.SetBool("swimming", current == PathAgentFluidState.Floating);
};
// guard dog: only reacts to targets it can actually see nearby, then returns to its post
agent.detectionRange = 15f;
agent.requireLineOfSight = true;
agent.loseTargetDistance = 30f;
agent.returnHome = true;
Blocking areas for the planner:
// a gate: closed for path searches until it opens again
PathfindingBlockHandle gate = env.PathfindingBlockArea(gateCollider.bounds);
...
env.PathfindingUnblockArea(gate);
// a hazard that clears itself after 20 seconds
env.PathfindingBlockPositions(burningVoxels, 20f); // List<VoxelIndex> from a damage event
Locomotion events and a derived agent:
agent.OnStepUp += (a, cells) => animator.SetTrigger("jump");
agent.OnDrop += (a, cells) => { if (cells > 1) animator.SetTrigger("fall"); };
agent.OnDestinationReached += a => animator.SetBool("walking", false);
agent.OnTargetAcquired += a => animator.SetBool("alert", true);
agent.OnTargetLost += a => animator.SetBool("alert", false);
// speed per state and a custom climb, keeping everything else
public class MobAgent : VoxelPlayPathAgent {
public float swimSpeed = 1.5f;
public float chaseSpeed = 5f;
protected override float GetMoveSpeed () {
if (fluidState == PathAgentFluidState.Floating) return swimSpeed;
return perceptionState == PathAgentPerceptionState.Chasing ? chaseSpeed : speed;
}
protected override void SettleVertical () {
// your own vertical motion towards currentFeet + heightOffset (arc, impulse, tween)
base.SettleVertical();
}
}Suggest an improvement
Help us improve this documentation page.