Skip to content

Queries

A query asks the physics system about colliders at a place: what a ray hits, what a moving shape would hit, or what is inside an area. Use queries for line of sight, ground checks, explosions and aiming.

Queries are methods of PhysicsAPI:

import { PhysicsAPI } from 'dacha';
const physics = world.systemApi.get(PhysicsAPI);
Three queries. A raycast goes from an origin until it hits a box, and reports the hit point and the normal. A shape cast moves a circle until it touches a box. An overlap finds the colliders inside a circle, and ignores a collider outside it. Raycastwhat a ray hitsorigindistancenormalpointShape castwhat a moving shape hitsshapedirectionOverlapwhat is inside a shape nowfoundnot found
A raycast and a shape cast move along a direction and report what they hit. An overlap checks one place and reports every collider inside the shape.
Query What it asks
Raycast What does a ray from a point hit?
Shape cast What does a shape hit when it moves in a direction?
Actor cast What does an actor’s collider hit when it moves in a direction?
Overlap Which colliders are inside a shape right now?
Actor overlap Which colliders overlap an actor’s collider right now?

Each query type has several methods:

Query First hit All hits Runs callback per hit
Raycast raycast raycastAll raycastEach
Shape cast shapeCast shapeCastAll shapeCastEach
Actor cast castActor castActorAll castActorEach
Overlap overlapShape overlapEach
Actor overlap overlapActor overlapActorEach

A raycast sends a ray from origin in direction, up to maxDistance world units:

import { PhysicsAPI, Transform, Vector } from 'dacha';
const from = enemy.getComponent(Transform).world.position;
const to = player.getComponent(Transform).world.position;
const hit = physics.raycast({
origin: from,
direction: new Vector(to.x - from.x, to.y - from.y),
maxDistance: 400,
excludeActors: [enemy],
});
const canSeePlayer = hit?.actor === player;

A ray that starts inside a collider can hit that collider. Exclude the actor that casts the ray, as in the example above.

A shape cast moves a shape from its position in direction, up to maxDistance. It finds the colliders the shape touches on the way:

const hit = physics.shapeCast({
shape: { type: 'circle', center: { x: 100, y: 50 }, radius: 8 },
direction: new Vector(1, 0),
maxDistance: 200,
});

A shape cast can use these shapes:

type Fields
circle center, radius
box center, size, rotation
capsule center, height, radius, rotation

The fields work like the fields of a Collider, in world space. rotation is in radians, and it is optional.

A shape that already overlaps a collider at the start hits it at distance 0.

An actor cast moves the collider of an actor. Use it to check whether an actor can move somewhere before you move it:

const hit = physics.castActor({
actor,
direction: new Vector(0, 1),
maxDistance: 2,
});
const isOnGround = hit !== null && hit.normal.y < -0.7;

An actor cast has these extra fields:

Field What it does
actor The actor whose collider moves. The cast starts from its current Transform
offset Moves the start of the cast, in world units. Optional
excludeSelf Leaves the actor itself out of the results. true by default
layer See filters. Without it, the cast uses the layer of the actor’s collider

An actor without a collider finds nothing. An actor with a segment collider also finds nothing.

An overlap finds the colliders that are inside a shape. It can use a point, in addition to the shapes of a shape cast:

type Fields
point point
circle center, radius
box center, size, rotation
capsule center, height, radius, rotation

This explosion pushes every body around its center:

import { PhysicsAPI, RigidBody } from 'dacha';
physics.overlapEach(
{ shape: { type: 'circle', center, radius: 80 } },
(hit) => {
const body = hit.actor.getComponent(RigidBody);
if (!body) {
return;
}
body.applyImpulse(hit.normal.clone().multiplyNumber(-300));
},
);

overlapActor and overlapActorEach use the collider of an actor as the shape. They have the same extra fields as actor casts: actor, offset, excludeSelf and layer.

Raycasts and casts return a cast hit:

Field What it holds
actor The actor that was hit
point The point where the ray or the shape touches the collider, in world space
normal The direction out of the surface that was hit. It points back toward the ray or the shape
distance How far the ray or the shape went before it touched the collider

Overlaps return an overlap hit:

Field What it holds
actor The actor that overlaps the shape
normal The direction from the actor to the query shape
penetration How deep they overlap along normal, in world units
contactPoints The points where they touch, in world space

First hit. raycast, shapeCast and castActor return the nearest hit, or null when nothing is hit.

All hits. The All methods, overlapShape and overlapActor return an array. Raycasts and casts sort it from the nearest hit to the farthest.

One call per hit. The Each methods call your function once for every hit, in no particular order.

Every query accepts these optional fields:

Field What it does
layer Finds only colliders whose layer collides with this layer, as the collision matrix says
excludeActors Leaves these actors out
actorFilter A function that gets each actor and returns false to leave it out
hitFilter A function that gets each hit and returns false to leave it out

Without layer, raycasts, shape casts and overlaps find colliders on all layers.

Queries see the colliders where the physics system last checked them, in its last step. So:

  • If you move an actor through its Transform, queries find it at the new position only after the next physics step.
  • A removed actor can still appear in results until the next physics step.
  • An actor you add to the scene is found at once, at the position it had when you added it.