1
\$\begingroup\$

I've been trying to use GestureListener to turn touchscreen into the effect of my dpad. It all works pretty much, but the touch-held (or longpress) is not always working. It mostly does work but will stutter every few seconds. I am fairly sure that I have implemented the interface properly and when reading my input handling code I feel like it should work but it doesn't. I'm almost certain it is to do with LongPress (and/or the transition between a TouchDown event into the LongPress event).

All I actually want to achieve here is have my LEFT and RIGHT dpad button make the player move whenever the finger is on it - smoothly.

At first I thought this might have been a physics/frame-rate issue, but it's not becoz if I setup desktop buttons they work fine, also the jump is always smooth and this is how i am sure it is the "button held down" scenario that is failing.

Please kind sirs please take a look at my code and see if you can find what is wrong.

Code: Select all package com.megabro.wasteland.screens;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapRenderer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.megabro.wasteland.sprites.Player;
import com.megabro.wasteland.tools.Constants;
import com.megabro.wasteland.tools.InputController;

public class GameScreen implements Screen, GestureDetector.GestureListener {
    Game game;
    SpriteBatch batch;

    OrthographicCamera camInner, camOuter;
    public Viewport v1, v2;

    Sprite handheldControllerSprite;

    public InputController inputController;

    TmxMapLoader mapLoader;
    TiledMap map;
    TiledMapRenderer mapRenderer;
    TiledMapTileLayer tileLayer;

    public World world = new World(new Vector2(0, -10f), true);
    Box2DDebugRenderer box2DDebugRenderer = new Box2DDebugRenderer();

    Player player;

    Vector3 touchPos = new Vector3();
    Rectangle touchRect = new Rectangle();

    public GameScreen(Game game) {
        this.game = game;
        batch = new SpriteBatch();
        handheldControllerSprite = new Sprite(new Texture("handheld-landscape.png"));
        camInner = new OrthographicCamera();
        camOuter = new OrthographicCamera();

        v1 = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), camOuter);
        v1.apply();
        handheldControllerSprite.setSize(v1.getWorldWidth(), v1.getWorldHeight());
        camOuter.setToOrtho(false);
        v2 = new FitViewport(Constants.GRID_WIDTH, Constants.GRID_HEIGHT, camInner);
        v2.setScreenBounds((int)(v1.getScreenX() + (v1.getWorldWidth() * 0.205f)), (int)(v1.getScreenY() + (v1.getWorldHeight() * 0.1f)), Constants.GRID_WIDTH, Constants.GRID_HEIGHT);
        handheldControllerSprite.setPosition(v1.getScreenX(), v1.getScreenY());


        inputController = new InputController(new Texture("debugRect.png"), v1);
        mapLoader = new TmxMapLoader();
        map = mapLoader.load("level01.tmx");
        mapRenderer = new OrthogonalTiledMapRenderer(map, 1f / Constants.PPM);

        v2.apply();
        camInner.position.set(v2.getWorldWidth() /2, v2.getWorldHeight() / 2,0);
        camInner.update();

        player = new Player(new Texture("debugRect.png"), this);


        // TODO: research more about these geturedetector parameters (particularly LongPressDuration, which appears to be the amount of time allowed BEFORE the longpress is called)
        //Gdx.input.setInputProcessor(new GestureDetector(5f, 10f, 0.1f, 5f, this));
        Gdx.input.setInputProcessor(new GestureDetector(5f, 2f, 1f, 20f, this));

        tileLayer = (TiledMapTileLayer)map.getLayers().get(0);


        // TODO: Make this into another class or method of its own called LoadLevel or something:
        for (MapObject object : map.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)){
            Rectangle rect = ((RectangleMapObject) object).getRectangle();
            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.StaticBody;
            bodyDef.position.set(rect.getX() / Constants.PPM + rect.getWidth() / 2 / Constants.PPM, rect.getY() / Constants.PPM + rect.getHeight() / 2 / Constants.PPM);

            Body body = world.createBody(bodyDef);

            PolygonShape shape = new PolygonShape();
            shape.setAsBox(rect.getWidth() / 2 / Constants.PPM, rect.getHeight() / 2 / Constants.PPM);
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = shape;
            body.createFixture(fixtureDef);
        }
        // TODO: Above probably needs to be moved to own class or method.
    }

    @Override
    public void show() {

    }

    @Override
    public void render(float delta) {
        update(delta);
        clearScreen();
        draw();
    }

    private void update(float delta) {
        world.step(1 / 45f, 6, 2);
        v2.apply();
        if (player.getX()> v2.getWorldWidth() / 2 && player.getX() < tileLayer.getTileWidth() * tileLayer.getWidth() - v2.getWorldWidth() ) {
            camInner.position.set(player.getX(), camInner.position.y ,0);
        }
        camInner.update();
        player.update(delta);


    }

    private void clearScreen() {
        Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    }

    private void draw() {
        mapRenderer.setView(camInner);
        mapRenderer.render();

        box2DDebugRenderer.render(world, camInner.combined);

        v1.apply();
        batch.setProjectionMatrix(camOuter.combined);
        batch.begin();
        handheldControllerSprite.draw(batch);
        inputController.drawDebug(batch);

        batch.end();

    }

    @Override
    public void resize(int width, int height) {
        v1.apply();
        v1.update(width, height);
        v2.apply();
        v2.update(width * Constants.GRID_WIDTH / Constants.BG_WIDTH, height * Constants.GRID_HEIGHT / Constants.BG_HEIGHT);
        v2.setScreenX((int)(v1.getScreenX() + (v1.getScreenWidth() * 0.205f)));
        v2.setScreenY((int)(v1.getScreenY() + (v1.getScreenHeight() * 0.1f)));
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {

    }

    @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
        v1.unproject(touchPos.set(x, y, 0));
        touchRect.set(touchPos.x, touchPos.y, 1,1);
        if (touchRect.overlaps(inputController.buttonOff.getBoundingRectangle())){
            Gdx.app.exit();
            return true;
        }
        if (touchRect.overlaps(inputController.buttonA.getBoundingRectangle())){
            player.jump();
            return true;
        }
        if (touchRect.overlaps(inputController.buttonB.getBoundingRectangle())){
            //player.walkSpeed = Constants.PLAYER_SPRINT_SPEED;
            return true;
        }
        if (touchRect.overlaps(inputController.padLeft.getBoundingRectangle())){
            player.move(false);
            return true;
        }
        if (touchRect.overlaps(inputController.padRight.getBoundingRectangle())){
            player.move(true);
            return true;
        }

        return false;
    }

    @Override
    public boolean tap(float x, float y, int count, int button) {
        return false;
    }

    @Override
    public boolean longPress(float x, float y) {
        v1.unproject(touchPos.set(x, y, 0));
        touchRect.set(touchPos.x, touchPos.y, 1,1);
//        if (touchRect.overlaps(inputController.buttonA.getBoundingRectangle())){
//            player.jump();
//            return true;
//        }
        if (touchRect.overlaps(inputController.buttonB.getBoundingRectangle())){
            //player.walkSpeed = Constants.PLAYER_SPRINT_SPEED;
            return true;
        }
        if (touchRect.overlaps(inputController.padLeft.getBoundingRectangle())){
            player.move(false);
            return true;
        }
        if (touchRect.overlaps(inputController.padRight.getBoundingRectangle())){
            player.move(true);
            return true;
        }

        return false;
    }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        return false;
    }

    @Override
    public boolean pan (float x, float y, float deltaX, float deltaY) {
        v1.unproject(touchPos.set(x, y, 0));
        touchRect.set(touchPos.x, touchPos.y, 1,1);
//        if (touchRect.overlaps(inputController.buttonA.getBoundingRectangle())){
//            player.jump();
//            return true;
//        }
        if (touchRect.overlaps(inputController.buttonB.getBoundingRectangle())){
            //player.walkSpeed = Constants.PLAYER_SPRINT_SPEED;
            return true;
        }
        if (touchRect.overlaps(inputController.padLeft.getBoundingRectangle())){
            player.move(false);
            return true;
        }
        if (touchRect.overlaps(inputController.padRight.getBoundingRectangle())){
            player.move(true);
            return true;
        }

        return false;

    }

    @Override
    public boolean panStop(float x, float y, int pointer, int button) {
        return false;
    }

    @Override
    public boolean zoom(float initialDistance, float distance) {
        return false;
    }

    @Override
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
        return false;
    }

    @Override
    public void pinchStop() {

    }


}

All I actually want to achieve here is have my LEFT and RIGHT dpad button make the player move whenever the finger is on it - smoothly.

At first I thought this might have been a physics/frame-rate issue, but it's not becoz if I setup desktop buttons they work fine, also the jump is always smooth and this is how i am sure it is the "button held down" scenario that is failing.

Please kind sirs please take a look at my code and see if you can find what is wrong.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.