Skip to content

Cast a shape ​

Goal ​

Check a straight throw path with a sphere, check a character teleport with a capsule, and find the bodies on a pressure plate with a box overlap.

Files you will edit ​

  • src/game.ts

Steps ​

  1. In the third-person template's src/game.ts, add physics and Transform to the SDK import and HERO_RADIUS / HERO_HALF_HEIGHT to the ./prefabs import. Add these reusable query records above defineGame.

    ts
    const queryRotation = { x: 0, y: 0, z: 0, w: 1 };
    const throwOrigin = { x: 0, y: 0, z: 0 };
    const throwDirection = { x: 0, y: 0, z: -1 };
    const teleportStart = { x: -2, y: 1.3, z: -3 };
    const teleportDirection = { x: 1, y: 0, z: 0 };
    const teleportSpot = { x: 0, y: 1.3, z: -3 };
    const plateCentre = { x: 0, y: 0.2, z: -5 };
    const plateHalf = { x: 1, y: 0.15, z: 1 };
    const queryLayers = { defaultLayer: true, staticGeometry: true, player: true };
    const plateLayers = { defaultLayer: true, player: true };
    let throwClear = false;
    let plateCount = 0;
  2. Add this system above defineGame and insert shapeChecks after locomotionSystem in the existing systems array. Press G to test a 6 m throw segment toward -Z from the hero's eye; the 15 cm sphere catches obstacles a thin ray would miss. Consume its hit before running another query.

    ts
    function shapeChecks(ctx: GameContext): void {
      if (ctx.player === 0) return;
      if (ctx.input.pressed('G')) {
        throwOrigin.x = Transform.x[ctx.player];
        throwOrigin.y = Transform.y[ctx.player] + 0.5;
        throwOrigin.z = Transform.z[ctx.player];
        const hit = physics.sphereCast(
          throwOrigin,
          0.15,
          throwDirection,
          6,
          queryLayers,
          ctx.player,
        );
        throwClear = hit === null;
      }
      if (ctx.input.pressed('T')) {
        const blocked = physics.capsuleCast(
          teleportStart,
          HERO_RADIUS,
          HERO_HALF_HEIGHT,
          queryRotation,
          teleportDirection,
          2,
          queryLayers,
          ctx.player,
        );
        if (blocked === null) {
          const occupied = physics.overlapCapsule(
            teleportSpot,
            HERO_RADIUS,
            HERO_HALF_HEIGHT,
            queryRotation,
            1,
            queryLayers,
            ctx.player,
          );
          if (occupied.length === 0) {
            physics.teleport(ctx.player, teleportSpot.x, teleportSpot.y, teleportSpot.z);
          }
        }
      }
      const onPlate = physics.overlapBox(plateCentre, plateHalf, queryRotation, 16, plateLayers);
      plateCount = onPlate.length;
    }

    T checks a 2 m arrival corridor from teleportStart to teleportSpot, then overlaps the destination before teleporting. Both centres must be above the floor by at least the capsule's radius plus half-height; neither test includes the player's current body. Use an overlap for an occupied spot: a sweep alone is not a reliable initial-penetration check. These queries describe a straight segment; a ballistic throw needs several segments.

  3. Reset throwClear = false and plateCount = 0 in the existing init. Use those values in your game rules or HUD: throwClear is permission to launch, and plateCount > 0 means the plate is occupied. An overlap returns entity ids in its hits if you need to distinguish the hero from a crate. The plate filter skips staticGeometry, so the floor does not count as an occupant; its box also starts 5 cm above the floor. The 16-result cap is intentional; raise it for a crowded plate. Queries ignore solidOnly, including sensors on selected layers just like raycast.

Verify ​

sh
npm run dev

Stand with clear space toward -Z and press G: throwClear becomes true. Stand near a wall edge where a line fits but a 30 cm wide projectile does not: it becomes false. Press T: the hero arrives at (0, 1.3, -3) only if the corridor and destination are clear. Walk across (0, 0, -5): plateCount becomes positive, then returns to zero when the volume is empty. Adjust the three test locations if your arena has scenery there.

See also ​