Using camera zoom on player using Easystar pathfinding algorithm?

Hi there!

I’m toying with some code from a pathfinding tutorial, this one here, it’s really neat.

I’m trying to set the zoom on the camera. When the zoom is not applied, the path finding works fine. And it follows the player. But with the zoom on, using setZoom(2, 2), the pathfinding algorithm breaks. As in the code, the easystar library recieves a grid and and gives you a path if I’m not mistaken. Heres the code I’m working with.


import Phaser from 'phaser'
import EasyStar from 'easystarjs'

let MyScene = new Phaser.Class({
  Extends: Phaser.Scene,
  initialize:
  function MyScene (config)
  {
    Phaser.Scene.call(this, { key: "MyScene" });
      this.checkCollision = this.checkCollision.bind(this)
      this.getTileID = this.getTileID.bind(this)
      this.handleClick = this.handleClick.bind(this)
      this.moveCharacter = this.moveCharacter.bind(this)
  },
  init: function () {},
  preload: function () {
    this.load.image('tileset', 'assets/gridtiles.png')
    this.load.tilemapTiledJSON('map', 'assets/map.json')
    this.load.image('phaserguy', 'assets/phaserguy.png');
  },
  create: function () {

    this.input.on('pointerup',this.handleClick);

    this.camera = this.cameras.main;
    this.camera.setBounds(0, 0, 20*32, 20*32)

    let phaserGuy = this.add.image(32, 32, 'phaserguy')
    phaserGuy.setDepth(1)
    phaserGuy.setOrigin(0, 0.5)
    this.camera.startFollow(phaserGuy)
    this.camera.setZoom(2, 2)

    this.player = phaserGuy

    this.map = this.make.tilemap({key: 'map'})
    let tiles = this.map.addTilesetImage('tiles', 'tileset')
    this.map.createLayer(0, tiles, 0, 0)

    this.marker = this.add.graphics()
    this.marker.lineStyle(3, 0xffffff, 1)
    this.marker.strokeRect(0, 0, this.map.tileWidth, this.map.tileHeight)

    this.finder = new EasyStar.js()

    // We create the 2D array representing all the tiles of our map
    let grid = [];
    for(let y = 0; y < this.map.height; y++){
        let col = [];
        for(let x = 0; x < this.map.width; x++){
            // In each cell we store the ID of the tile, which corresponds
            // to its index in the tileset of the map ("ID" field in Tiled)
            col.push(this.getTileID(x,y));
        }
        grid.push(col);
    }

    this.finder.setGrid(grid);

    let tileset = this.map.tilesets[0]
    let properties = tileset.tileProperties
    let acceptableTiles = []

    // We need to list all the tile IDs that can be walked on. Let's iterate over all of them
    // and see what properties have been entered in Tiled.
    for(let i = tileset.firstgid-1; i < tiles.total; i++){ // firstgid and total are fields from Tiled that indicate the range of IDs that the tiles can take in that tileset
      if(!properties.hasOwnProperty(i)) {
          // If there is no property indicated at all, it means it's a walkable tile
          acceptableTiles.push(i+1);
          continue;
      }
      if(!properties[i].collide) acceptableTiles.push(i+1);
      if(properties[i].cost) this.finder.setTileCost(i+1, properties[i].cost); // If there is a cost attached to the tile, let's register it
  }
  this.finder.setAcceptableTiles(acceptableTiles)


  },
  update: function (time, delta) {
    let worldPoint = this.input.activePointer.positionToCamera(this.cameras.main)

     // Rounds down to nearest tile
     let pointerTileX = this.map.worldToTileX(worldPoint.x);
     let pointerTileY = this.map.worldToTileY(worldPoint.y);
     this.marker.x = this.map.tileToWorldX(pointerTileX);
     this.marker.y = this.map.tileToWorldY(pointerTileY);
     this.marker.setVisible(!this.checkCollision(pointerTileX,pointerTileY));

  },
  checkCollision: function (x, y) {
    let tile = this.map.getTileAt(x, y)
    return tile.properties.collide == true
  },
  getTileID: function(x, y) {
    let tile = this.map.getTileAt(x, y)
    return tile.index
  },

  handleClick: function (pointer) {
    console.log("pressed tile")
    let x = this.camera.scrollX + pointer.x;
    let y = this.camera.scrollY + pointer.y;
    let toX = Math.floor(x/32);
    let toY = Math.floor(y/32);
    let fromX = Math.floor(this.player.x/32);
    let fromY = Math.floor(this.player.y/32);
    console.log('going from ('+fromX+','+fromY+') to ('+toX+','+toY+')');

    let scene = this

    this.finder.findPath(fromX, fromY, toX, toY, function( path ) {
      if (path === null) {
          console.warn("Path was not found.");
      } else {
          console.log(path);
          scene.moveCharacter(path)
      }
  });
  this.finder.calculate(); // don't forget, otherwise nothing happens
  },
  moveCharacter: function (path) {
    let scene= this
    let tweens = []
    for (let i = 0; i < path.length-1; i++) {
      let ex = path[i+1].x
      let ey = path[i+1].y
      tweens.push({
        targets: this.player,
        x: {value: ex*this.map.tileWidth, duration: 200},
        y: {value: ey*this.map.tileHeight, duration: 200}
      })      
    }
    scene.tweens.timeline({
      tweens: tweens
    })
  },
  

The code is basically the same from the example.

For some reason, when I zoom using the camera, the grid becomes broken. I would guess that its a scaling issue but I’m unsure?

If anyone knows anything about pathfinding algorithms and/or libraries, please let me know. I’d really appreciate it, thanks.

In update() I think it is enough to use

let { worldX, worldY } = this.input.activePointer;

// Rounds down to nearest tile
let pointerTileX = this.map.worldToTileX(worldPoint.x);
let pointerTileY = this.map.worldToTileY(worldPoint.y);

And in handleClick() it should be

let x = pointer.worldX;
let y = pointer.worldY;
// etc.
1 Like

Oh thats made it work perfectly. Thanks again!

1 Like