LibGDX - 使用 InputProcessor 的多点触控处理

LibGDX - Multitouch handling using InputProcessor

一段时间以来,我一直在尝试在我的 android 游戏中设置适当的多点触控支持。对于输入处理,我使用我的 InputHandler(实现 InputProcessor)。我用这样的东西

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
    screen.renderer.cam.unproject(touchPos);
    if (left.isTouchDown((int) touchPos.x, (int) touchPos.y)) {
        player.setMovingLeft(true);
        player.leftPressed();
    }

还有这个

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
    screen.renderer.cam.unproject(touchPos);
    if (left.isTouchUp((int) touchPos.x, (int) touchPos.y)) {
        player.setMovingLeft(false);
        player.leftReleased();
    }

我已经设置了3个这样的按钮,但我不知道为什么它不起作用。我找到的所有答案在使用 InputProcessor 时都不是很有帮助。

我知道它与触摸指针和迭代输入有关,但不幸的是,我的知识到此为止。

代码 "when touched" 和 "when released" 确实有效,我使用键盘输入的方式相同。唯一的问题是多点触控。

您将 libGDX 输入轮询接口与 libGDX 输入事件 API 混合在一起。具体来说,这些调用:

 Gdx.input.getX(), Gdx.input.getY()

相当于:

 Gdx.input.getX(0), Gdx.input.getY(0)

参见 the getX documentation。所以你总是在读取第 0 个触摸索引的 x/y 坐标,与哪个触摸处于活动状态无关。

事件 API 即将过去 in the x, y and pointerID to the callback,因此您只需要执行以下操作:

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPos = new Vector3(screenX, screenY, 0);
screen.renderer.cam.unproject(touchPos);
if (left.isTouchDown((int) touchPos.x, (int) touchPos.y)) {
    player.setMovingLeft(true);
    player.leftPressed();
}

多点触控时需要使用"pointer"参数来区分手指

我遇到过一次类似的问题,试图在屏幕上设置3个按钮。这些按钮可以单独按下(这样就没问题了,你总是只用一根手指和一根指针 - 因此指针 ID 可以忽略),但它们也应该正确反应,如果按下其中任何两个,或者玩家按下所有按钮立刻。 您必须使用 InputProcessor 提供的指针 ID。指针 ID 是一个从 0 到 9 范围的整数(对于 10 个手指)。 我是这样做的:

首先为三个指针声明了三个变量:

int forwardPointer, leftPointer, rightPointer;

然后在 TouchDown 方法中我检查了哪个手指按下了哪个按钮(是第一次、第二次还是第三次按下?),并将此信息存储在我的变量中以备将来使用。

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    if (game.forwardButton.contains(screenX, screenY)) {
        game.forwardButton.isPressed=true;
        forwardPointer=pointer; 
    }
    if (game.leftButton.contains(screenX, screenY)) {
        game.leftButton.isPressed=true;
        leftPointer=pointer;
    }
    if (game.rightButton.contains(screenX, screenY)) {
        game.rightButton.isPressed=true;
        rightPointer=pointer;
    }}

然后,在 TouchUp 方法中,我检查了哪个手指被抬起(通过比较来自 TouchUp 方法的指针 ID 与存储的指针变量值),并据此,我 "relased" 正确的按钮。

    @Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    if (pointer==forwardPointer) {
        game.forwardButton.isPressed=false;
    }
    if (pointer==leftPointer) {
        game.leftButton.isPressed=false;
    }
    if (pointer==rightPointer) {
        game.rightButton.isPressed=false;
    }}

这对我有用。无需使用 Gdx.input.getX()、Gdx.input.getY(),因为 这些值已经由 touchDown 和 touchUp 方法(screenX 和 screenY)给出。

由于在事件方法中传递的指针值是触摸手指的唯一 ID,您可以使用散列图来存储和操作具有该唯一键的所有触摸。

创建哈希图。

public static HashMap<Integer, Vector2> touchlist;
public Constructor(){
    touchlist=new HashMap<>();
}

如果触摸不存在,则添加为新的。

@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    if(!touchlist.containsKey(pointer))touchlist.put(pointer, new Vector2(screenX, screenY));
    return false;
}

如果手指向上,则移除。

@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    touchlist.remove(pointer);
    return false;
}

如果手指被拖动,更新相应的触摸事件

@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
    Vector2 touch=touchlist.get(pointer);
    if(touch!=null)touch.set(screenX, screenY);
    return false;
}

键是指针,值是将存储触摸坐标的向量。 要在任何地方使用它们,只需遍历地图

for(Integer key:touchlist.keySet()){
    Vector2 touchpos=touchlist.get(key);
    //do your manipulation here
    if(isvalid(touchpos)) //use if valid skip if not etc..
}