Picking
Entity picking answers a scene question in entity terms: what does this ray, this screen position, or this camera's forward direction hit, and which entity, if any, owns what it hit. Picking is NodeSimulation's, reached through engine.simulation.
import type { EntityPickFilter, EntityPickResult } from '@skewedaspect/sage';The three picks
| Method | Picks along |
|---|---|
pickEntityWithRay(ray, filter?) | A given Ray |
pickEntity(x, y, filter?) | The ray a screen position projects into the scene |
pickEntityForward(camera, range, filter?) | A camera's forward direction, out to range |
All three answer with an EntityPickResult or undefined, and all three resolve and filter the same way.
const hit = simulation.pickEntityForward(camera, 5, { tags: [ 'interactive' ] });
if(hit !== undefined && hit.entity.hasBehavior(InteractBehavior))
{
showPrompt(hit.entity.ops.promptText());
}scene.onPointerDown = (event, pickInfo) =>
{
const hit = simulation.pickEntity(scene.pointerX, scene.pointerY);
if(hit !== undefined)
{
console.log(hit.entity.name, hit.point, hit.distance);
}
};Resolving a hit to an entity
Babylon's own pick answers with a mesh, not an entity. Resolving the mesh to the entity that owns it walks the mesh's ancestors, the mesh itself, then its parent, then that parent's parent, until one entity's own node matches, checked against every NodeEntity the simulation holds. The walk answers with nothing when the chain runs out without a match, such as level geometry with no entity of its own.
The walk keeps no lookup of its own in step with spawn and despawn, and writes nothing to any node. The same walk resolves a fresh node, a pooled one, and an adopted one alike.
A node the walk crosses before reaching a match is not itself the answer: a turret's own node resolves to the turret, not to the ship carrying it, because the walk stops at the first NodeEntity it matches.
A despawned poolable entity's node is disabled while it waits in the pool, and Babylon's pick already excludes a disabled node.
Filtering
interface EntityPickFilter
{
tags ?: readonly string[];
}tags is a list an entity's own tags must all hold for a pick to answer with it. An entity the walk resolves to that fails the filter is the same as no hit at all; picking never tries whatever the same ray might hit behind it. Omitting the filter matches every entity the walk resolves to.
The pick result
interface EntityPickResult
{
entity : NodeEntity;
mesh : AbstractMesh;
point : Vector3;
distance : number;
normal : Vector3;
}| Field | Meaning |
|---|---|
entity | The resolved NodeEntity |
mesh | The Babylon mesh actually hit |
point | The hit point in world space |
distance | The distance to it |
normal | The surface normal there, or the zero vector when Babylon cannot compute one |
entity is a plain NodeEntity. Narrow it with instanceof against a class, or with hasBehavior.
Not in this release
A multi-result pick, answering with every entity along a ray or under a screen position rather than only the nearest, is not built.
