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);
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.