Interact
Interact shows a prompt above an entity while the player’s character is near it, and fires a callback on a key press or a click. The player’s character is an entity that carries the ControlledTrait trait, whether or not a player controls it now: every character <CharacterSpawn> spawns, and any other entity control linked to a player, a kart she has left among them. A view reads her own character with useCharacter().
Its props are in InteractProps.
The prompt shows while the player’s character is near, with the key that presses it, and the E key fires onInteract, except an E typed into a text field. Where the camera walks the player’s character to a click, as the classic camera does, a click or a tap on the entity walks her to where it stood and fires onInteract once she comes within radius, stopping her there, as World of Warcraft’s click-to-move does with an NPC. A click on the ground, a steer, or a walk that ends short of the entity, because it walked on, cancels the press; a second click follows it. A callback is allowed here because Interact is client behaviour. Each press also adds the InteractedEvent event to the entity, which a system or an NPC’s routine reads. A door that opens when the player uses a key on it is an Interact whose press uses the key, as Locks and keys builds.
Where it runs
Section titled “Where it runs”Client. The prompt only changes what this client shows.
In a room, “the player’s character” is each page’s own. The room steps the entity and streams its trait, whose near says whether any player’s character stands within radius. Each page ignores that near: it shows the prompt while its own character stands within radius, and the E key fires the onInteract its own scene passed. A press on one page fires nothing on another. The press also reaches the room as the engine’s behaviours.interact command, which behaviours() declares: the room adds InteractedEvent to its own copy of the entity when the pressing player’s character stands within radius plus 1 m, the metre covering the player’s page walking ahead of the room. InteractedEvent carries by, the characters whose presses reached the entity in that step, so two players who press together each start their own conversation; a game played alone takes the same command, so its InteractedEvent names her character too. So an NPC’s talk routine runs on the room, and every page sees it through the stream. A Server behaviour that needs to know which character is near reads findNearestControlled in its system, as Pickup and Chase do.
import { Entity, Interact, type EntityProps } from "@spawnite/engine";
export function Chest({ position, onInteract,}: Pick<EntityProps, "position"> & { onInteract: () => void }) { return ( <Entity position={position}> <Interact prompt="Open" onInteract={onInteract} /> <mesh position={[0, 0.4, 0]}> <boxGeometry args={[1, 0.8, 0.6]} /> <meshStandardMaterial color="saddlebrown" /> </mesh> </Entity> );}