Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

steering

Steering behaviours for the boids simulation — obstacle avoidance, boundary containment, predator flee, and leader following. Each function returns force components (fx, fy, fz) the caller accumulates onto the boid's steering force before integration. Position and velocity scalars are passed individually to avoid per-call vec3 allocation.

Exports

  • S.obstacleAvoidance(px, py, pz, vx, vy, vz, avoidDist, avoidWeight) -> (number, number, number) — raycast ahead along velocity; if it hits an obstacle, push along the hit normal with quadratic-falloff urgency. Safe no-op when __physics.raycast is unavailable.
  • S.boundaryForce(px, py, pz, boundary: Boundary, force) -> (number, number, number) — soft containment force inside the outer 30% of a sphere or box boundary; zero inside.
  • S.predatorFlee(px, py, pz, predators: { Predator }) -> (number, number, number) — accumulated flee force from every predator inside its individual fleeDistance. Predator positions are read from each predator entity's Transform.
  • S.leaderFollow(px, py, pz, leader: Leader) -> (number, number, number) — steer toward a leader entity, scaling with overshoot beyond the follow distance. Reads leader position from the leader entity's Transform.

Types:

  • Vec3 = { x: number, y: number, z: number, [number]: number? } — map or array.
  • SphereBoundary = { type: "sphere", center: Vec3, radius: number }.
  • BoxBoundary = { type: "box", min: Vec3, max: Vec3 }.
  • Boundary = SphereBoundary | BoxBoundary.
  • Predator = { entityId: string, fleeDistance: number, fleeWeight: number }.
  • Leader = { entityId: string, followDistance: number, followWeight: number }.

Usage

local Steering = require("@builtin::modules.boids.steering")

local ax, ay, az = Steering.obstacleAvoidance(px, py, pz, vx, vy, vz, 3.0, 5.0)
local bx, by, bz = Steering.boundaryForce(px, py, pz,
    { type = "sphere", center = { x = 0, y = 0, z = 0 }, radius = 50 }, 2.0)
local px2, py2, pz2 = Steering.predatorFlee(px, py, pz, predators)
local lx, ly, lz = Steering.leaderFollow(px, py, pz, leader)

Notes

  • All four functions read entity / physics state at call time. Caller ordering inside the boids inner loop matters — these run after the spatial grid query and before integration.
  • obstacleAvoidance calls __physics.raycast through pcall. A missing physics binding (e.g. in a non-3D test context) yields a silent no-op rather than a runtime error.
  • boundaryForce returns zero for unrecognised boundary.type values. Existing callers always pass "sphere" or "box".
  • Position reads (__reflect.get(entityId, "Transform", "position")) are tolerant of missing entities — if the predator/leader is despawned mid-frame the function returns zero for that contribution.