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

LibGDX中Tiled地图鼠标悬停Tile偏移问题求助

解决LibGDX Tilemap鼠标悬停高亮偏移问题

核心问题分析

你的偏移问题主要来自三个方面:相机与渲染器矩阵不同步、Tile图层偏移未纳入坐标计算、ShapeRenderer错误的创建方式,手动缩放相机也容易导致坐标逻辑混乱。

具体修复步骤

1. 同步相机与Tilemap渲染器的矩阵

在render()方法中必须先更新相机状态,再将相机投影矩阵传递给渲染器,否则渲染的Tilemap与鼠标计算的世界坐标会错位:

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    // 更新相机状态
    camera.update();
    // 将相机矩阵同步给Tilemap渲染器
    renderer.setView(camera);
    renderer.render();

    // 执行鼠标检测逻辑
    checkTileUnderMouse();
}

2. 纳入Tile图层的偏移量计算

Tiled图层默认可能带有offsetX/offsetY属性,计算Tile坐标时必须减去这些偏移才能匹配实际位置:

private void checkTileUnderMouse() {
    Vector3 mousePos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
    Vector3 worldPos = camera.unproject(mousePos);

    int tileWidth = map.getProperties().get("tilewidth", Integer.class);
    int tileHeight = map.getProperties().get("tileheight", Integer.class);

    TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(0);
    // 获取图层自带的偏移量
    float layerOffsetX = layer.getOffsetX();
    float layerOffsetY = layer.getOffsetY();

    // 修正Tile坐标计算:减去图层偏移
    int tileX = (int) ((worldPos.x - layerOffsetX) / tileWidth);
    int tileY = (int) ((worldPos.y - layerOffsetY) / tileHeight);

    TiledMapTileLayer.Cell cell = layer.getCell(tileX, tileY);
    if (cell != null && cell.getTile() != null) {
        System.out.println("Mouse is over tile at (" + tileX + ", " + tileY + "), Tile ID: " + cell.getTile().getId());
    }

    debugTileUnderMouse(worldPos.x, worldPos.y, tileX, tileY, tileWidth, tileHeight, layerOffsetX, layerOffsetY);
}

3. 修正ShapeRenderer的使用方式

每次调用调试方法都新建并销毁ShapeRenderer会导致性能浪费和渲染状态异常,改为成员变量统一管理:

private ShapeRenderer shapeRenderer;

public void create() {
    map = new TmxMapLoader().load("1-1.tmx");
    camera = new OrthographicCamera();
    camera.setToOrtho(false, Gdx.graphics.getWidth() * 2, Gdx.graphics.getHeight() * 2);
    camera.position.set(220, 138, 0);
    camera.zoom = 0.129f;

    renderer = new OrthogonalTiledMapRenderer(map);
    // 初始化ShapeRenderer为成员变量
    shapeRenderer = new ShapeRenderer();
}

@Override
public void dispose() {
    map.dispose();
    renderer.dispose();
    // 统一销毁资源
    shapeRenderer.dispose();
}

// 调整调试方法,传入图层偏移量
private void debugTileUnderMouse(float worldX, float worldY, int tileX, int tileY, int tileWidth, int tileHeight, float layerOffsetX, float layerOffsetY) {
    shapeRenderer.setProjectionMatrix(camera.combined);
    shapeRenderer.begin(ShapeRenderer.ShapeType.Line);

    shapeRenderer.setColor(0, 1, 0, 1);
    // 绘制高亮框时加上图层偏移,匹配实际Tile位置
    shapeRenderer.rect(tileX * tileWidth + layerOffsetX, tileY * tileHeight + layerOffsetY, tileWidth, tileHeight);

    shapeRenderer.setColor(1, 0, 0, 1);
    shapeRenderer.circle(worldX, worldY, 5);

    shapeRenderer.end();
}

4. 优化相机设置(可选但推荐)

手动设置camera.zoom容易引发坐标逻辑混乱,建议使用Viewport管理视口,保持Tilemap比例正确:

private Viewport viewport;

public void create() {
    map = new TmxMapLoader().load("1-1.tmx");
    camera = new OrthographicCamera();
    // 使用FitViewport,参数为Tiled地图的像素宽高
    viewport = new FitViewport(1920, 1080, camera);
    camera.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);
    renderer = new OrthogonalTiledMapRenderer(map);
    shapeRenderer = new ShapeRenderer();
}

@Override
public void resize(int width, int height) {
    // 窗口尺寸变化时更新视口
    viewport.update(width, height);
}

验证修复

完成修改后,鼠标悬停的高亮框应与实际Tile位置完全对齐。若仍有偏移,可打印layerOffsetX/layerOffsetY的值,确认Tiled图层是否存在额外偏移设置。

内容的提问来源于stack exchange,提问作者Jack Lander

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:14:57