Sure, here’s the translation: Java使用Libgdx的瓦片地图:查找鼠标位置处的瓦片

huangapple go评论81阅读模式
英文:

Java tile map using Libgdx: finding tile at mouse position

问题

以下是您提供的代码的翻译:

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() {
        // 创建海洋瓦片
        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() {
        // 更新相机
        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
         * 这些值将被添加到 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
         * 这些值将被添加到 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("瓦片:" + 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);
                }
            }
        }
    }
}

以上是您提供的代码的翻译内容。

英文:

I've looked at several examples of people creating tile maps, and I am unable to get the tile position where my mouse is pointed at.

I am using a spritebatch and GameTile[][] to create the map. Keep in mind that the tiles themselves are isometric and not actually a square.

The method renderMap() is where the map is actually is being rendered. createMap() just sets the initial GameTiles for an empty map.

The map is able to be dragged and zoomed in and out using Ortho camera.

Zooming out gives me an issue as well, the tiles seem to be shifted over on click

public class MapEditor implements GameScene {
private GameContext context;
private SpriteBatch batch;
private OrthographicCamera camera;
public static GameTile[][] tiles; //GameTile.WIDTH = 64 &amp; 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 &lt; MAP_WIDTH; x++) {
for (int y = 0; y &lt; MAP_HEIGHT; y++) {
if (y &lt; 3 || y &gt; 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(&quot;Tile:&quot;+tileX + &quot;,&quot;+tileY);
}
private void renderMap() {
for (int i = 0; i &lt; tiles.length; i++) {
for(int j = 0; j &lt; 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);
}
}
}
}

Actual tile before doing anything to it;

Sure, here’s the translation:
Java使用Libgdx的瓦片地图:查找鼠标位置处的瓦片

Actual:

Sure, here’s the translation:
Java使用Libgdx的瓦片地图:查找鼠标位置处的瓦片
Desired:

Sure, here’s the translation:
Java使用Libgdx的瓦片地图:查找鼠标位置处的瓦片

答案1

得分: 3

转换笛卡尔坐标到等距坐标准确地说可以像这样完成

    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因为绘制不是对齐于图块,而是对齐于图像

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

[![enter image description here][1]][1]

上述示例的完整源代码

	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因为绘制不是对齐于图块,而是对齐于图像
	
			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();


<details>
<summary>英文:</summary>

Converting Cartesian coordinates to isometric is (sort of) done like this:

    float isometricX = cartesianX - cartesianY;
    float isometricY = (cartesianX + cartesianY) * 0.5f;

The formula needs to be scaled by the *height-to-width* ratio of the tiles as well and I think that is where it&#39;s going wrong in your code.

Given an unprojected `worldMousePosition` you can get the coordinates and tile coordinates like this:

		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&#39;t aligned to the tile, it&#39;s aligned to the image

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

[![enter image description here][1]][1]

Full source code for the example above:
	
	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(&quot;default.fnt&quot;), Gdx.files.internal(&quot;default.png&quot;), false);
			textures = new Texture[] {
				new Texture(Gdx.files.internal(&quot;tile.png&quot;))
			};
	
			for(int x = 0; x &lt; MAP_WIDTH; ++x) {
				for(int y = 0; y &lt; MAP_HEIGHT; ++y) {
					int rnd = MathUtils.random(10);
					if (rnd &lt; 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&#39;t aligned to the tile, it&#39;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 &gt;= 0; --col) {
				for (int row = MAP_HEIGHT - 1; row &gt;= 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 &amp;&amp; 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 &gt;= 0; --col) {
					for (int row = MAP_HEIGHT - 1; row &gt;= 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(&quot;(%d, %d)&quot;, col, row), x, y);
					}
				}
			}
	
			String str = String.format(&quot;World position (%.2f, %.2f), Tile (%d, %d)&quot;, worldPosition.x, worldPosition.y, (int)worldPosition.x, (int)worldPosition.y);
			font.draw(batch, str, worldMousePosition.x, worldMousePosition.y);
			batch.end();
		}
	}


  [1]: https://i.stack.imgur.com/E81ng.gif

</details>



# 答案2
**得分**: 0

抱歉您的要求是只返回翻译好的部分所以我将只提供翻译后的内容

我无法回复bornander的帖子但我的调整将在以下位置

```csharp
        int tileX = (int) Math.Floor(worldPosition.x);
        int tileY = (int) Math.Floor(worldPosition.y);

简单的(int)转换将在存在负值的情况下在0周围提供错误的位置,而使用Math.Floor将按预期工作。

英文:

I cant respond to bornander's post, but my tweak would be at

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

Where simple (int) cast will provide wrong position around 0 with negative values, if there are tiles, while using Math.Floor will work as intended.

huangapple
  • 本文由 发表于 2020年10月6日 06:07:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/64216848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定