Convert Screen coords to World Coords LIBGDX

I’m working on a tile based platformer game in libgdx. I’m having trouble getting the actual touch input coordinates when the aspect ratio of device is different from the virtual fixed aspect ratio that I’m working on. I’m using a virtual resolution of 480x800. All the rendering work and camera work is being done in GameRenderer class and the input is being handled in InputHandler class. I’ve tried implementing the camera.unproject() method but it won’t do any good. I’ve added the unproject method in GameRenderer class since my camera is defined here. Then I’ve sent the screen touch coords from the InputHandler class to the GameRenderer class and returned the converted coords back to InputHandler.

I’m posting the relevant code from both classes.

GameRenderer:


public class GameRenderer 
{
    public static OrthographicCamera cam;
    private ShapeRenderer shapeRenderer;
    private SpriteBatch batcher;
    private static Player player=GameWorld.getPlayer();

    private static final int VIRTUAL_WIDTH = 800;
    private static final int VIRTUAL_HEIGHT = 480;
    private static final float ASPECT_RATIO = (float)VIRTUAL_WIDTH/(float)VIRTUAL_HEIGHT;
    private Rectangle viewport;
    public static Vector2 crop = new Vector2(0f, 0f); 
    public static float scale = 1f;
    public static int Case=0;
    public static float width;
    public static float height;
    public static float w;
    public static float h;

    public GameRenderer(GameWorld world) 
    {
        cam = new OrthographicCamera();
        cam.setToOrtho(true, 800, 480);
        batcher=new SpriteBatch();
        batcher.setProjectionMatrix(cam.combined);
        shapeRenderer = new ShapeRenderer();
        shapeRenderer.setProjectionMatrix(cam.combined);
    }


    public void render()
    {
        cam.update();
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

        height=Gdx.graphics.getHeight();
        width=Gdx.graphics.getWidth();

        float aspectRatio = (float)width/(float)height;


        if(aspectRatio > ASPECT_RATIO)
        {
            scale = (float)height/(float)VIRTUAL_HEIGHT;
            crop.x = (width - VIRTUAL_WIDTH*scale)/2f;
            Case=1;
        }
        else if(aspectRatio < ASPECT_RATIO)
        {
            scale = (float)width/(float)VIRTUAL_WIDTH;
            crop.y = (float)(height - VIRTUAL_HEIGHT*scale)/2f;
            Case=2;
        }
        else
        {
            scale = (float)width/(float)VIRTUAL_WIDTH;
        }

        w = (float)VIRTUAL_WIDTH*scale;
        h = (float)VIRTUAL_HEIGHT*scale;


        viewport = new Rectangle(crop.x, crop.y, w, h);

        Gdx.gl.glViewport((int) viewport.x, (int) viewport.y, (int) viewport.width, (int) viewport.height);

        switch(GameWorld.state)
        {
            case Running: renderRunning(); break;
            case GameOver: renderGameOver(); break;
            case Paused: renderPaused(); break;
            default: break;
        }

    }

    public static Vector3 unprojectCoords(Vector3 coords)
    {
        cam.unproject(coords);
        return coords;
    }

}

InputHandler:


public class InputHandler implements InputProcessor 
{

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

        Vector3 coords=new Vector3(screenX,screenY,0);
        Vector3 coords2=GameRenderer.unprojectCoords(coords);

        screenX=(int) coords2.x;
        screenY=(int) coords2.y;

        switch(GameWorld.state)
        {
            case Running:
            {
                if(GameRenderer.jumpButton.isTouchDown((int)screenX, (int)screenY))
                {
                    if(player.isJumped() == false)
                    {
                        player.jump();
                        if(!GameWorld.soundMuted) AssetLoader.jump.play(AssetLoader.SOUND_VOL);
                    }

                }




        return false;
    }

    @Override
    public boolean keyDown(int keycode) 
    {
        switch(GameWorld.state)
        {
            case Running:
            {
                if(keycode==Keys.SPACE)
                {
                    if(player.isJumped() == false)
                    {
                        player.jump();
                        if(!GameWorld.soundMuted) AssetLoader.jump.play(AssetLoader.SOUND_VOL);
                    }
                }

                if(keycode==Keys.LEFT)
                {
                    leftDown=true;
                }

                if(keycode==Keys.RIGHT)
                {
                    rightDown=true;
                }

                if(keycode==Keys.CONTROL_RIGHT)
                {
                    player.shoot();
                }
                break;
            }

            default: break;
        }

        return false;
    }



}

All you have literally got to do is this:



Vector3 touchPos = new Vector3();

touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);

cam.unproject(touchPos);

codeYouWantToUseTheseCoords(touchPos.x, touchPos.y);


That is pretty much it, you take your custom camera and unproject any on screen touch/click events, then you can use these coords.

I do this to create level layouts in my little breakout clone, it does not matter what the screen resolution is since you are forcing it to use 480x800 anyway, it is a fixed viewport. Also most phones use 16:9 aspect ratio, you would be tailoring it a very small majority and imo it is not worth the fuss.

Code your game for whatever device you have, worry about it later.

I solved it. For some unknown reason I had to pass the viewport information to the unproject function.

unproject(Vector3 screenCoords, float viewportX, float viewportY, float viewportWidth, float viewportHeight);

Thanks to you anyway. I’ll try your method in my other project. Cheers