Overlap & cast queries
Overlap & cast queries
Section titled “Overlap & cast queries”The collision backends can answer one-off questions about the world without adding trigger colliders: either what is inside a region right now (overlap queries) or what would a ray or moving shape hit (cast queries). Both families are exposed as methods on golem.Server, use the same layer mask rules as Colliders, and do not register persistent shapes—the next tick’s collision step is unaffected.
Built-in golem.collision/resolv and golem.collision/cp implement both capabilities for 2D collision. If no backend is set, or the backend does not implement the corresponding optional interface, overlap methods return nil and cast methods return false / an empty hit / nil for *All variants (see the table below). For 3D methods such as OverlapSphere, OverlapBox3D, and Raycast3D, see 3D collision.
Layer masks
Section titled “Layer masks”For every query, layerMask uses the same convention as Add: an entity is considered only if (entityLayer & layerMask) != 0. Pass 0xFFFFFFFF to include all layers, or use layers.MaskFor(...) from a CollisionLayers registry (see Colliders):
// Include any entity on the Enemy or Boss layer.ids := s.OverlapCircle(x, y, 200, layers.MaskFor("Enemy", "Boss"))
// Include everything.ids = s.OverlapBox(cx, cy, hw, hh, 0xFFFFFFFF)Overlap queries
Section titled “Overlap queries”Use these when you care about volume: aggro bubbles, explosion radii, “who is in this rectangle”, scoring zones.
OverlapBox(cx, cy, hw, hh, layerMask)— axis-aligned box centred at(cx, cy)with half-extents(hw, hh), same asCollisionAABBhalf-size.OverlapCircle(cx, cy, radius, layerMask)— circle centred at(cx, cy)with the given radius.
Returns []int64 entity IDs, or nil if the backend is missing or does not implement SpatialQuery.
srv.OnTick(func(dt float64, s *golem.Server) { // Enemies inside a 5×3 box centred at (12, 8). ids := s.OverlapBox(12, 8, 2.5, 1.5, layers.MaskFor("Enemy")) for _, id := range ids { e, _ := s.Get(id) triggerAggro(e) }
// Everything within radius 4 of an explosion at (20, 20). ids = s.OverlapCircle(20, 20, 4, 0xFFFFFFFF) for _, id := range ids { applyBlast(id) }})Cast queries
Section titled “Cast queries”Use these when you care about ordered hits along a path: line of sight, bullets, sweeping a hitbox before allowing movement.
Each successful hit is a CollisionRaycastHit (shared by rays and sweeps):
| Field | Type | Meaning |
|---|---|---|
EntityID | int64 | Entity that was hit |
Point | CollisionVec2 | World-space contact point |
Normal | CollisionVec2 | Unit normal: away from the hit shape, toward the cast origin (ray start or sweep start) |
Fraction | float64 | Distance along the cast, 0 = start, 1 = end |
Raycast / line segment
Section titled “Raycast / line segment”Raycast(x1, y1, x2, y2, layerMask)— first hit on segment(x1,y1)→(x2,y2);(hit, true)or zero value andfalse.RaycastAll(...)— every hit along the segment, sorted byFraction(closest first);nilif none.
srv.OnTick(func(dt float64, s *golem.Server) { if hit, ok := s.Raycast(5, 5, 20, 12, layers.MaskFor("Wall")); ok { fmt.Printf("wall at (%.1f, %.1f), fraction %.2f\n", hit.Point.X, hit.Point.Y, hit.Fraction) }})
hits := s.RaycastAll(ox, oy, ox+dir.X*range_, oy+dir.Y*range_, layers.MaskFor("Enemy"))for _, h := range hits { applyDamage(h.EntityID)}BoxCast / CircleCast (swept shapes)
Section titled “BoxCast / CircleCast (swept shapes)”Sweep origin is (ox, oy); (dx, dy) is the displacement (not an end point). Half-extents (hw, hh) match CollisionAABB; circle radius matches CollisionCircle.
BoxCast/BoxCastAll— AABB sweep.CircleCast/CircleCastAll— circle sweep.
// Can a 2×1 crate slide 5 units right without hitting the Wall layer?if _, ok := s.BoxCast(cx, cy, 1.0, 0.5, 5, 0, layers.MaskFor("Wall")); !ok { moveCrate(cx+5, cy)}
hits := s.CircleCastAll(gx, gy, 2.0, vx, vy, 0xFFFFFFFF)for _, h := range hits { scheduleBlastAt(h.EntityID, h.Point)}Cast methods require the backend to implement CastQuery. Otherwise you get false / empty hit / nil for *All, same as when nothing is hit (for the single-hit APIs, you can’t distinguish “no backend” from “clear line” without checking SetCollisionBackend yourself).
Server methods (quick reference)
Section titled “Server methods (quick reference)”| Method | Kind | Returns when nothing / no backend |
|---|---|---|
OverlapBox | overlap | nil |
OverlapCircle | overlap | nil |
Raycast | cast | zero CollisionRaycastHit, false |
RaycastAll | cast | nil |
BoxCast | cast | zero hit, false |
BoxCastAll | cast | nil |
CircleCast | cast | zero hit, false |
CircleCastAll | cast | nil |
Timing: the backend refreshes shape positions during Update, which runs after OnTick. Calls to OverlapBox, Raycast, etc. from inside OnTick therefore use poses as of the previous tick’s collision step, not movement from the current Ticker.Tick or OnTick. To query against this tick’s positions, run the query on the next tick (or test directly against your own state if you prefer).
Previous: Chipmunk (cp) backend. See also: Colliders, Collision & physics, 3D collision.