const config = {
  type: Phaser.WEBGL,
  width: 800,
  height: 600,
  physics: {
    default: "arcade",
    arcade: {
      debug: true
    }
  },
  scene: {
    preload: preload,
    create: create,
    update: update
  },
  loader: {
    baseURL: "https://labs.phaser.io",
    crossOrigin: "anonymous"
  },
  plugins: {
    scene: [
      {
        key: "PhaserRaycaster",
        plugin: PhaserRaycaster,
        mapping: "raycasterPlugin"
      }
    ]
  }
};

new Phaser.Game(config);

var raycaster;
var ray;
var graphics;
var obstacles;
var intersections = [];
var targets;
var slices;
var boundary;

var RANGE = 150;

function preload() {
  this.load.image("crate", "assets/sprites/crate.png");
}

function create() {
  raycaster = this.raycasterPlugin.createRaycaster({ debug: true });

  ray = raycaster.createRay({
    origin: { x: 400, y: 300 },
    autoSlice: true,
    collisionRange: RANGE,
    detectionRange: RANGE,
    rayRange: 2 * RANGE
  });
  ray.enablePhysics();

  console.log("raycaster", raycaster);
  console.log("ray", ray);

  // You would probably want this invisible
  boundary = this.add.polygon(
    ray.origin.x,
    ray.origin.y,
    new Phaser.Geom.Circle(RANGE, RANGE, RANGE).getPoints(12),
    0xffff00,
    0.5
  );
  raycaster.mapGameObjects(boundary);

  obstacles = this.add.group();
  createObstacles(this);
  raycaster.mapGameObjects(obstacles.getChildren());

  createTargets(this);

  graphics = this.add.graphics({
    lineStyle: { width: 1, color: 0x00ff00 },
    fillStyle: { color: 0xffffff, alpha: 0.5 }
  });
  
  intersections = ray.castCircle();
  draw();

  this.input.on("pointermove", function (pointer) {
    ray.setOrigin(pointer.x, pointer.y);
    
    boundary.setPosition(pointer.x, pointer.y);
    boundary.data.get('raycasterMap').updateMap();
    
    intersections = ray.castCircle();
  });

  this.physics.add.overlap(
    ray,
    targets,
    function (rayCircle, target) {
      target.setTint(0xff0000);
    },
    ray.processOverlap.bind(ray)
  );

  this.events.on("preupdate", function () {
    for (let target of targets.getChildren()) {
      target.clearTint();
    }
  });
}

function update() {
  draw();
}

function createTargets(scene) {
  targets = scene.physics.add.group({
    defaultKey: "crate",
    bounceX: 1,
    bounceY: 1,
    collideWorldBounds: true,
    velocityX: 60,
    velocityY: 60
  });

  targets.create(400, 300);
  targets.create(750, 500);
  targets.create(450, 75);
}

function createObstacles(scene) {
  let obstacle = scene.add.rectangle(100, 100, 75, 75, 0xaaaaaa, 0.5);
  obstacles.add(obstacle, true);

  obstacle = scene.add.line(400, 100, 0, 0, 200, 50);
  obstacles.add(obstacle);

  obstacle = scene.add.circle(650, 100, 50, 0xaaaaaa, 0.5);
  obstacles.add(obstacle);

  obstacle = scene.add.polygon(
    650,
    500,
    [0, 0, 50, 50, 100, 0, 100, 75, 50, 100, 0, 50],
    0xaaaaaa,
    0.5
  );
  obstacles.add(obstacle);

  for (let i = 0; i < 5; i++) {
    obstacle = scene.add.rectangle(
      350 + 30 * i,
      550 - 30 * i,
      50,
      50,
      0xaaaaaa,
      0.5
    );
    obstacles.add(obstacle, true);
  }

  obstacle = scene.add.image(100, 500, "crate");
  obstacles.add(obstacle, true);
}

function draw() {}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js
  2. https://cdn.jsdelivr.net/npm/[email protected]/dist/phaser-raycaster.js