Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using unProject correctly in Java Libgdx

I want to make a button clickable, but it isn't working - it seems like I need to use unproject() but I can't figure out how. The code in question is:

Texture playButtonImage;
SpriteBatch batch;
ClickListener clickListener;
Rectangle playButtonRectangle;
Vector2 touchPos;
OrthographicCamera camera;

@Override
public void show() {
    playButtonImage = new Texture(Gdx.files.internal("PlayButton.png"));

    camera = new OrthographicCamera();
    camera.setToOrtho(false, 800, 480);
    batch = new SpriteBatch();

    playButtonRectangle = new Rectangle();
    playButtonRectangle.x = 400;
    playButtonRectangle.y = 250;
    playButtonRectangle.width = 128;
    playButtonRectangle.height = 64;
}

@Override
public void render(float delta) {
    Gdx.gl.glClearColor(0, 0, 0.2f, 1);
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

    camera.update();
    batch.setProjectionMatrix(camera.combined);

    batch.begin();
    batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
    batch.end();

    if (Gdx.input.isTouched()) {
        Vector2 touchPos = new Vector2();
        touchPos.set(Gdx.input.getX(), Gdx.input.getY());


        if (playButtonRectangle.contains(touchPos)) {
            batch.begin();
            batch.draw(playButtonImage, 1, 1);
            batch.end();
        }
    }
}
like image 716
Chimpanse Avatar asked Sep 01 '13 00:09

Chimpanse


3 Answers

In general you use camera.unproject(Vector) to transform your screen coordinates from a click or touch to your gameworld. This is needed because the origin is not necessarily the same and using the camera you can also zoom in and out, move around, rotate and so on. Unprojecting will take care of all of that and give you your game world coordinate matching the pointers position.

In your example it would go like this:

Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(touchPos);

Having this said you should actually not do this UI task manually. Libgdx has also some shipped UI functionality which is called a Stage (see this). There are lots of widgets already available (see this). They use skins (you can get a basic one from here, you need all the uiskin.* files). They automatically forward inputevents to the socalled Actors, e.g. a button, and you just need to implement handling of those events.

like image 71
noone Avatar answered Nov 16 '22 01:11

noone


with camera.unproject(Vector3); you can translate screen coordinates to game world coordinates.

Vector3 tmpCoords = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);

tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.

In addition to that it is best practice to define a tmpVector as a field an Instantiate a Vector3 object only once. You can then do the same with the .set() method.

tmpCoords.set(Gdx.input.getX(), Gdx.input.getY(), 0);
camera.unproject(tmpCoords);

tmpCoords.x //is now the touched X coordinate in the game world coordinate system
tmpCoords.y //is now the touched Y coordinate in the game world coordinate system.

Therefore you reduce object creation and remove unnecessary GC calls which lead to microlag.

like image 45
laubed Avatar answered Nov 16 '22 00:11

laubed


@Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

camera.update();
batch.setProjectionMatrix(camera.combined);

batch.begin();
batch.draw(playButtonImage, playButtonRectangle.x, playButtonRectangle.y);
batch.end();

if (Gdx.input.isTouched()) {
    Vector3 touchPos = new Vector3();
    touchPos.set(Gdx.input.getX(), Gdx.input.getY(),0);
    camera.unproject(touchPos);


    if (playButtonRectangle.contains(touchPos.x, touchPos.y)) {
        batch.begin();
        batch.draw(playButtonImage, 1, 1);
        batch.end();
    }
   }
   }
like image 23
Paras Mittal Avatar answered Nov 16 '22 02:11

Paras Mittal