Phaser 3单图层多Tileset使用putTileAt的渲染与报错问题
Phaser 3 单图层多Tileset渲染异常问题
我正在用Phaser 3开发个人项目,之前用多个图层处理不同Tileset的瓦片,效果正常。但看到Phaser支持单图层使用多个Tileset,尝试合并成单图层后遇到了问题:放置指定Tileset的瓦片时,始终只会从第一个Tileset中提取对应索引的精灵。
将所有瓦片按网格排列后,出现如下渲染结果:
可以看到,虽然各Tileset的长度设置正确,但第一个精灵表被重复显示——先是第一个表的350个瓦片,接着是第二个表的约318个、第三个的60个、第四个的30个,全部显示第一个精灵表的内容。
初始实现代码
initTileSets() { // Initialize tilemap this.bgTilemap = this.scene.make.tilemap({ width: this.mapWidth, height: this.mapHeight, tileWidth: this.tileSize, tileHeight: this.tileSize }); // Add all tilesets to the tilemap this.terrainTiles = this.bgTilemap.addTilesetImage('terrainTileset'); this.terrainTiles2 = this.bgTilemap.addTilesetImage('terrainTileset2'); this.rogueTiles = this.bgTilemap.addTilesetImage('rogueTileset'); this.snowTiles = this.bgTilemap.addTilesetImage('snowTileset'); //Set the length of each tileset let terrainTilesetLength = this.terrainTiles.total; let terrainTileset2Length = this.terrainTiles2.total; let rogueTilesetLength = this.rogueTiles.total; let snowTilesetLength = this.snowTiles.total; //Set the first gid of each tileset to the total of the previous tileset this.terrainTiles.firstgid = 0; this.terrainTiles2.firstgid = terrainTilesetLength; this.rogueTiles.firstgid = terrainTilesetLength + terrainTileset2Length; this.snowTiles.firstgid = terrainTilesetLength + terrainTileset2Length + rogueTilesetLength; // Store tileset information this.tilesetsInfo = [ { name: 'terrainTileset', firstgid: this.terrainTiles.firstgid }, { name: 'terrainTileset2', firstgid: this.terrainTiles2.firstgid }, { name: 'rogueTileset', firstgid: this.rogueTiles.firstgid }, { name: 'snowTileset', firstgid: this.snowTiles.firstgid } ]; let allTilesets = [ this.terrainTiles, this.terrainTiles2, this.rogueTiles, this.snowTiles ]; // Create two main layers this.terrainLayer = this.bgTilemap.createBlankLayer('terrainLayer', allTilesets, 0, 0); this.detailLayer = this.bgTilemap.createBlankLayer('detailLayer', allTilesets, 0, 0); //log detaillayer console.log(this.detailLayer); // Optionally, you can manage all layers together if you need to apply settings to all this.allLayers = [ this.terrainLayer, this.detailLayer ]; } getTilesetForIndex(globalIndex) { for (let i = this.tilesetsInfo.length - 1; i >= 0; i--) { let tileset = this.tilesetsInfo[i]; if (globalIndex >= tileset.firstgid) { return this.bgTilemap.getTileset(tileset.name); } } return null; } placeTile(x, y, globalIndex, layer) { let tileset = this.getTilesetForIndex(globalIndex); if (!tileset) { console.error(`Tileset not found for global index: ${globalIndex}`); return; } //log name of tileset, first gid, and global index //console.log('tileset: ' + tileset.name + ' | firstgid: ' + tileset.firstgid + ' | globalIndex: ' + globalIndex); // Calculate the local tile index within the selected tileset let localIndex = globalIndex - tileset.firstgid; // Place the tile layer.putTileAt(localIndex, x, y, false, tileset.name); } getTotalTilesInLayer(layer) { let totalTiles = 0; layer.tileset.forEach(tileset => { totalTiles += tileset.total; }); return totalTiles; } placeDebugTileLine() { for (let i = 0; i < this.getTotalTilesInLayer(this.detailLayer); i++) { let row = Math.floor(i/25); let col = i % 25; this.placeTile(col, row, i, this.detailLayer); } }
我注意到placeTile()方法中,layer.putTileAt似乎忽略了最后一个tileset名称参数——即使传入无效的Tileset名称也能正常运行,这和文档描述不符。
更新后的问题
修改代码后,当map.putTileAt循环执行到i=350(第一个Tileset的长度上限)时,出现未定义错误:
修改后的代码
initTileSets2() { let map = this.scene.make.tilemap({ key:'map', width: 16, height: 16, tileWidth: 16, tileHeight: 16 }); // Add all tilesets to the tilemap let tiles1 = map.addTilesetImage('terrainTileset'); // 350 tiles let tiles2 = map.addTilesetImage('terrainTileset2'); // 324 tiles let tiles3 = map.addTilesetImage('rogueTileset'); // 60 tiles let tiles4 = map.addTilesetImage('snowTileset'); // 30 tiles //Set the first gid of each tileset to the total of the previous tileset tiles1.firstgid = 0; tiles2.firstgid = tiles1.total; tiles3.firstgid = tiles2.firstgid + tiles2.total; tiles4.firstgid = tiles3.firstgid + tiles3.total; let allTilesets = [ tiles1, tiles2, tiles3, tiles4 ]; let layer1 = map.createBlankLayer('layer1', allTilesets, 20, 50).setScale(0.75); let tilePerRow = 25; for (let i = 0; i < tiles4.firstgid; i++) { let col = i % tilePerRow; let row = Math.floor( i / tilePerRow ); console.log('i: ' + i + ' | col: ' + col + ' | row: ' + row); map.putTileAt( i, col, row ) } this.map = map; }
奇怪现象
如果不设置各Tileset的firstgid,且硬编码让循环在i=350时停止,会出现如下渲染结果:
这说明所有瓦片都已加载到地图中,但一旦设置firstgid避免堆叠,就会回到最初的重复渲染第一个Tileset的问题。
内容的提问来源于stack exchange,提问作者Daniel Dees
相关产品推荐
相关产品推荐

