在Java Libgdx中正确使用unProject

15

我希望能够使一个按钮可点击,但它却不起作用——看起来我需要使用unproject(),但我无法弄清楚如何使用。有问题的代码是:

Texture playButtonImage;
SpriteBatch batch;
ClickListener clickListener;
Rectangle playButtonRectangle;
Vector2 touchPos;
OrthographicCamera camera;

@Override
public void show() {
    playButtonImage = new Texture(Gdx.files.internal("PlayButton.png"));

    camera = new OrthographicCamera();
    camera.setToOrtho(false, 800, 480);
    batch = new SpriteBatch();

    playButtonRectangle = new Rectangle();
    playButtonRectangle.x = 400;
    playButtonRectangle.y = 250;
    playButtonRectangle.width = 128;
    playButtonRectangle.height = 64;
}

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

    camera.update();
    batch.setProjectionMatrix(camera.combined);

    batch.begin();
    batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
    batch.end();

    if (Gdx.input.isTouched()) {
        Vector2 touchPos = new Vector2();
        touchPos.set(Gdx.input.getX(), Gdx.input.getY());


        if (playButtonRectangle.contains(touchPos)) {
            batch.begin();
            batch.draw(playButtonImage, 1, 1);
            batch.end();
        }
    }
}

屏幕坐标(0,0)可能在左上角,但相机的坐标(0,0)在左下角。如果使用Gdx.input.getY()*-1会发生什么? - Ryan
4个回答

13

通常情况下,您使用camera.unproject(Vector)将您的屏幕坐标从点击或触摸转换为游戏世界中的坐标。这是必需的,因为起点不一定相同,并且使用相机您还可以缩放,移动,旋转等。通过取消投影来处理所有这些,并为您提供与指针位置匹配的游戏世界坐标。

在您的示例中,它会像这样进行:

Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);

话虽如此,你实际上不应该手动完成此UI任务。Libgdx还具有一些内置的UI功能,称为Stage(请参见此处)。已经有许多小部件可供使用(请参见此处)。它们使用皮肤(您可以从此处获取基本皮肤,您需要所有的uiskin.*文件)。它们自动将输入事件转发到所谓的Actors(例如按钮),您只需要实现处理这些事件。


2
正如我在答案中所述,每当触摸时初始化一个新的Vector3对象会引入很多开销。GC周期对于时间关键型应用程序(如游戏)来说非常重要,尤其是在移动设备上更糟糕;而libgdx也是为移动设备构建的。 - laubed
你也可以使用Pools来解决初始化新Vector3的问题。 - bazola

4
使用camera.unproject(Vector3),可以将屏幕坐标转换为游戏世界坐标。
Vector3 tmpCoords = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);

tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.

除此之外,最佳实践是将tmpVector定义为字段,并仅实例化一个Vector3对象。然后可以使用.set()方法执行相同的操作。

tmpCoords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);

tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.

因此,您减少了对象的创建并消除了不必要的GC调用,从而导致微小的延迟。

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

camera.update();
batch.setProjectionMatrix(camera.combined);

batch.begin();
batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
batch.end();

if (Gdx.input.isTouched()) {
    Vector3 touchPos = new Vector3();
    touchPos.set(Gdx.input.getX(), Gdx.input.getY(),0);
    camera.unproject(touchPos);


    if (playButtonRectangle.contains(touchPos.x, touchPos.y)) {
        batch.begin();
        batch.draw(playButtonImage, 1, 1);
        batch.end();
    }
   }
   }

0

每当您需要从用户获取触点并将这些触点转换为相机时,您需要通过相机坐标对它们进行反投影。

camera.unproject(touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接