Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

libgdx coordinate system differences between rendering and touch input

I have a screen (BaseScreen implements the Screen interface) that renders a PNG image. On click of the screen, it moves the character to the position touched (for testing purposes).

public class DrawingSpriteScreen extends BaseScreen {
    private Texture _sourceTexture = null;
    float x = 0, y = 0;

    @Override
    public void create() {
        _sourceTexture = new Texture(Gdx.files.internal("data/character.png"));
    }

    .
    .
}

During rendering of the screen, if the user touched the screen, I grab the coordinates of the touch, and then use these to render the character image.

@Override
public void render(float delta) {
    if (Gdx.input.justTouched()) {
        x = Gdx.input.getX();
        y = Gdx.input.getY();
    }

    super.getGame().batch.draw(_sourceTexture, x, y);
}

The issue is the coordinates for drawing the image start from the bottom left position (as noted in the LibGDX Wiki) and the coordinates for the touch input starts from the upper left corner. So the issue I'm having is that I click on the bottom right, it moves the image to the top right. My coordinates may be X 675 Y 13, which on touch would be near the top of the screen. But the character shows at the bottom, since the coordinates start from the bottom left.

Why is what? Why are the coordinate systems reversed? Am I using the wrong objects to determine this?

like image 733
Brian Mains Avatar asked May 13 '13 02:05

Brian Mains


3 Answers

To detect collision I use camera.unproject(vector3). I set vector3 as:

x = Gdx.input.getX();     
y = Gdx.input.getY();
z=0;

Now I pass this vector in camera.unproject(vector3). Use x and y of this vector to draw your character.

like image 197
Pranav008 Avatar answered Oct 12 '22 21:10

Pranav008


You're doing it right. Libgdx generally provides coordinate systems in their "native" format (in this case the native touch screen coordinates, and the default OpenGL coordinates). This doesn't create any consistency but it does mean the library doesn't have to get in between you and everything else. Most OpenGL games use a camera that maps relatively arbitrary "world" coordinates onto the screen, so the world/game coordinates are often very different from screen coordinates (so consistency is impossible). See Changing the Coordinate System in LibGDX (Java)

There are two ways you can work around this. One is transform your touch coordinates. The other is to use a different camera (a different projection).

To fix the touch coordinates, just subtract the y from the screen height. That's a bit of a hack. More generally you want to "unproject" from the screen into the world (see the Camera.unproject() variations). This is probably the easiest.

Alternatively, to fix the camera see "Changing the Coordinate System in LibGDX (Java)", or this post on the libgdx forum. Basically you define a custom camera, and then set the SpriteBatch to use that instead of the default.:

// Create a full-screen camera:
camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
// Set it to an orthographic projection with "y down" (the first boolean parameter)
camera.setToOrtho(true, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
camera.update();

// Create a full screen sprite renderer and use the above camera
batch = new SpriteBatch(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
batch.setProjectionMatrix(camera.combined);

While fixing the camera works, it is "swimming upstream" a bit. You'll run into other renderers (ShapeRenderer, the font renderers, etc) that will also default to the "wrong" camera and need to be fixed up.

like image 39
P.T. Avatar answered Oct 12 '22 21:10

P.T.


I had same problem , i simply did this.

public boolean touchDown(int screenX, int screenY, int pointer, int button) {

    screenY = (int) (gheight - screenY);
    return true;
}

and every time you want to take input from user dont use Gdx.input.getY(); instead use (Gdx.graphics.getHeight()-Gdx.input.getY()) that worked for me.

like image 38
geekydhaval Avatar answered Oct 12 '22 22:10

geekydhaval