любой может подсказать в общих чертах, как добиться следующего с помощью Phaser 3:
Мне нужно иметь возможность использовать console.info() обновленным способом, когда включен спрайт врага свойств плитки или местности. Идея состоит в том, чтобы обновить анимацию персонажа, если он находится на воде или на суше. Я пытался console.info(this.streetLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true);, но карта мира не определена в методе update(). Или есть более простой способ добиться этого? Моя игра — это ролевая игра с видом сверху. Вот полный код:
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.info('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.info('Street Layer:', streetLayer); // Log the street layer object to check if it's properly created
console.info('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.info("enemy on street");
} else {
this.enemy.play('enemy_move_water');
console.info("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.info(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);



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ну, не зная вашего кода (соответствующих частей кода), потому что вы поделились слишком мало. Я просто могу сказать, что вы можете просто добавить таймер в свою функцию create. Что-то вроде этого:
let timedEvent = this.time.addEvent({
delay: 1000, // once every second = 1000ms
callback: () => console.info(
this.streetLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true)
),
loop: true,
});
Это будет выводить плитку/свойство каждую секунду.
Я бы не рекомендовал это для производства, но, не зная соответствующих частей вашего кода, это решение, которое должно работать (если в вашем коде нет других ошибок. Чтобы убедиться, проверьте консоль браузера).
Если это по-прежнему приводит к undefined/null, возможно, слой недействителен, координаты врага могут находиться в null или находиться за пределами карты.
Обновлять:
Поскольку вы опубликовали свой код, я вижу реальную проблему: this.waterLayer/this.streetLayer не определены, они создаются как константы.
Решение: просто определите this.streetLayer (или this.waterLayer) в конце функции create следующим образом:
create() {
// your code
this.streetLayer = streetLayer;
// this.waterLayer = waterLayer;
}
чем эта проблема объема должна быть решена.
После такого исправления кода вышеупомянутое «решение» с
timeбольше не нужно.
Проблема в том, что this.waterLayer не существует. Просто добавьте this.waterLayer = waterLayer; в конце функции create и все должно работать.
@AftersunLotion, кстати. теперь вы можете вызвать код напрямую, таймер не требуется, поскольку основная ошибка/проблема решена.
Отлично, это сработало. Ты мужчина. Следующая проблема заключается в том, что анимация в методе обновления воспроизводит только первый кадр... Далее нужно решить эту проблему.
@AftersunLotion, конечно, без проблем. :) кстати: для вашей проблемы с анимацией просто добавьте true в метод play в качестве второго параметра (ссылка на документацию). .play("enemy_move_street", true). Это должно решить вашу проблему.
Спасибо, это тоже сработало. Удачи!
Хорошее решение, попытался создать с его помощью новый метод класса, но через секунду результат стал неопределенным. Набор плиток и слои отображаются хорошо при регистрации, но по какой-то причине этот getTileAtWorldXY просто не работает со мной. Все должно быть в границах мира, а сумма плиток равна размеру карты.