Skip to content
Work in progress. These docs describe Spawnite at launch, and some parts are still being built.

Canvas tap

useCanvasTap reports each tap on the scene as a ray in world space and the target your game finds on it. It suits a game with no player character, such as a farm or a city builder under the map camera, where a tap selects a tree or sends a worker. For the thumb button beside the joystick, see Tap.

You pass two functions:

  • findTarget(ray) returns your target under the ray, or nothing. Read your own layout, such as the plot nearest where the ray meets the ground, or call findEntityUnderRay to take the nearest entity by what it draws.
  • onTap({ ray, target, event }) runs on each tap. target is null on a tap on nothing, where a game usually clears its selection. event is the release, for its pointer type.

A tap is a still, short press of one pointer that went down on the canvas: a mouse’s left button, a finger or a pen. The following presses are no tap:

  • A press that travels more than 4 pixels from where it went down, at any moment, so a drag that comes back is still a drag. The map camera pans past the same 4 pixels, so a pan never taps. maxTravelPixels changes the limit.
  • A press held longer than 0.4 seconds. maxHoldSeconds changes the limit.
  • A press on the HUD over the canvas, such as a button or a panel.
  • A pinch: a second finger cancels the press, as does the browser taking the touch to scroll.
  • A press while the cursor is captured, whose position stands still.

The hook hears a release the map camera captured, and a release off the canvas.

Where a game also has a character that walks to a click, a tap that found a target keeps the character still: the hook claims the click, as registerClickClaim does. A tap on nothing leaves the click to the walk. findTarget runs once a tap, so onTap may remove the target it was given.

Mount the component inside the scene’s <Views>, since a room has no canvas to tap. A tap takes the near crate of two that stand in line:

packages/engine/test/outside/CrateTaps.tsx
import {
createQuery,
defineTrait,
findEntityUnderRay,
RefTrait,
useCanvasTap,
useWorld,
} from "@spawnite/engine";
import type { Entity } from "@spawnite/engine/core";
export const CrateTrait = defineTrait("crate", { opened: false });
const crates = createQuery(CrateTrait, RefTrait);
interface CrateTapsProps {
/** The crate tapped, or null for a tap on nothing. */
onSelect: (crate: Entity | null) => void;
}
// Mount it inside the scene's <Views>, which a room skips, as <MapCamera />
// is. A tap takes the crate it lands on, the nearest of two in line.
export function CrateTaps({ onSelect }: CrateTapsProps) {
const world = useWorld();
useCanvasTap({
findTarget: (ray) => findEntityUnderRay(world, ray, { query: crates }),
onTap: ({ target }) => onSelect(target),
});
return null;
}

Its options are in CanvasTapOptions.