LogoLogo
  • Get Started
  • Getting Started
    • Initial Setup
    • Create Your First Game
    • API Reference
    • Build Your First World Map
    • Multiplayer Testing
    • Use Templates & Examples
    • Styling & Assets
      • Modeling Guidelines
      • Texturing Guidelines
      • Default Assets
  • Build Faster With AI Tools
  • SDK Guides
    • Assets
    • Audio & SFX
      • Audio Manager
    • Blocks & Chunks
      • Block Types
      • Block Type Registry
      • Chunks
      • Chunk Lattice
    • Camera
    • Chat & Commands
    • Debugging
    • Entities
      • Animations
      • Block Entities
      • Colliders & Hitbox
      • Child Entities
      • Entity Controllers
        • Base Entity Controller
        • Pathfinding Entity Controller
        • DefaultPlayer Entity Controller
        • Simple Entity Controller
      • Entity Manager
      • Model Entities
      • Movement & Pathfinding
      • Player Controlled Entities
    • Events
    • Input & Controls
    • Lighting
      • Ambient Light
      • Light Manager
      • Point Lights
      • Spot Lights
      • Sun Light (Directional)
    • Mobile
    • Persisted Data
    • Players
      • Player Manager
      • Persisted Player Data
    • Plugins
    • Physics
      • Colliders
      • Collision Groups
      • Debugging
      • Gravity
      • Raycasts
      • Rigid Bodies
    • User Interface
      • Overlay UI
      • Scene UIs
      • Scene UI Manager
    • Worlds
      • Map Data Format
  • Helpful Resources
    • HYTOPIA Architecture & Platform Overview
    • Useful Third-Party Tools
Powered by GitBook
On this page
  • Basic Raycast Example
  • Block Breaking & Placing Example
  • Diving Deeper
Export as PDF
  1. SDK Guides
  2. Physics

Raycasts

PreviousGravityNextRigid Bodies

Last updated 9 days ago

A Raycast is a method of projecting an imaginary line (a "ray) from a specific point in a given direction to detect intersections with objects. You can think of it as a quick way to figure out what object would be "hit" if you fired an infinitely thin laser beam from a certain point in the direction of another point.

If the raycast hit an object, it gives information on the object hit. In HYTOPIA a hit object will be a block or entity.

If the raycast does not hit an object, it will return null.

You can control the length of the cast ray, it's origin and direction, and a number of options to ignore certain intersections, and more.

Basic Raycast Example

Here's some basic code showing how we can perform a raycast. Raycasts are performed from the simulation instance of a world as follows.

const origin = { x: 10, y: 2, z: 0 }; 
const direction = { x: 0, y: 1, z: 0 }; // raycast straight up
const length = 5; // Max length in blocks the ray travels 
const raycastResult = world.simulation.raycast(origin, direction, length);

Block Breaking & Placing Example

Let's make something more useful. How about we setup our players so they can use the left click of their mouse to break blocks in front of the direction their facing, and the right click to place a block.

We can do that as follows.

// ... other code

// Enable debug raycasting so we can visualize our raycasts for testing
world.simulation.enableDebugRaycasting(true);

world.on(PlayerEvent.JOINED_WORLD, ({ player }) => {
  const playerEntity = new DefaultPlayerEntity({
    player,
    name: 'Player',
  });

  // PlayerEntity by default has a PlayerEntityController assigned to .controller,
  // but we explicitly assert that with ! to prevent typescript from complaining.
  playerEntity.controller!.on(BaseEntityControllerEvent.TICK_WITH_PLAYER_INPUT, ({ entity, input, cameraOrientation, deltaTimeMs }) => {
    if (input.ml || input.mr) { // ml = mouse left clicked, mr = mouse right clicked
      const origin = entity.position; // start at the player's current position.
      const direction = entity.player.camera.facingDirection; // cast in the camera direction
      const length = 5;
      const raycastResult = world.simulation.raycast(origin, direction, length, {
        // Prevent the raycast from registering our player entity as the hit object.
        // Raycast options typically work using raw physics engine handles, so we
        // have to use the raw rigid body of our player entity.
        filterExcludeRigidBody: playerEntity.rawRigidBody, 
      });

      if (raycastResult?.hitBlock) { // see if the result hit a block
        if (input.ml) { // left click, break block
          const breakPosition = raycastResult.hitBlock.globalCoordinate;
          world.chunkLattice.setBlock(breakPosition, 0); // 0 = no block/air
        } else { // right click, place block as neighbor of the hit block
          const placePosition = raycastResult.hitBlock.getNeighborGlobalCoordinateFromHitPoint(raycastResult.hitPoint);
          world.chunkLattice.setBlock(placePosition, 1); // 1 = bricks in the default block types
        }
      }

      // Explicitly cancel inputs to prevent raycast spam each tick
      // A player will need to let go of their click and click again
      input.ml = false;
      input.mr = false;
    }
  });
  
  playerEntity.spawn(world, { x: 0, y: 10, z: 0 });
});

Here's a gif showcasing how our block breaking and placing code using raycasts works!

Diving Deeper

Raycasts make use of a few systems. To learn more and understand all of the features of raycasts, we recommend the following resources.

If there are features that we don't currently support for raycasts that you'd like to see added to the HYTOPIA SDK, you can submit a feature request here.

, used to perform a raycast.

, returned by raycast() if an object was hit.

, used with raycast() to control its behavior.

raycast() method API Reference
RaycastHit type API Reference
RaycastOptions type API Reference
When debug raycasting is enabled, we can see our raycast in the world. The black arrow point up is the resulting example raycast.