简体   繁体   中英

LibGDX: How to get the same coordinates in tiled map for tile with and without zoom

I am a beginner with LibGDX. I am trying to create an android game based fixed size tiled map (33x21 tiles). Tiles I am using are 32x32px. So far I managed to load the map created with Tiled and add touch gestures like zoom in/out and panning. The game character movement will be turn based tile by tile, so I need to have a possibility to select specific tile in order to perform some action. I tried solution from here: LibGDX: How to make tiled map tiles clickable? and it works perfectly fine, until the screen is not zoomed in.

Without zoom, the left-bottom corner coordinates shows that it is (0,0), which is correct. When I zoom in, the left-bottom corner of the visible part of the map instead of keeping it's correct coordinates (ie (480, 320)) it becomes (0,0) again. I tried to use camera.unproject(Vector3), but I was unsuccessful. Probably used it wrong. I am also not really convinced, that the way in which I try to get tiles is the most appropriate one. Can you help me get tiles coordinates properly? Below is the code that I am using:

public class TiledTest extends ApplicationAdapter  {

public TiledMap tiledMap;
OrthographicCamera camera;
TiledMapRenderer tiledMapRenderer;

GestureDetector gesture;
InputMultiplexer myInputMultiplexer;

float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();

public static final float PAN_RATE = (float) 0.01;
private static final float ZOOM_SPEED = (float) 0.009;
int columns, rows;
TiledMapTileLayer grid_layer;

@Override
public void create () {

    gesture =new GestureDetector(new MyGestureListener());
    myInputMultiplexer = new InputMultiplexer();
    float unitScale = 1 / 32f;


    camera = new OrthographicCamera();
    camera.setToOrtho(true, 33,21);

    tiledMap = new TmxMapLoader().load("tiled_map.tmx");
    tiledMapRenderer = new OrthogonalTiledMapRenderer(tiledMap, unitScale);
    grid_layer = (TiledMapTileLayer)tiledMap.getLayers().get(0);
    Stage stage = new TiledMapStage(tiledMap);
    myInputMultiplexer.addProcessor(gesture);
    myInputMultiplexer.addProcessor(stage);
    Gdx.input.setInputProcessor(myInputMultiplexer);
}

@Override
public void render () {

    tiledMapRenderer.setView(camera);
    tiledMapRenderer.render();
    camera.update();
}

public class TiledMapActor extends Actor {

    private TiledMapTileLayer.Cell cell;

    public TiledMapActor(TiledMap tileMap, TiledMapTileLayer tiledLayer, TiledMapTileLayer.Cell cell) {
        tiledMap = tileMap;
        grid_layer = tiledLayer;
        this.cell = cell;
    }

}

public class TiledMapClickListener extends ClickListener {

    private TiledMapActor actor;

    public TiledMapClickListener(TiledMapActor actor) {
        this.actor = actor;
    }

    @Override
    public void clicked(InputEvent event, float x, float y) {

    int a = (int) actor.getX();
        int b = (int) actor.getY();

        System.out.println(actor.cell + " has been clicked.");
        System.out.println("x =  " + a +  "y = " + b );
        }
}

public class TiledMapStage extends Stage {

    private TiledMap tiledMap;

    public TiledMapStage(TiledMap tiledMap) {
        this.tiledMap = tiledMap;

        for (MapLayer layer : tiledMap.getLayers()) {

            TiledMapTileLayer tiledLayer = (TiledMapTileLayer)layer;
            createActorsForLayer(tiledLayer);
        }
    }

    private void createActorsForLayer(TiledMapTileLayer tiledLayer) {
        for (int x = 0; x <= tiledLayer.getWidth(); x++) {
            for (int y = 0; y < tiledLayer.getHeight(); y++) {
                TiledMapTileLayer.Cell cell = tiledLayer.getCell(x, y);
                TiledMapActor actor = new TiledMapActor(tiledMap, tiledLayer, cell);
                actor.setBounds(x * tiledLayer.getTileWidth(), y * tiledLayer.getTileHeight(), tiledLayer.getTileWidth(),
                        tiledLayer.getTileHeight());
                addActor(actor);
                EventListener eventListener = new TiledMapClickListener(actor);
                actor.addListener(eventListener);
            }
        }
    }
}

public void resize(float width, float height) {

}

public class MyGestureListener implements GestureListener{

    @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
        return false;
    }

    @Override
    public boolean tap(float x, float y, int count, int button) {
        return false;
    }

    @Override
    public boolean longPress(float x, float y) {
        return false;
    }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        return false;
    }

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) {

        float effectiveViewportWidth = camera.viewportWidth * camera.zoom;
        float effectiveViewportHeight = camera.viewportHeight * camera.zoom;

        camera.position.x = MathUtils.clamp(camera.position.x, effectiveViewportWidth / 2f, 33 - effectiveViewportWidth / 2f);
        camera.position.y = MathUtils.clamp(camera.position.y, effectiveViewportHeight / 2f, 21 - effectiveViewportHeight / 2f);
        if (camera.zoom < 1) {

             camera.translate(-deltaX * PAN_RATE, -deltaY * PAN_RATE,   0);
             camera.update();
        } 
        return false;
    }

    @Override
    public boolean panStop(float x, float y, int pointer, int button) {
        //Gdx.app.log("Text", "panstop");
        return false;
    }


    @Override
    public boolean zoom (float originalDistance, float currentDistance){

         float ratio = originalDistance/currentDistance;

         camera.zoom += ZOOM_SPEED * ratio;

        if (camera.zoom < 0.3)
         {
            camera.zoom = (float) 0.3;
         }
         else if (camera.zoom > 1)
         {
            camera.zoom = 1;
         }
         System.out.println(camera.zoom);
    return false;
}

    @Override
    public boolean pinch (Vector2 initialFirstPointer, Vector2 initialSecondPointer, Vector2 firstPointer, Vector2 secondPointer){
         camera.zoom -= .01;
         camera.update();
       return false;
    }

}

}

So you want to transfer the screen coordinates to world coordinates.
For example:

@Override
public void clicked(InputEvent event, float x, float y) {

    Vector3 touch = new Vector3(x, y, 0);
    camera.unproject(touch);

    System.out.println("Screen coordinates translated to world coordinates: "
        + "X: " + touch.x + " Y: " + touch.y);

    }
}

Above clicked function does not worked for me, but you led me to the answer. I dumped whole assigning actors for tiles and used camera.unproject in MyGestureListener in touchDown.

If someone is interested I just leave it here :)

@Override
    public boolean touchDown(float x, float y, int pointer, int button) {

         Vector3 temp_coord = new Vector3(x,y,0);
         Vector3  coords = camera.unproject(temp_coord);

            x =(int) coords.x;
            y =(int) coords.y;

            writerX = x;
            writerY = y;

            System.out.println("Screen coordinates translated to world coordinates: "
                    + "X: " + x + " Y: " + y);

        return false;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM