You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 16:30:46