Jump to content

Making a Zone


cseibert
 Share

Recommended Posts

Does anyone have a good example of how to create a zone which invokes a callback function when a player enters / leaves the zone?  I am just trying to display some extra text when a player enters a zone, but I can't find any good examples using the Phaser3 Zone class.

I found a work around using the Rectangle object manually, but I'm assuming (hoping) there is an easier way to use the Zone class to setup this same functionality using enter / leave callbacks?

This is what I have done so far:

// create
this.zone = new Phaser.Geom.Rectangle(this.box.x - 25, this.box.y - 25, 50, 50);
this.player = this.physics.add.sprite(800, 600, 'player_handgun');
this.text = this.add.text(this.box.x + 20, this.box.y, "use", {
  font: "18px Arial",
  fill: "#ff0000",
  align: "center",
  backgroundColor: "#00ffff"
});
this.text.setOrigin(0.5, 0.5);
this.text.setVisible(false);

// update
if (Phaser.Geom.Rectangle.Overlaps(this.player.getBounds(), this.zone)) {
  this.text.setVisible(true);
} else {
  this.text.setVisible(false);
}

Again, ^ this approach works, but I rather find a way to use the Phaser's Zone class.  Some issues I have with this approach is I can't set the origin(0.5, 0.5) on the rectangle, so I have to calculate the zone offset manually.

Link to comment
Share on other sites

Zones don't really do their own overlap checks, but you could add an Arcade Physics body to a zone and then use an overlap collider, if you prefer that.

Even without a physics body, you could do 

Phaser.Geom.Rectangle.Overlaps(player.getBounds(), zone.getBounds())

 

Link to comment
Share on other sites

  • 3 years later...

Doesn't work if the objects stops in the zone. Because of this written in documentation:

touching :Phaser.Types.Physics.Arcade.ArcadeBodyCollision
Whether this Body is colliding with a Body or Static Body and in which direction. In a collision where both bodies have zero velocity, embedded will be set instead.

And because of this, you cannot rely on wasTouching.none

Link to comment
Share on other sites

Back,

I've written some code that works. I load the areas (zones) from a tilemap (.json file) created with Tiled (the rectangle in the object layer must have Type=AREA). I am pasting only the necessary code (striped the irrelevant).

And it is TypeScript, Not JavaScript, but easey to change to js.

mainMenuScene.ts

import 'phaser';
import Grizzly from '../grizzly';
import Hero from '../hero';

export enum AreaCollision {
    ENTER_AREA,
    EXIT_AREA
}

export default class MainMenuScene extends Phaser.Scene {
    map: Phaser.Tilemaps.Tilemap;
    hero: Hero;

    heroArea: String | null = null;

    areaObjects: Array<Phaser.Types.Tilemaps.TiledObject>;

    constructor() {
        super({ key: 'MainMenuScene' });
    }

    preload() {
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/town.json');
    }

    create() {
        this.map = this.make.tilemap({ key: 'map' });
        this.areaObjects = this.map.filterObjects('Objects', (obj) => obj.type === 'AREA');
    }

    update(time, delta) {
        for (let area of this.areaObjects) {
            //debug:
            //let rectangle = this.add.rectangle(area.x!, area.y!, area.width!, area.height!);
            //rectangle.setStrokeStyle(1, 0xff0000, 1);
            //rectangle.setOrigin(0, 0);

            let entities: Array<Phaser.Physics.Arcade.Body> = this.physics.overlapRect(
                area.x!,
                area.y!,
                area.width!,
                area.height!,
                true,
                false
            ) as Array<Phaser.Physics.Arcade.Body>;

            let heroesInArea = entities.filter((entity) => entity.gameObject instanceof Hero);
            let inArea = true;
            if (heroesInArea.length == 0) {
                inArea = false;
            }

            if (inArea == true && (this.heroArea == null || this.heroArea != area.name)) {
                this.hero.emit(AreaCollision[AreaCollision.ENTER_AREA], area.name);
                this.heroArea = area.name;
            }
            if (!inArea && this.heroArea == area.name) {
                this.hero.emit(AreaCollision[AreaCollision.EXIT_AREA], area.name);
                this.heroArea = null;
            }
        }
    }
}

and hero.ts

import 'phaser';
import MainMenuScene, { AreaCollision } from './scenes/mainMenuScene';

export default class Hero extends Phaser.GameObjects.Sprite {
   
    constructor(scene, x, y) {
        this.on(AreaCollision[AreaCollision.ENTER_AREA], (areaName) => {
            console.log('Enter area ' + areaName);
        });

        this.on(AreaCollision[AreaCollision.EXIT_AREA], (areaName) => {
            console.log('Exit area ' + areaName);
        });
    }
}

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...