[SOLVED] [LibGdx] [Desktop] Overlapping 'Button' Functionality

Hello. If you are reading this, then you have successfully found a very obvious scrub and have no idea wth i’m doing, and I am in need of your help.

I’m having an issue with my ‘buttons’ basically on the main menu. The way the buttons work is that there is just text on the screen and when the player clicks inside a certain area during that gameState, it will perform the function. (in this case clicking the button just send the player to an entire new gamestate).

My problem is that my ‘Back Button’ in the Options menu and my ‘Exit button’ in my Main menu overlap in position, but are not in the same gameState. when the ‘Back Button’ in the options menu (gameState = 1), is clicked, instead of proceeding with going to, gameState = 0, the game closes, which can only happen when the ‘Exit button’ is clicked during the gameState = 0. The only conclusion i have came to is that since they overlap and that there is no delay between the two gameStates, that the action during clicking of the Back button is also applied to the Exit button when the gameState is changed.

Any help toward a solution would be very much appreciated. ;D Thank you for your time.

// Main Menu
		if (gameState == 0) {
			batch.begin();
			batch.draw(MainMenuBackground, 0, 0);
			font16.setScale(1, 1);
			font16.draw(batch, "Alpha v1.0.1_02", 10, 20);
			font16.draw(batch, "FPS: ", 950, 20);
			font16.draw(batch,
					Integer.toString(Gdx.graphics.getFramesPerSecond()), 994,
					20);
			font16.setColor(Color.LIGHT_GRAY);
			font16.setScale(2, 2);
			font16.draw(batch, "Start", 845, 450);
			font16.draw(batch, "Options", 830, 380);
			font16.draw(batch, "Exit", 860, 250);
			batch.end();

			// Start Button
			if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
				if (Gdx.input.getX(pointer) > 830
						&& Gdx.input.getX(pointer) < 970
						&& Gdx.input.getY(pointer) > 50
						&& Gdx.input.getY(pointer) < 100) {
					gameState = 2;
				}
			}
			// Options Button
			if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
				if (Gdx.input.getX(pointer) > 810
						&& Gdx.input.getX(pointer) < 990
						&& Gdx.input.getY(pointer) > 120
						&& Gdx.input.getY(pointer) < 170) {
					gameState = 1;
				}
			}
			// Exit Button
			if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
				if (Gdx.input.getX(pointer) > 840
						&& Gdx.input.getX(pointer) < 940
						&& Gdx.input.getY(pointer) > 250
						&& Gdx.input.getY(pointer) < 300) {
					// dispose of all the native resources
					dispose();
					System.exit(0);
				}
			}
		}
		// Options Menu
		if (gameState == 1) {
			batch.begin();
			batch.draw(MainMenuBackground, 0, 0);
			font16.setScale(1, 1);
			font16.draw(batch, "Alpha v1.0.1_02", 10, 20);
			font16.draw(batch, "FPS: ", 950, 20);
			font16.draw(batch,
					Integer.toString(Gdx.graphics.getFramesPerSecond()), 994,
					20);
			font16.setScale(2, 2);
			font16.draw(batch, "Back", 855, 250);
			font16.setColor(Color.LIGHT_GRAY);
			batch.end();
			// Back Button
			if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
				if (Gdx.input.getX(pointer) > 840
						&& Gdx.input.getX(pointer) < 940
						&& Gdx.input.getY(pointer) > 250
						&& Gdx.input.getY(pointer) < 300) {
					gameState = 0;
				}
			}
		}

Two ways to do this:

Simple to implement way, but does not solve root of the problem: use a cooldown for the button:


@@//these will be fields, not local variables
+private long timeOfLastPress = 0;
+private final int cooldownTime = 1000000000; // 1 second in nanos

if (gameState == 0) {
         ...

         // Options Button
@@        if (Gdx.input.isButtonPressed(Input.Buttons.LEFT) && System.nanoTime() - timeOfLastPress >= cooldownTime) {
            if (Gdx.input.getX(pointer) > 810
                  && Gdx.input.getX(pointer) < 990
                  && Gdx.input.getY(pointer) > 120
                  && Gdx.input.getY(pointer) < 170) {
+               timeOfLastPress = System.nanoTime();
               gameState = 1;
            }
         }
         // Exit Button
         if (Gdx.input.isButtonPressed(Input.Buttons.LEFT && System.nanoTime() - timeOfLastPress >= cooldownTime)) {
            if (Gdx.input.getX(pointer) > 840
                  && Gdx.input.getX(pointer) < 940
                  && Gdx.input.getY(pointer) > 250
                  && Gdx.input.getY(pointer) < 300) {
               // dispose of all the native resources
               dispose();
               System.exit(0);
            }
         }
      }
      // Options Menu
      if (gameState == 1) {
         ...

         // Back Button
@@         if (Gdx.input.isButtonPressed(Input.Buttons.LEFT && System.nanoTime() - timeOfLastPress >= cooldownTime)) {
            if (Gdx.input.getX(pointer) > 840
                  && Gdx.input.getX(pointer) < 940
                  && Gdx.input.getY(pointer) > 250
                  && Gdx.input.getY(pointer) < 300) {
+             timeOfLastPress = System.nanoTime();
               gameState = 0;
            }
         }
      }

This keeps buttons from activating until cooldownTime time has elapsed since a button was pressed, which will work, unless the player holds down the button for more than cooldownTime.

Which brings us to the heart of the problem: Your buttons merely check if the mouse button is held down, not whether it was pressed just now.
That is called a polling event model, which is fine for many things, but an event handling method is usually better, and more importantly will solve your problem. Look through that link and try it out.

Edit: hmm some code highlighting doesn’t seem to be working…

Use scene2d.ui. :slight_smile:


If not, you could look how clicks are registered there.

Or maybe not, as it’s a bit complicated. :stuck_out_tongue: Anyway, a click has to go down on an actor, then go up and not have moved X pixels (the tap square) from the down position. Note this allows an actor to be clicked even if the touch up is outside the actor, as long as it is still within the tap square. This improves buttons for touch screens.

Thanks BurntPizza, this worked perfectly.

I would like to note that you have ‘1000000’ nanoseconds (which is 1/1000 of a second )for the cooldownTime instead of ‘1000000000’ for it.

Also I found a solution (i think) for the holding down of the button. Which is just a if statement using ‘isTouched’ and ‘mouseDown’.

anyway, Thank you again!

Whoops! Ha, yeah forgot those extra orders of magnitude, fixed.
And you’re welcome! :wink: