user3591115
user3591115

Reputation: 393

Libgdx - camera.unproject is not fixing my coordinates

The following code gives me very strange y coordinates.

10-18 00:13:36.834  30543-30567/com.xxxx.yyyy.android I/x﹕ 137.4782
10-18 00:13:36.834  30543-30567/com.xxxx.yyyy.android I/y﹕ -1984.2426
10-18 00:13:36.835  30543-30567/com.xxxx.yyyy.android I/ux﹕ 91.65213
10-18 00:13:36.835  30543-30567/com.xxxx.yyyy.android I/uy﹕ -1984.2426

I imagine I set up everything wrong rather than do it wrong while running? The camera.unproject call should take care of all remapping from screen coordinates to game coordinates, shouldn't it? Or do i have to scale and invert before unprojecting?

package com.xxxx.yyyy;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;


public class LetterActor extends Actor
{
    private Texture texture;
    private Vector3 touchPosition = new Vector3();
    private Camera camera;
    private boolean unproject = true;

    public LetterActor(Texture letterTexture, Camera theCamera)
    {
        texture = letterTexture;
        camera = theCamera;

        touchPosition.set(240, 800, 0);
        camera.unproject(touchPosition);
        setPosition(touchPosition.x, touchPosition.y);

        setSize(texture.getWidth(), texture.getHeight());

        addListener(new InputListener()
        {
            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
            {
                touchPosition.set(x, y, 0);
                if (unproject)
                {
                    camera.unproject(touchPosition);
                }
                setPosition(touchPosition.x, touchPosition.y);

                logPositions(x, y, touchPosition.x, touchPosition.y);

                return true;
            }

            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button)
            {
                touchPosition.set(x, y, 0);
                if (unproject)
                {
                    camera.unproject(touchPosition);
                }
                setPosition(touchPosition.x, touchPosition.y);

                logPositions(x, y, touchPosition.x, touchPosition.y);
            }

            @Override
            public void touchDragged(InputEvent event, float x, float y, int pointer)
            {
                touchPosition.set(x, y, 0);
                if (unproject)
                {
                    camera.unproject(touchPosition);
                }
                setPosition(touchPosition.x, touchPosition.y);

                logPositions(x, y, touchPosition.x, touchPosition.y);
            }
        });
    }

    private void screenTo()
    {

    }

    private void logPositions(float x, float y,float ux, float uy)
    {
        Gdx.app.log("x", Float.toString(x));
        Gdx.app.log("y", Float.toString(y));
        Gdx.app.log("ux", Float.toString(ux));
        Gdx.app.log("uy", Float.toString(y));
    }

    @Override
    public void draw(Batch batch, float alpha)
    {
        batch.draw(texture, getX(), getY(), getWidth(), getHeight());
    }

    @Override
    public void act(float delta) {}
}



package com.xxxx.yyyy;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.utils.viewport.FitViewport;

public class WordPuzzle extends ApplicationAdapter
{
    private final static float VIRTUAL_WIDTH = 480;
    private final static float VIRTUAL_HEIGHT = 800;

    private OrthographicCamera camera;
    private FitViewport viewport;
    private Stage stage;

    @Override
    public void create()
    {
        camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
        camera.setToOrtho(false, VIRTUAL_WIDTH, VIRTUAL_HEIGHT);

        viewport = new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, camera);
        stage = new Stage();
        stage.setViewport(viewport);
        Gdx.input.setInputProcessor(stage);

        Texture[] textures = LetterLoader.loadLetters();
        for (int i = 0; i < textures.length; i++)
        {
            LetterActor letterActor = new LetterActor(textures[i], camera);
            letterActor.setTouchable(Touchable.enabled);
            stage.addActor(letterActor);
        }
    }

    @Override
    public void render()
    {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }


    @Override public void resize(int width, int height)
    {
        stage.getViewport().update(width, height, true);
    }

    @Override public void dispose()
    {
        stage.dispose();
    }
}



package com.xxxx.yyyy;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;

public class LetterLoader {

    public static Texture[] loadLetters()
    {
        Texture[] letters = new Texture[26];

        for (int i = 0; i < 26; i++)
        {
            char letter = (char) (i + 65);
            letters[i] = new Texture(Gdx.files.internal("bigletters/" + letter + ".png"));
        }

        return letters;
    }
}

Upvotes: 2

Views: 822

Answers (2)

Pinkie Swirl
Pinkie Swirl

Reputation: 2415

First, the touch position (x, y) you get from the input listener are already the correct coordinates.


Concerning your output, you actually print y two times, but call it uy the second time:

Gdx.app.log("uy", Float.toString(y));

If touchPosition.set(240, 800, 0); is in screen coordinates, then you need to unproject them, but

camera.unproject(touchPosition);

assumes that your camera fills the whole screen, thus it calls internally:

unproject(screenCoords, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

Since you use a virtual size, this is wrong. The most simple solution would be to use the unproject method from the viewport that you are using:

viewport.unproject(touchPosition);

This will call the camera unproject method with the correct parameters automatically.

Upvotes: 4

Tenfour04
Tenfour04

Reputation: 93581

Since you are using Stage and InputListener, the coordinates you get in touchDown and the related methods are already in world coordinates, so it doesn't make sense to unproject them. You can use the x and y directly.

Also (although this is irrelevant to InputListener), camera.unproject assumes a Viewport that fills the screen, which is not true of FitViewport, which you're using. If you are using a Viewport class, you need to use viewport.unproject instead of camera.unproject, so it takes the black bars into account.

But you only need to worry about unprojecting for stuff not related to the Stage.

Upvotes: 1

Related Questions