vladutelu
vladutelu

Reputation: 157

LibGDX button not working properly?

I am so confused at the moment. You know that feeling when your app should be working just fine, but it isn't for some reason?!

In my app's PlayState, I have 3 states, defined by the variable "currentState".

currentState = 0 = Running

currentState = 1 = Pause

currentState = 2 = Game Over

public class PlayState extends State {
public static final int TUBE_SPACING = 420;
private static final int TUBE_COUNT = 4;
public static SpriteBatch batch;

public static Preferences prefs;

private Array<Tube> tubes;
private Array<Coin> coins;
private boolean hasBeenPlayed = false;

private Texture pausemenu, coin, bg, grass, gameover;
private Sound boop, wow, ding;
private Music failed;


private Bird bird;
private Vector2 groundPos1, groundPos2, groundPos3;
private PlayStateButtons pauseButton;

private BitmapFont highScoreFont, coinsFont, font120;

private Viewport viewport;

private int score = 0;
private int gameState;
private boolean tableVisible, restartVisible;
public PlayState(GameStateManager gsm, AssetLoader assets) {
    super(gsm, assets);
    initFonts();
    gameState = 0;
    hasBeenPlayed = false;
    tableVisible = false;
    restartVisible = false;

    viewport = new StretchViewport(720, 1280,cam);
    viewport.apply();
    cam.position.set(cam.viewportWidth / 2, cam.viewportHeight / 2,0);

    batch = new SpriteBatch();
    bg = assets.manager.get("textures/bg2.png", Texture.class);
    pausemenu = assets.manager.get("pausemenu.png", Texture.class);
    grass = assets.manager.get("grass.png", Texture.class);
    gameover = assets.manager.get("gameover.png", Texture.class);
    boop = assets.manager.get("boop.wav", Sound.class);
    failed = assets.manager.get("failed.wav", Music.class);
    wow = assets.manager.get("wow.wav", Sound.class);
    coin = assets.manager.get("coin.png", Texture.class);
    ding = assets.manager.get("ding.wav", Sound.class);

    prefs = Gdx.app.getPreferences("Bird");
    if (!prefs.contains("highScore")) {
        prefs.putInteger("highScore", 0);
    }
    if (!prefs.contains("coins"))
        prefs.putInteger("coins", 0);

    bird = new Bird(100, 375, assets);

    tubes = new Array<Tube>();
    coins = new Array<Coin>();

    pauseButton = new PlayStateButtons(assets);

    for (int i = 1; i <= TUBE_COUNT; i++){
        tubes.add(new Tube(i * (TUBE_SPACING + Tube.TUBE_WIDTH),assets));
    }
    for(int i = 1; i<= 2; i++)
        coins.add(new Coin(2 * i * (TUBE_SPACING + Tube.TUBE_WIDTH),assets));

    }

public static void setHighScore(int val) {
    prefs.putInteger("highScore", val);
    prefs.flush();
}
public void addCoin(){
    ding.play();
    prefs.putInteger("coins", prefs.getInteger("coins") + 1);
    prefs.flush();
}
public static int getHighScore() {
    return prefs.getInteger("highScore");
}
public int getCoins() { return prefs.getInteger("coins"); }




private void initFonts(){
    font120 = assets.manager.get("fonts/myfont.ttf", BitmapFont.class);
    highScoreFont = assets.manager.get("fonts/highscore.ttf", BitmapFont.class);
    coinsFont = assets.manager.get("fonts/coins.ttf", BitmapFont.class);

}
@Override
public void resize(int width, int height){
    viewport.update(width, height);
    cam.position.set(cam.viewportWidth / 2, cam.viewportHeight / 2,0);
}

@Override
public void handleInput() {
    if (Gdx.input.justTouched() && gameState == 0){
        wow.play(0.6f);
        bird.jump();
}
    if(pauseButton.isPauseButtonPressed() && gameState != 1) {
        boop.play(0.9f);
        gameState = 1;
        bird.die();
    }
    if(gameState == 2) {
        if(pauseButton.isRestartPressed())
            gsm.set(new PlayState(gsm, assets));
    }

    if(gameState == 1) {
        if (pauseButton.isResumePressed()) {
            boop.play(0.9f);
            gameState = 0;
            bird.resume();
        }
        if (pauseButton.isMenuPressed()) {
            boop.play(0.9f);
            gsm.set(new MenuState(gsm, assets));}
        if (pauseButton.isShopPressed()) {
            boop.play(0.9f);
            gsm.set(new ShopStateFaces(gsm, assets));
            }
        }

    }

@Override
public void update(float dt) {
    handleInput();
    updateGround();
    if(gameState == 0 && tableVisible){
        pauseButton.removePauseButtons();
        pauseButton.pauseVisible();
        tableVisible = false;
    }
    else if(gameState == 2 && !restartVisible) {
        pauseButton.restartVisible();
        restartVisible = true;
    }
    else if(gameState == 1 && !tableVisible) {
        pauseButton.restartInvisible();
        pauseButton.pauseInvisible();
        pauseButton.displayPauseButtons();
        tableVisible = true;
    }

    bird.update(dt);
    cam.position.x = bird.getPosition().x + 80;

    for(Tube tube : tubes){
        if(cam.position.x - cam.viewportWidth / 2 > tube.getPosTopTube().x + TUBE_WIDTH + 300) {
            tube.reposition(tube.getPosTopTube().x + (TUBE_WIDTH + TUBE_SPACING) * TUBE_COUNT);
            tube.setScored(false);
        }
        if(tube.collides(bird.getBounds())) {
            if(!hasBeenPlayed) {
                failed.play();
            }
            gameState = 2;
            bird.die();
            if(score > getHighScore())
                setHighScore(score);
            hasBeenPlayed = true;
            return;
        }
        if (!tube.isScored() && bird.getPosition().x > tube.getPosTopTube().x + TUBE_WIDTH /2 + 300) {
            addScore(1);
            tube.setScored(true);
    }
    }
    for(Coin coin : coins){
        if(cam.position.x - cam.viewportWidth / 2 > coin.getPosCoin().x + 100 + 300){
            coin.reposition(coin.getPosCoin().x + (TUBE_WIDTH + TUBE_SPACING) * TUBE_COUNT);
        }
        if(coin.touches(bird.getBounds())){
            addCoin();
            coin.reposition(coin.getPosCoin().x + 4 * (TUBE_WIDTH + TUBE_SPACING));
        }
    }
    cam.update();
    if (bird.getPosition().y <= grass.getHeight() - 40) {
        if(!hasBeenPlayed) {
            failed.play();
        }
        gameState = 2;
        bird.die();
        if(score > getHighScore())
            setHighScore(score);
        hasBeenPlayed = true;
    }
    if(gameState != 2)
        failed.stop();
}

public void addScore(int increment) {
    score += increment;
}


@Override
public void render(SpriteBatch sb) {
    cam.update();
    sb.setProjectionMatrix(cam.combined);
    Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    sb.begin();
    sb.setColor(Color.WHITE);
    sb.draw(bg, cam.position.x - cam.viewportWidth / 2, 0, cam.viewportWidth, cam.viewportHeight);
    for(Coin coin : coins){
        sb.draw(coin.getCoin(), coin.getPosCoin().x + 300, coin.getPosCoin().y, 100, 100);
    }

    sb.draw(bird.getTexture(), bird.getPosition().x, bird.getPosition().y, bird.getBounds().getWidth(), bird.getBounds().getHeight());

    for (Tube tube : tubes) {
            sb.draw(tube.getTopTube(), tube.getPosTopTube().x + 300, tube.getPosTopTube().y, 230, 1660);
            sb.draw(tube.getBottomTube(), tube.getPosBotTube().x + 300, tube.getPosBotTube().y, 230, 1660);}
        sb.draw(grass, groundPos1.x, groundPos1.y);
        sb.draw(grass, groundPos2.x, groundPos2.y);
        sb.draw(grass, groundPos3.x, groundPos3.y);
        font120.draw(sb, score + "", cam.position.x - 29, cam.viewportHeight - 100, 100, Align.center, false);
    String highScore = getHighScore() + "";
    String coins = getCoins() + "";

   if(gameState == 2){
        sb.draw(gameover, cam.position.x - gameover.getWidth() / 2 - 85 , cam.viewportHeight / 2 - gameover.getHeight() / 2, 600 , 500);
        highScoreFont.draw(sb, "Highscore: " + highScore, cam.position.x - highScoreFont.getScaleX() / 2 - 250 , cam.viewportHeight - 425, 500, Align.center, true);
        coinsFont.draw(sb, coins, cam.position.x - coinsFont.getScaleX() / 2 - 195, cam.viewportHeight - 590, 500, Align.center, true);
       sb.draw(coin, cam.position.x - 95, cam.viewportHeight - 660, 90, 90);
   }
    else if(gameState == 1){
        sb.draw(pausemenu, cam.position.x - 315,cam.viewportHeight / 2 - 625 / 2, 625, 625);
    }
    sb.end();
    pauseButton.act();
    pauseButton.draw();
}

@Override
public void dispose() {

}
}

I have a different class where I created all the buttons for the PlayState class, called PlayStateButtons.

public class PlayStateButtons {
private Viewport viewport;
private Stage stage;
boolean pauseButtonClicked, RestartPressed, shopPressed, resumePressed, menuPressed;
OrthographicCamera cam;
private Table table;
private Button shopButton, menuButton, resumeButton, restartButton, pauseButton;
private Skin pauseButtonSkin, resumeButtonSkin, menuButtonSkin, restartButtonSkin, shopButtonSkin;


public PlayStateButtons(AssetLoader assets){
    cam = new OrthographicCamera();
    viewport = new StretchViewport(720,1280, cam);
    viewport.apply();
    stage = new Stage(viewport, PlayState.batch);
    Gdx.input.setInputProcessor(stage);
    table = new Table();
    stage.addActor(table);

    Button.ButtonStyle pauseButtonStyle = new Button.ButtonStyle();
    pauseButtonSkin = new Skin(assets.manager.get("pauseButton.atlas", TextureAtlas.class));
    pauseButtonStyle.up = pauseButtonSkin.getDrawable("pausebutton");
    pauseButtonStyle.down = pauseButtonSkin.getDrawable("pausebutton2");
    pauseButton = new Button(pauseButtonStyle);
    pauseButton.setPosition(55, 1150);
    pauseButton.setSize(70, 70);
    stage.addActor(pauseButton);
    pauseButton.addListener(new ClickListener(){
        @Override
        public void clicked(InputEvent event, float x, float y) {
            pauseButtonClicked = true;
        }
    });

    Button.ButtonStyle restartButtonStyle = new Button.ButtonStyle();
    restartButtonSkin = new Skin(assets.manager.get("restartButton.atlas", TextureAtlas.class));
    restartButtonStyle.up = restartButtonSkin.getDrawable("restartbutton");
    restartButtonStyle.down = restartButtonSkin.getDrawable("restartbutton.down");
    restartButton = new Button(restartButtonStyle);
    restartButton.setSize(350, 90);
    restartButton.setPosition(cam.viewportWidth / 2 - restartButton.getWidth() / 2, 525);
    stage.addActor(restartButton);
    restartButton.setVisible(false);
    restartButton.addListener(new ClickListener(){
        @Override
        public void clicked(InputEvent event, float x, float y) {
            RestartPressed = true;
        }
    });

    Button.ButtonStyle resumeButtonStyle = new Button.ButtonStyle();
    resumeButtonSkin = new Skin(assets.manager.get("resumeButton.atlas", TextureAtlas.class));
    resumeButtonStyle.up = resumeButtonSkin.getDrawable("resumebutton");
    resumeButtonStyle.down = resumeButtonSkin.getDrawable("resumebutton.down");
    resumeButton = new Button(resumeButtonStyle);
    stage.addActor(resumeButton);
    resumeButton.addListener(new ClickListener(){
        @Override
        public void clicked(InputEvent event, float x, float y) {
            resumePressed = true;
        }
    });

    Button.ButtonStyle menuButtonStyle = new Button.ButtonStyle();
    menuButtonSkin = new Skin(assets.manager.get("menuButton.atlas", TextureAtlas.class));
    menuButtonStyle.up = menuButtonSkin.getDrawable("menubutton");
    menuButtonStyle.down = menuButtonSkin.getDrawable("menubutton.down");
    menuButton = new Button(menuButtonStyle);
    stage.addActor(menuButton);
    menuButton.addListener(new ClickListener(){
        @Override
        public void clicked(InputEvent event, float x, float y) {
            menuPressed = true;
        }
    });

    Button.ButtonStyle shopButtonStyle = new Button.ButtonStyle();
    shopButtonSkin = new Skin(assets.manager.get("shopButton.atlas", TextureAtlas.class));
    shopButtonStyle.up = shopButtonSkin.getDrawable("shopbutton");
    shopButtonStyle.down = shopButtonSkin.getDrawable("shopbutton.down");
    shopButton = new Button(shopButtonStyle);
    stage.addActor(shopButton);
    shopButton.addListener(new ClickListener(){
        @Override
        public void clicked(InputEvent event, float x, float y) {
            shopPressed = true;
        }
    });
    table.add(resumeButton).padBottom(25);
    table.row();
    table.add(menuButton).padBottom(25);
    table.row();
    table.add(shopButton);
    table.setPosition(cam.viewportWidth / 2, 560);
    table.setVisible(false);

}
public void draw(){
    stage.draw();
}

public void act(){
    stage.act();
}

public boolean isPauseButtonPressed() {
    return pauseButtonClicked;
}

public boolean isRestartPressed(){return RestartPressed;}

public boolean isResumePressed(){return resumePressed;}

public boolean isShopPressed() {
    return shopPressed;
}

public boolean isMenuPressed() {
    return menuPressed;
}

public void restartVisible(){
    restartButton.setVisible(true);
}
public void restartInvisible() { restartButton.setVisible(false); }
public void displayPauseButtons(){
    table.setVisible(true);
}

public void pauseInvisible(){
    pauseButton.setVisible(false);
}
public void pauseVisible(){
    pauseButton.setVisible(true);
}

public void removePauseButtons(){
    table.setVisible(false);
}

public void resize(int width, int height) {
  viewport.update(width, height);
  }

public void dispose(){
    stage.clear();}
}

The "Resume" Button is supposed to resume the game from the Pause to Running, but when I click it, it resumes the game, but the "boop" sound plays continuously forever and when the bird collides with anything, it doesn't stop, it just displays the Game Over menu while it is touching objects.

My theory is that it "resumes" the bird as if the Resume Button would always be pressed, so that is why it cannot die and it keeps playing the sound. But the problem is, why the hell is it doing that?!

Upvotes: 1

Views: 306

Answers (1)

Tenfour04
Tenfour04

Reputation: 93922

Once your buttons are clicked and set some boolean to say they are pressed, there is nothing in your code that ever sets the pressed booleans back to false. So once you press a button, it is like it is pressed down forever.

This is a complicated and error prone way of handling these buttons anyway. It is convoluted to have your render method poll all the buttons to see which ones have been recently pressed.

Get rid of all those booleans for whether buttons are pressed, and all those if-pressed cases in your handleInput() method. Each button's click listener should call a method that changes the state, plays a sound, etc. The way your code is structured, you would need to pass an instance of PlayState to your PlatStateButtons constructor, so its various ClickListeners can access it.

As an aside, Buttons in LibGDX behave more naturally if you use ChangeListener on them instead of ClickListener.

Upvotes: 2

Related Questions