Phaser.js中相机缩放时如何获取正确的瓦片位置?
在Phaser.js 3中处理相机缩放时的瓦片点击定位问题
你的代码存在两个关键问题,导致缩放时瓦片定位错误:
- 不要在
update函数内绑定事件:update每帧都会执行,你每帧都在添加新的pointerdown监听器,点击时会触发多次逻辑,既混乱又浪费性能,事件绑定只需在create中执行一次。 - 手动计算缩放坐标没必要:Phaser的
Pointer对象自带worldX/worldY属性,已经自动处理了相机的缩放、滚动等转换,直接使用即可,无需手动除以缩放级别。
修正后的完整代码
全局变量与preload函数
var game = new Phaser.Game(config); var map; var layer; var player; var controls; // 补充声明controls变量 function preload () { this.load.tilemapTiledJSON('tilemap', '/img/phaser/map.json'); this.load.image('base_tiles', '/img/phaser/outdoors.png'); this.load.spritesheet('player', '/img/phaser/dude.jpg', { frameWidth: 32, frameHeight: 48 }); }
create函数(添加点击事件)
function create () { map = this.make.tilemap({ key: 'tilemap' }); const tileset = map.addTilesetImage('outdoors', 'base_tiles'); layer = map.createLayer(0, tileset, 0, 0); player = this.add.sprite(500, 100, 'player', 4); var cursors = this.input.keyboard.createCursorKeys(); var controlConfig = { camera: this.cameras.main, left: cursors.left, right: cursors.right, up: cursors.up, down: cursors.down, zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q), zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E), acceleration: 0.06, drag: 0.0005, maxSpeed: 1.0 }; controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig); // 仅绑定一次点击事件 this.input.on("pointerdown", function (pointer) { // 直接使用pointer.worldX/worldY,自动适配相机状态 var tileX = layer.worldToTileX(pointer.worldX); var tileY = layer.worldToTileY(pointer.worldY); var tile = map.getTileAt(tileX, tileY); if (tile) { // 用map.tileToWorldXY获取瓦片左上角坐标,再加上半宽高得到中心 var worldPos = map.tileToWorldXY(tileX, tileY); var goalX = worldPos.x + map.tileWidth / 2; var goalY = worldPos.y + map.tileHeight / 2; this.tweens.add({ targets: player, x: goalX, y: goalY, duration: 1000, ease: 'Power4', }); } }, this); }
update函数(仅保留相机控制)
function update (time, delta) { controls.update(delta); // 无需在这里处理缩放或绑定事件 }
替代方案:使用相机的坐标转换方法
如果不想用pointer.worldX,也可以通过相机的getWorldPoint方法将屏幕坐标转为世界坐标:
this.input.on("pointerdown", function (pointer) { // 将屏幕坐标转为世界坐标 var worldPoint = this.cameras.main.getWorldPoint(pointer.x, pointer.y); var tileX = layer.worldToTileX(worldPoint.x); var tileY = layer.worldToTileY(worldPoint.y); // 后续逻辑同上... }, this);
额外说明
layer.worldToTileX/Y会考虑图层的位置偏移(如果图层不是从(0,0)开始),比直接用map.worldToTileX/Y更通用。- 使用
map.tileToWorldXY代替手动计算x*32+16,可以避免硬编码瓦片尺寸,适配不同大小的瓦片。
内容的提问来源于stack exchange,提问作者TKur
相关产品推荐
相关产品推荐

