Search code examples
javascriptgame-developmentphaser-frameworkphaserjs

Phaser 3 console.log() tile properties for a specific game character


anyone can suggest on a general level how to achieve following with Phaser 3:

I need to be able to console.log() in an updated manner the tile or terrain properties enemy sprite is on. Idea is to update character animation if its on water or land. I tried to console.log(this.streetLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true); but world map is undefined in the update() method.. Or is there easier way of achieving this? My game is a top down RPG. Here is the complete code:

import "./style.css";
import Phaser from "phaser";

const sizes = {
  width: 960,
  height: 640,
};
let last_direction;
let enemy_terrain;


class GameScene extends Phaser.Scene {
  constructor() {
    super("scene-game");
  }

  preload() {
    // Load spritesheet for the protagonist
    this.load.spritesheet('protagonist', '/assets/mainCH.png', { frameWidth: 100, frameHeight: 100 });
    this.load.spritesheet('enemy', '/assets/waterspirit.png', { frameWidth: 150, frameHeight: 150 });
    
  
    // Load tileset and tilemap
    this.load.tilemapTiledJSON('map', '/assets/maps/testmap.json');

    this.load.image('tiles', 'assets/maps/terrain.png');
  }

  create() {
    console.log('create method executed');
    this.protagonist = this.physics.add.sprite(200, 550, 'protagonist');
    this.enemy = this.physics.add.sprite(200, 100, 'enemy');
    
    // Set up properties for the enemy
    this.enemy.speed = 100; // Adjust the speed as needed
    this.protagonist.setDepth(1);
    this.enemy.setDepth(1);
    const map = this.make.tilemap({ key: 'map' });



    // Add tilesets for each layer
    const Tileset = map.addTilesetImage('test-tiles', 'tiles');
  
    
    // Create layers from tilemap data
    const streetLayer = map.createLayer('street', Tileset, 0, 0); 
    const waterLayer = map.createLayer('water', Tileset, 0, 0); 

    console.log('Street Layer:', streetLayer); // Log the street layer object to check if it's properly created
    console.log('Water Layer:', waterLayer); // Log the street layer object to check if it's properly created
  
    // Adjust the depth of layers as needed
    streetLayer.setDepth(0);
    waterLayer.setDepth(0);
    map.setCollisionBetween(188, 188, true, waterLayer);
    map.setCollisionBetween(0, 0, true, streetLayer);

 /////////////////////////BUNCH OF ANIMATIONS START///////////////////////////////////
 /////////////////////////BUNCH OF ANIMATIONS END///////////////////////////////////
    this.cursors = this.input.keyboard.createCursorKeys();
    // Enable physics for the protagonist
    this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
    this.physics.add.collider(this.protagonist, streetLayer);
    this.physics.add.collider(this.enemy, streetLayer);
 
  
    if(this.enemy.y >= 350){
        enemy_terrain = "street"
      this.enemy.play('enemy_move_street');
  
     } else {
        enemy_terrain = "water"
    
     }
 
 // Play the appropriate animation based on the collision result
 if (enemy_terrain == "street") {
     this.enemy.play('enemy_move_street');
     console.log("enemy on street");
  
 } else {
     this.enemy.play('enemy_move_water');
     console.log("enemy on water");
 }


 
  }

  update() {
    // Reset velocity
    this.protagonist.setVelocity(0);
   
    // Handle keyboard input
        XXXX
    this.physics.moveToObject(this.enemy, this.protagonist, this.enemy.speed);
 // Call updateInfo method
    this.updateInfo();
  }
  updateInfo() {
    let timedEvent = this.time.addEvent({ 
      delay: 1000, // once every second = 1000ms
      callback: () => console.log(this.waterLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true)), 
      loop: true });
}
}


const config = {
  type: Phaser.WEBGL,
  width: sizes.width,
  height: sizes.height,
  canvas: gameCanvas,
  physics: {
    default: "arcade",
    arcade: {
      debug: true, // Set to true to enable debugging (displays collision bodies)
    },
  },
  scene: [GameScene],
};

const game = new Phaser.Game(config);

Solution

  • Well without knowing your code (the relevant parts of the code), because you shared too little. I just can say,you could simply add a timer in your create function. Something like this:

    let timedEvent = this.time.addEvent({ 
      delay: 1000, // once every second = 1000ms
      callback: () => console.log(
        this.streetLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true)
      ), 
      loop: true,
    });
    

    This will output the tile/property every second.

    I would not recommend this for production, but without knowing the relevant parts of your code this is a solution, that should work(if there are no other errors in your code. Check the browserConsole to be sure ).

    If this still results in undefined / null, the layer could be invalid, the coordinates of the enemy could be null or outside of the map.

    Update:

    Since you posted your code I can see the real problem, this.waterLayer / this.streetLayer are not defined, they are created as constants.

    The solution is: just define this.streetLayer (or this.waterLayer) at the end of the create function like this:

    create() {
      // your code
      this.streetLayer = streetLayer;
      // this.waterLayer = waterLayer;
    }
    

    than this scope issue should be solved.

    Fixing the code like this, the aforementioned "solution" with time is not really needed anymore.