Search code examples
javaandroidinputlibgdxgesture

Libgdx - Input Processing [Android]. What am I not getting about Listeners?


I've looked into numerous different ways to process input for android but I really can't get my head around it. I'm wondering with the code I provide you, could someone explain to me how I can integrate either approach into my code? and why it is appropriate to do so?

Firstly, I'll explain what my intentions are and show you a quick overview of the relevant code. I'm wanting to move my character, left, right and jump (for the time being). This is my first game, it's a portrait (somewhat similar context as Doodle Jump in regards to rendering) game without the automatic jumping. I'm got my level generated randomly, it renders all objects. Now I want to add input, but the main confusion is for me where do I put the code in my code?

Firstly, I have a GameObject class and a sub class DynamicGameObject, this is the super class for all objects inside the world (platforms, powerups, coins, player, enemies etc)

GameObject.java

public class GameObject {
    public final Vector2 position;
    public final Rectangle bounds;

    public GameObject (float x, float y, float width, float height) {
        this.position = new Vector2(x, y);
        this.bounds = new Rectangle(x - width / 2, y - height / 2, width, height);
    }

DynamicGameObject.java

public class DynamicGameObject extends GameObject {
    protected static Vector2 velocity;
    public final Vector2 accel;

    public DynamicGameObject (float x, float y, float width, float height) {
        super(x, y, width, height);
        setVelocity(new Vector2());
        accel = new Vector2();
    }

    public Vector2 getVelocity() {
        return velocity;
}

public void setVelocity(Vector2 velocity) {
    DynamicGameObject.velocity = velocity;
}
}

And then I have the main game object in which will be moving upon the actions I'll implement. In this class would I be putting any input processing?

Ruben. java [relevant code]

public Ruben (float x, float y) {
    super(x, y, RUBEN_WIDTH, RUBEN_HEIGHT);
    state = RUBEN_STATE_IDLE;
    stateTime = 0;
    grounded = true;
    facingRight = true;
    }

public void update (float deltaTime) {
    //getVelocity().add(World.gravity.x * deltaTime, World.gravity.y * deltaTime);
    position.add(velocity.x * deltaTime, velocity.y * deltaTime);
    bounds.x = position.x - bounds.width / 2;
    bounds.y = position.y - bounds.height / 2;

    if (position.x < 0) position.x = World.WORLD_WIDTH;
    if (position.x > World.WORLD_WIDTH) position.x = 0;
    stateTime += deltaTime;
}

Then I have the world class that will update everything inside the game, The relevant update method will be where ruben gets updated, shown here:

private void updateRuben (float deltaTime, float accelX) {


    if (ruben.getState() != Ruben.RUBEN_STATE_IDLE && ruben.position.y <= 0.5f) ruben.hitPlatform();
    if (ruben.getState() != Ruben.RUBEN_STATE_IDLE) ruben.getVelocity().x = -accelX / 10 * Ruben.RUBEN_MOVE_VELOCITY;

    // clamp the velocity to the maximum, x-axis only
            if (Math.abs(ruben.getVelocity().x) > Ruben.RUBEN_MAX_VELOCITY) {
                ruben.getVelocity().x = Math.signum(ruben.getVelocity().x) * Ruben.RUBEN_MAX_VELOCITY;
            }

            // clamp the velocity to 0 if it's < 1, and set the state to standing
            if (Math.abs(ruben.getVelocity().x) < 1) {
                ruben.getVelocity().x = 0;
                if (Ruben.isGrounded()) {
                    Ruben.setState(Ruben.RUBEN_STATE_IDLE);
                }
            }

    ruben.getVelocity().scl(deltaTime);
    ruben.update(deltaTime);
    heightSoFar = Math.max(ruben.position.y, heightSoFar);
}

So Now i'm hoping you get the general context of the actor i'm dealing with, where would I go about putting a gesture listener callback? Do I put it into ruben? or do I create a seperate class altogether? I've tried out so many different ways and I'm not really getting anywhere it's abit frustrating. Where does the input handler go for the gestures? I tried putting the callback for a gesture detector with a new gesture listener inside the constructor of Ruben

(GestureDetector gd = new GestureDetector(new GestureHandler(this));

and then using a variable to indicate a fling has been directed upwards on the screen, when the boolean trigger is true, set the state of ruben to jump and change the velocity on y axis. It still didn't work. Can someone help?

if you need anything else, let me know.

Main game class

public class GameView extends Game {
    // used by all screens
    public SpriteBatch batcher;
    @Override
    public void create () {
        batcher = new SpriteBatch();
        Settings.load();
        Assets.loadBackgrounds();
        Assets.loadItems();
        Assets.loadRuben();
        setScreen(new MainMenuScreen(this));

    }

    @Override
    public void render() {
        super.render();
    }
}

Solution

  • If you want to use an InputAdapter like the GestureDetector in libGdx you must set it, don't know if you do so, else there won't be any method called from the GestureDetector. Hope that's the main problem. GestureDetector LibGdx Wiki

        Gdx.input.setInputProcessor(new GestureDetector(new GestureHandler(this)));
    

    Also if you want to use multiple InputAdapter you have to use an InputMultiplexer especially if you also want to use a Stage for GUI things. Event Handling LibGdx Wiki

        InputMultiplexer inputMultiplexer = new InputMultiplexer();
        inputMultiplexer.addProcessor(stage);
        inputMultiplexer.addProcessor(new GestureDetector(new GestureHandler(this)));
        Gdx.input.setInputProcessor(inputMultiplexer);
    

    EDIT: My preferred way to implement it with a Screen is MainMenuScreen extends Screen implements GestureDetector.GestureListener and in the show() method Gdx.input.setInputProcessor(new GestureDetector(this)); then you have also easy access to the objects you want to control from the methods.