Phaser世界编辑器切换放置模式触发TypeError问题求助
问题:Phaser世界编辑器切换到瓦片放置模式时出现TypeError错误
我用JavaScript基于Phaser框架开发自定义世界编辑器,能加载文件夹里的独立瓦片并展示,点击选瓦片功能正常,但切换到瓦片放置模式时,出现错误:TypeError: Cannot read properties of undefined (reading 'width')。
已经检查过变量定义但可能有遗漏,把箭头函数换成普通函数后问题依旧,执行console.log(this.map)输出undefined。
完整代码如下:
class WorldEditor extends Phaser.Scene { constructor() { super("editWorld") this.tileSize = 48 this.tileIndex = 0 this.tileFolder = 'Assets/Tiles/' this.tilesPerRow = 37 this.totalTiles = 160 this.tilePicked = false } preload() { // Load tile images from the folder for (let i = 0; i < this.totalTiles; i++) { this.load.image('tile (' + i + ')', this.tileFolder + 'tile (' + i + ').png') } } create() { const tileWidth = this.tileSize const tileHeight = this.tileSize const tilesPerRow = this.tilesPerRow if(!this.map){ this.map = this.make.tilemap({ tileWidth: this.tileSize, tileHeight: this.tileSize, width: 1200, height: 720 }) } for (let i = 0; i < this.totalTiles; i++) { const x = ((i % tilesPerRow) * tileWidth)/1.48 const y = (Math.floor(i / tilesPerRow) * tileHeight)/1.48 this.tile = this.add.image(x, y, 'tile (' + i + ')') this.tile.setOrigin(0) this.tile.setScale((tileWidth / this.tile.width)/1.48, (tileHeight / this.tile.height)/1.48) } // Set up pointer events this.setupPointerEvents() // Keyboard event to switch back to tile selection this.input.keyboard.on('keydown-F', () => { this.tilePicked = false console.log('Switched back to tile selection') this.setupPointerEvents() // Update pointer events after switching back }) } setupPointerEvents() { this.input.off('pointerdown') if (!this.tilePicked) { const tiles = this.children.list.filter(child => child.texture && child.texture.key.startsWith('tile (')) tiles.forEach((tile, i) => { tile.setInteractive() tile.on('pointerdown', function() { this.tileIndex = i this.tilePicked = true tile.setTint(0xff0000) console.log('Selected tile index:', this.tileIndex) this.setupPointerEvents() }, this) }) } else { this.input.on('pointerdown', function(pointer) { this.tileX = Math.floor(pointer.x / this.tileSize) this.tileY = Math.floor(pointer.y / this.tileSize) this.placeTile(this.tileX, this.tileY) }, this) } } // Other methods... placeTile(tileX, tileY) { this.map.putTileAt(this.tileIndex, tileX, tileY) } // Implement saveMap and loadMap functions to save and load level data }
问题分析与解决方案
核心问题
this.map虽然被创建,但未关联任何瓦片集(Tileset),Phaser的putTileAt方法需要依赖瓦片集的尺寸信息才能正常工作,导致读取width属性时触发undefined错误。同时原代码中if(!this.map)的判断多余,Scene初始化时this.map必然是undefined,可能引发不必要的逻辑混乱。
具体修复步骤
创建瓦片集并关联图层
在create方法中,创建tilemap后必须添加瓦片集,并创建用于放置瓦片的图层:// 替换原create方法中的map初始化部分 this.map = this.make.tilemap({ tileWidth: this.tileSize, tileHeight: this.tileSize, width: 1200, height: 720 }) // 关联已加载的瓦片图像到瓦片集,第一个参数用任意已加载的tile纹理名即可 this.tileset = this.map.addTilesetImage('tile (0)', null, this.tileSize, this.tileSize) // 创建图层用于显示放置的瓦片 this.layer = this.map.createLayer(0, this.tileset, 0, 0)修正
placeTile方法
确保putTileAt指定目标图层,同时增加基础校验:placeTile(tileX, tileY) { if (!this.map || !this.tileset) return; this.map.putTileAt(this.tileIndex, tileX, tileY, true, this.layer) }优化瓦片选择逻辑
避免循环中覆盖this.tile全局属性,同时取消之前选中瓦片的 tint:// 替换原create方法中的瓦片循环部分 for (let i = 0; i < this.totalTiles; i++) { const x = ((i % tilesPerRow) * tileWidth)/1.48 const y = (Math.floor(i / tilesPerRow) * tileHeight)/1.48 // 用局部变量tile,避免覆盖全局属性 const tile = this.add.image(x, y, 'tile (' + i + ')') tile.setOrigin(0) tile.setScale((tileWidth / tile.width)/1.48, (tileHeight / tile.height)/1.48) } // 替换setupPointerEvents中tile的pointerdown事件逻辑 tiles.forEach((tile, i) => { tile.setInteractive() tile.on('pointerdown', function() { this.tileIndex = i this.tilePicked = true // 清除所有瓦片的tint,避免多个瓦片变红 tiles.forEach(t => t.clearTint()) tile.setTint(0xff0000) console.log('Selected tile index:', this.tileIndex) this.setupPointerEvents() }, this) })
内容的提问来源于stack exchange,提问作者Duckpedia
相关产品推荐
相关产品推荐

