简体   繁体   中英

LibGDX - Multitouch handling using InputProcessor

I am trying to set up proper multitouch support in my android game for some time. For input handling I use my InputHandler(implementing InputProcessor). I use something like this

    @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();
    }

and this

    @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();
    }

I have set up 3 buttons like that, but I have no idea why it doesn't work. All the answers I've found aren't very helpful when using InputProcessor.

I know that it has something to do with touch pointers and iterating input, but that's where my knowledge ends, unfortunately.

The code "when touched" and "when released" is working for sure, I'm using it the same way with keyboard input. The only problem is multitouch.

I encoutered similar problem once,trying to set up 3 buttons on screen. Those buttons can be pressed separately (then there is no problem, you always use just one finger and one pointer - therefore pointer ID can be ignored), but they should also react properly, if any two of them are pressed, or player presses all at once. You have to make use of pointer ID, given by InputProcessor. Pointer ID is an int from 0 to 9 range (for 10 fingers). I did it that way:

first declared three variables for three pointers:

int forwardPointer, leftPointer, rightPointer;

then in TouchDown method i checked, which finger pressed which button (was it first, second or third press?), and stored this information in my variables for future use.

@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;
    }}

and then, in TouchUp method i checked, which finger was lifted up (by comparing pointer ID from TouchUp method with stored pointer variable value), and according to this, i "relased" proper button.

    @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;
    }}

This worked for me. No need to use Gdx.input.getX(), Gdx.input.getY(), as those values are already given by touchDown and touchUp method (screenX and screenY).

You're mixing the libGDX input polling interfaces with the libGDX input event API. Specifically, these calls:

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

are equivalent to:

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

see the getX documentation . So you're always reading the x/y coordinates of the 0th touch index, independent of which touch is active.

The event API is passing in the x, y and pointerID to the callback , so you just need to do something like:

@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();
}

You should use the "pointer" parameter to distinguish fingers during multi-touch.

Since pointer value passed in event methods is a unique id of the touching finger, you can use a hashmap to store and manipulate all of the touches with that unique key.

Create a hashmap.

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

Add as new if touch is not present.

@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;
}

Remove if finger is up.

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

Update the corresponding touch event if finger is dragged

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

Key is the pointer and value is a vector that will store the touch coordinates. And to use them anywhere you want just iterate over the map

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM