Phaser 3:实时输出敌人地形瓦片属性及切换动画问题求助
问题描述
我正在开发一款俯视视角RPG游戏,需求是实时通过console.log()输出敌人精灵所在的瓦片或地形属性,以此切换敌人在陆地或水中的动画。尝试使用console.log(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.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);
解决方案
1. 修复图层作用域问题
你在create方法里用const定义的streetLayer和waterLayer是局部变量,update方法无法访问。改成赋值给场景实例属性,就能全局调用:
// 在create方法里替换图层创建代码 this.streetLayer = map.createLayer('street', Tileset, 0, 0); this.waterLayer = map.createLayer('water', Tileset, 0, 0);
2. 优化地形检测逻辑
不要在updateInfo里重复创建定时事件(每次update调用都会新建一个,导致重复输出),直接在update里控制检测频率:
// 在场景类中添加属性记录上次检测时间 lastTerrainCheck = 0; update() { // ... 其他原有代码 this.physics.moveToObject(this.enemy, this.protagonist, this.enemy.speed); // 每100ms检测一次地形(可根据需求调整间隔) const now = this.time.now; if (now - this.lastTerrainCheck > 100) { this.checkEnemyTerrain(); this.lastTerrainCheck = now; } } checkEnemyTerrain() { // 获取敌人所在位置的瓦片 const waterTile = this.waterLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true); const streetTile = this.streetLayer.getTileAtWorldXY(this.enemy.x, this.enemy.y, true); let currentTerrain; // 根据你设置的碰撞瓦片ID判断地形 if (waterTile && waterTile.index === 188) { currentTerrain = "water"; } else if (streetTile && streetTile.index === 0) { currentTerrain = "street"; } console.log(`Enemy is on: ${currentTerrain}`); // 仅当地形变化时切换动画,避免重复播放 if (currentTerrain !== enemy_terrain) { enemy_terrain = currentTerrain; this.enemy.play(`enemy_move_${currentTerrain}`, true); } }
3. 额外规范优化
- 把全局变量
enemy_terrain改成场景实例属性this.enemyTerrain,避免全局污染,更符合代码规范。 - 动画播放时添加
true参数,确保动画能正确切换或重启。
内容的提问来源于stack exchange,提问作者Aftersun Lotion
相关产品推荐
相关产品推荐

