Libgdx weird issue with button touch coordinate

I’m trying to work on a screen with an options button. Currently my code works perfect on desktop but on my mobile device, when I touched the options button, it did changes color but doesn’t switch to the next screen. I found out that the real triggering point is at the bottom left of the screen which I’ve no idea why. Hope someone could shed some light here. Thanks.

This is my current code:

public class GameScreen implements Screen {

	public GameScreen( ) {
		screenWidth = Gdx.graphics.getWidth();
		screenHeight = Gdx.graphics.getHeight();
		
		cam = new OrthographicCamera();
		cam.setToOrtho(false, VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
	}


@Override
	public void show() {
		stage = new Stage( );
		Gdx.input.setInputProcessor(stage);

		TextureAtlas buttons = new TextureAtlas( Gdx.files.internal("data/milk.txt") );
		Skin skin = new Skin( buttons );
		
		ImageButtonStyle btnStyle = new ImageButtonStyle();
		btnStyle.up = skin.getDrawable( "optionsBtn");
		btnStyle.down = skin.getDrawable( "optionsBtn");
		
		ImageButton button = new ImageButton(btnStyle);
		button.setBounds( ZBGame.VIRTUAL_WIDTH/2-(121/2), ZBGame.VIRTUAL_HEIGHT/2-100,
 						button.getWidth(), button.getHeight());

		button.addListener(new ClickListener( ) {
				public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
					game.setScreen(new OptionScreen( game ) );
					return true;
				}
			});
        }


@Override
	public void render(float delta) {
		Gdx.gl.glClearColor(1, 1, 1, 1);
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		
		if( Gdx.input.justTouched( ) ) {
			Vector3 touchPos = new Vector3();
			touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
			ZBGame.cam.unproject(touchPos);
			
			Actor actor = stage.hit( touchPos.x, touchPos.y, true );

			if( actor != null ) {
				// change the button color
				// Its working on mobile device when touch but not changing screen.
				actor.setColor((float)Math.random(), (float)Math.random(),
								(float)Math.random(), 0.5f+0.5f*(float)Math.random());
			}
		}
		
		stage.act(delta);
		stage.draw();
	}
}

Why are you trying to manually do this?..

There is no reason for any of this:

      if( Gdx.input.justTouched( ) ) {
         Vector3 touchPos = new Vector3();
         touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
         ZBGame.cam.unproject(touchPos);
         
         Actor actor = stage.hit( touchPos.x, touchPos.y, true );

         if( actor != null ) {
            // change the button color
            // Its working on mobile device when touch but not changing screen.
            actor.setColor((float)Math.random(), (float)Math.random(),
                        (float)Math.random(), 0.5f+0.5f*(float)Math.random());
         }
      }

All you have to do is setup the Stage, set it as the input processor, add listeners to your buttons and then call act/draw. The stage will listener for any events.

I don’t get what you are trying to do here.

The cam.unproject is a very important requirement for touch. I made the same mistake. :slight_smile:

He is unprojecting it, but the whole thing is just weird. He is manually checking for touch down, getting the position and storing it, the checking if it is over an actor and then triggering the actors touch methods…but you don’t need to do any of that.

Yes you are right, I removed it already. Initially I thought addlistener isn’t working on my mobile device hence I use input.touch as a test until I found out the following problem:

I’ve updated my show method to use my own batch with camera combined but it just doesn’t seems to work. Any idea why?

My updated code:


public class GameScreen implements Screen {

   public final int VIRTUAL_WIDTH = 370;
   public final int VIRTUAL_HEIGHT = 640;

   public OrthographicCamera cam;
   public SpriteBatch batch;

   public GameScreen( ) {
      screenWidth = Gdx.graphics.getWidth();
      screenHeight = Gdx.graphics.getHeight();
      
      cam = new OrthographicCamera();
      cam.setToOrtho(false, VIRTUAL_WIDTH, VIRTUAL_HEIGHT);

      batch = new SpriteBatch( );
      batch.setProjectionMatrix(cam.combined);
   }


@Override
   public void show() {
      // Stage doesn't seems to be using my own batch with camera combined :(
      stage = new Stage( game.VIRTUAL_WIDTH, game.VIRTUAL_HEIGHT, true, batch );
      Gdx.input.setInputProcessor(stage);

      TextureAtlas buttons = new TextureAtlas( Gdx.files.internal("data/milk.txt") );
      Skin skin = new Skin( buttons );
      
      ImageButtonStyle btnStyle = new ImageButtonStyle();
      btnStyle.up = skin.getDrawable( "optionsBtn");
      btnStyle.down = skin.getDrawable( "optionsBtn");
      
      ImageButton button = new ImageButton(btnStyle);
      button.setBounds( ZBGame.VIRTUAL_WIDTH/2-(121/2), ZBGame.VIRTUAL_HEIGHT/2-100,
                   button.getWidth(), button.getHeight());

      button.addListener(new ClickListener( ) {
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
               game.setScreen(new OptionScreen( game ) );
               return true;
            }
         });
        }


@Override
   public void render(float delta) {
      Gdx.gl.glClearColor(1, 1, 1, 1);
      Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
      
      stage.act(delta);
      stage.draw();
   }
}

Omg finally got it to work. Thanks for the help guys. All I did was adding stage.setCamera( cam ); to my render method and its working fine now.

Don’t add it in the render method, should work just fine calling it once in show() or constructor.

Oh ok thank you so much! I shifted it to the constructor now.