使用 Libgdx : finding tile at mouse position 的 Java 瓦片 map

标签 java libgdx

我看过几个人创建瓷砖 map 的例子,但我无法获得鼠标指向的瓷砖位置。
我正在使用 spritebatch 和 GameTile[][] 来创建 map 。请记住,瓷砖本身是等距的,实际上并不是正方形。
renderMap() 方法是实际渲染 map 的地方。 createMap() 只是为空 map 设置初始 GameTiles。
可以使用 Ortho 相机拖动和放大和缩小 map 。
缩小也给我带来了一个问题,瓷砖似乎在点击时移动了

public class MapEditor implements GameScene {
    private GameContext context;
    private SpriteBatch batch;
    private OrthographicCamera camera;
    public static GameTile[][] tiles; //GameTile.WIDTH = 64 & GameTile.HEIGHT =48

    public static final int MAP_WIDTH = 20;
    public static final int MAP_HEIGHT = 36;

    public MapEditor(GameContext context) {
        this.context = context;
        tiles = new GameTile[MAP_WIDTH][MAP_HEIGHT];
    }
    @Override
    public void create() {
        renderer = new ShapeRenderer();
        this.batch = new SpriteBatch();
        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    }
    public void createMap() {
        // Create the sea tiles
        for (int x = 0; x < MAP_WIDTH; x++) {
            for (int y = 0; y < MAP_HEIGHT; y++) {
                if (y < 3 || y > 32) {
                    if(tiles[x][y] == null) {
                        tiles[x][y] = safezone;
                    }
                }
                else {
                    if(tiles[x][y] == null) {
                        tiles[x][y] = cell;
                    }
                }

            }
        }

    }

   @Override
    public void update(){
        // update the camera
        camera.update();
    }

    @Override
    public void render() {
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        Gdx.gl.glViewport(0,0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        renderMap();
        batch.end();
    }
    public int getTileX(float x, float y) {
        /*
         * getRegionWidth() = TILE_WIDTH_HALF 
         * getRegionHeight() = TILE_HEIGHT_HALF
         * these are the ones being added to worldCoords.x/y
        */
        Vector3 worldCoords = camera.unproject(new Vector3(x, y, 0));
        return (int)((TILE_WIDTH_HALF * ((-TILE_HEIGHT_HALF + (worldCoords.y + TILE_HEIGHT_HALF)) / 
                TILE_HEIGHT_HALF) + (worldCoords.x + TILE_WIDTH_HALF)) / TILE_WIDTH_HALF) / 2;
    }
    
    public int getTileY(float x, float y) {
        /*
         * getRegionWidth() = TILE_WIDTH_HALF 
         * getRegionHeight() = TILE_HEIGHT_HALF
         * these are the ones being added to worldCoords.x/y
        */
        Vector3 worldCoords = camera.unproject(new Vector3(x, y, 0));
        return (int)(((-TILE_HEIGHT_HALF * (TILE_WIDTH_HALF + (worldCoords.x + TILE_WIDTH_HALF)) / 
                TILE_WIDTH_HALF) + (worldCoords.y + TILE_HEIGHT_HALF)) / TILE_HEIGHT_HALF) / 2;
    }
    
    @Override
    public boolean handleClick(float x, float y, int button) {
        int tileX = getTileX(x,y);
        int tileY = getTileY(x,y);

        System.out.println("Tile:"+tileX + ","+tileY);
    }

    private void renderMap() {
        for (int i = 0; i < tiles.length; i++) {
            for(int j = 0; j < tiles[i].length; j++) {
                TextureRegion region = tiles[i][j].getRegion();
                int x = (i * GameTile.TILE_WIDTH / 2) - (j * GameTile.TILE_WIDTH / 2) - region.getRegionWidth() / 2;
                int y = (i * GameTile.TILE_HEIGHT / 2) + (j * GameTile.TILE_HEIGHT / 2) - region.getRegionHeight() / 2;
                if (canDraw(x, y, GameTile.TILE_WIDTH, GameTile.TILE_HEIGHT)) {
                    batch.draw(region, x, y);
                }
            }
        }
    }

在做任何事情之前的实际瓷砖;
enter image description here
实际的:
enter image description here
期望:
enter image description here

最佳答案

将笛卡尔坐标转换为等距坐标(有点)是这样完成的:

float isometricX = cartesianX - cartesianY;
float isometricY = (cartesianX + cartesianY) * 0.5f;
该公式还需要按图块的高宽比进行缩放,我认为这就是您的代码出错的地方。
给定一个未投影的 worldMousePosition您可以像这样获得坐标和平铺坐标:
    float r = (float) TILE_HEIGHT / (float) TILE_WIDTH;

    float mapx = (worldMousePosition.x / TILE_HEIGHT + worldMousePosition.y / (TILE_HEIGHT * r)) * r;
    float mapy = (worldMousePosition.y / (TILE_HEIGHT * r) - (worldMousePosition.x / TILE_HEIGHT)) * r;
    worldPosition = new Vector2(mapx - 0.5f, mapy + 0.5f); // -.5/+.5 because the drawing isn't aligned to the tile, it's aligned to the image

    int tileX = (int) worldPosition.x;
    int tileY = (int) worldPosition.y;
enter image description here
上面例子的完整源代码:
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class SandboxGame extends Game {
    public static final int TILE_NONE = -1;
    public static final int MAP_WIDTH = 20;
    public static final int MAP_HEIGHT = 36;
    public static final int TILE_WIDTH = 64;
    public static final int TILE_HEIGHT = 48;

    private SpriteBatch batch;
    private OrthographicCamera camera;
    private BitmapFont font;
    private Vector3 unprojectVector = new Vector3();
    private Vector2 worldMousePosition = new Vector2();
    private Vector2 worldPosition = new Vector2();
    private Texture[] textures;

    private int[][] tiles = new int[MAP_WIDTH][MAP_HEIGHT];

    @Override
    public void create() {
        batch = new SpriteBatch();
        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        font =  new BitmapFont(Gdx.files.internal("default.fnt"), Gdx.files.internal("default.png"), false);
        textures = new Texture[] {
            new Texture(Gdx.files.internal("tile.png"))
        };

        for(int x = 0; x < MAP_WIDTH; ++x) {
            for(int y = 0; y < MAP_HEIGHT; ++y) {
                int rnd = MathUtils.random(10);
                if (rnd < 1)
                    tiles[x][y] = TILE_NONE;
                else
                    tiles[x][y] = 0;
            }
        }
    }

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

        float scrollSpeed = 64;
        float zoomSpeed = 2;

        float delta = Gdx.graphics.getDeltaTime();
        if (Gdx.input.isKeyPressed(Input.Keys.A))
            camera.position.x -= delta * scrollSpeed;
        if (Gdx.input.isKeyPressed(Input.Keys.D))
            camera.position.x += delta * scrollSpeed;
        if (Gdx.input.isKeyPressed(Input.Keys.W))
            camera.position.y += delta * scrollSpeed;
        if (Gdx.input.isKeyPressed(Input.Keys.S))
            camera.position.y -= delta * scrollSpeed;

        if (Gdx.input.isKeyPressed(Input.Keys.Q))
            camera.zoom = Math.min(camera.zoom + zoomSpeed * delta, 8.0f);
        if (Gdx.input.isKeyPressed(Input.Keys.E))
            camera.zoom = Math.max(camera.zoom - zoomSpeed * delta, 0.5f);

        camera.update();

        int mx = Gdx.input.getX();
        int my = Gdx.input.getY();

        camera.unproject(unprojectVector.set(mx, my, 0.0f));
        worldMousePosition.set(unprojectVector.x, unprojectVector.y);
        float r = (float) TILE_HEIGHT / (float) TILE_WIDTH;

        float mapx = (worldMousePosition.x / TILE_HEIGHT + worldMousePosition.y / (TILE_HEIGHT * r)) * r;
        float mapy = (worldMousePosition.y / (TILE_HEIGHT * r) - (worldMousePosition.x / TILE_HEIGHT)) * r;
        worldPosition = new Vector2(mapx - 0.5f, mapy + 0.5f); // -.5/+.5 because the drawing isn't aligned to the tile, it's aligned to the image

        int tileX = (int) worldPosition.x;
        int tileY = (int) worldPosition.y;

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

        for (int col = MAP_WIDTH - 1; col >= 0; --col) {
            for (int row = MAP_HEIGHT - 1; row >= 0; --row) {
                if (tiles[col][row] != TILE_NONE) {
                    Texture texture = textures[tiles[col][row]];
                    int x = (col * TILE_WIDTH / 2) - (row * TILE_WIDTH / 2);
                    int y = (col * TILE_HEIGHT / 2) + (row * TILE_HEIGHT / 2);
                    batch.setColor(col == tileX && row == tileY ? Color.GRAY : Color.WHITE);
                    batch.draw(texture, x, y);

                }
            }
        }

        if (Gdx.input.isKeyPressed(Input.Keys.SPACE)) {
            for (int col = MAP_WIDTH - 1; col >= 0; --col) {
                for (int row = MAP_HEIGHT - 1; row >= 0; --row) {
                    int x = (col * TILE_WIDTH / 2) - (row * TILE_WIDTH / 2);
                    int y = (col * TILE_HEIGHT / 2) + (row * TILE_HEIGHT / 2);
                    font.draw(batch, String.format("(%d, %d)", col, row), x, y);
                }
            }
        }

        String str = String.format("World position (%.2f, %.2f), Tile (%d, %d)", worldPosition.x, worldPosition.y, (int)worldPosition.x, (int)worldPosition.y);
        font.draw(batch, str, worldMousePosition.x, worldMousePosition.y);
        batch.end();
    }
}

关于使用 Libgdx : finding tile at mouse position 的 Java 瓦片 map ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64216848/

相关文章:

java - 如何包含 java src 代码,以便我可以在 Android Studio 中使用它

java - 下载 pdf 后出现文件损坏错误

Java显示从最后一个用户输入到第一个用户输入的数组内容

java - 操作系统如何决定如何运行 .exe

android - 在异常处理程序(java)中使程序崩溃

android - 如何改变移动物体的位置 - Box2D

java - Libgdx如何存储碰撞检测数据

Java 未正确发送到串行端口

java - Spring-Data-JPA throws "Caused by: java.sql.SQLException: Incorrect syntax near ' limit'."by using findAll

android - 如何为不同的屏幕尺寸设置 libgdx 游戏?