Search code examples
javaandroidwindowslibgdxtiled

libGDX: How to implement a smooth tile / grid based game character movement?


In fear of reinventing the wheel, I wonder:

What is the best approach to implement a smooth grid based game character movement on a top-down Tiled (2D) map with libGDX?

The character should keep moving smoothly between tiles as long as an arrow key is pressed (or a touch event occures on certain direction of the character) and should finish confined to a grid position on key / touch release. The movement should be independent from the frame rate.

I would be glad about some already implemented examples that can be studied and lead to a proper libGDX API usage.


Solution

  • Test if a specific button is pressed (or screen touched), if it is, set the correct target tile (the tile where the player will go) in a field and start moving there, this Movement will only end when the player is in the next tile. When that happens, check for input again to keep moving (i.e. repeat).

    Lets suppose, your tile width/height is 1, and you want to move 1 tile per second. Your user pressed Right arrow key. Then you just set the targettile to the tile just right of the player.

    if(targettile!=null){
        yourobject.position.x += 1*delta;
        if(yourobject.position.x>=targettile.position.x){
            yourobject.position.x = targettile.position.x;
            targettile = null;
        }
    }
    

    This code is simplified for right movement only, you need to make it for the other directions too.
    Dont forget to poll the input again if the player is not moving.

    Edit:

    InputPolling for keys:

    if (Gdx.input.isKeyPressed(Keys.DPAD_RIGHT)){
    

    InputPolling for touchs (cam is your camera, and touchPoint is a Vector3 to store the unprojected touch coordinates, and moverightBounds a (libgdx) Rectangle):

    if (Gdx.input.isTouched()){
        cam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
        //check if the touch is on the moveright area, for example:
        if(moveRightBounds.contains(touchPoint.x, touchPoint.y)){
            // if its not moving already, set the right targettile here
        }
    }
    

    And noone already said it, you get the delta as a parameter in the render method, or you can get it anywhere else using:

    Gdx.graphics.getDeltatime();
    

    References: