如何用 Java 为 2D 游戏构建 Tiled 地图?

发布于 2024-07-14 21:07:39 字数 461 浏览 7 评论 0原文

不知道如何解决这个问题。

基本上,我想要一个 Pixel -> 400x400 窗口的平铺表示。 屏幕上的每个坐标(例如 120x300)都应该是图块的一部分。 我最小的精灵是 4 个像素,所以我们可以说 1 个图块 = 4 个像素。 玩家和敌人精灵都是 20 x 20,因此每个玩家/坏人将占据 5 个方块。

然后我想使用这个 Map 类来:

  • 通过提供图块的索引/id 来检索玩家/怪物精灵的 x/y 坐标。

  • 知道边界在哪里,所以它不会将精灵移动到400x400之外,从而隐藏它。

    知道边界
  • 碰撞检测,了解某个图块是否是空的。

如何才能做到这一点? 这里具体讨论 x,y-> 图块或图块索引->x,y 转换(用于正确绘制精灵)。

Not sure how to approach this problem.

Basically, I want a Pixel -> Tile representation of a 400x400 window. Each coordinate on the screen, e.g 120x300 should be part of a tile. My smallest sprite is 4 pixels, so we can say that 1 tile = 4 pixels. The player and enemy sprites are all 20 x 20, so each player/bad guy will occupy 5 tiles.

Then I want to use this Map class to:

  • Retrieve the x/y coordinates of a player/monster sprite by suppling the index/id of the tile.

  • Knowing where the boundaries are, so it doesn't move the sprite beyond 400x400, thus hiding it.

  • Collision detection, knowing whether a tile is vacant or not.

How can this be done? Talking specifically about the x,y->tile or tile index->x,y conversion (for drawing the sprites appropriately) here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故笙诉离歌 2024-07-21 21:07:39

首先,将像素的概念与图块分开,像素仅与表示有关,图块是实际的游戏对象,对游戏施加了约束。

我发现解决此类问题的一个好方法是开始勾画出您想要的粗略 API。 类似于:

public class Board {
  public Board (int width, int height){.. }
  public boolean isOccupied(int x, int y){.. }
  public void moveTo(Point from, Point to) { .. 
    (maybe throws an exception for outofbounds )

棋盘的所有内部单元都在图块中,而不是像素中。
然后,可以通过一些内部乘法从棋盘中独立地从图块表示中导出像素信息 -

  public Point getPixelPosition(int xTilePos, int yTilePos, int pixelsPerTile)..

图块可以在内部表示为二维数组或单个数组,在这种情况下,您可以使用某种内部表示方案来将您的数组映射到棋盘方块,从而进行 mod 算术。

Firstly, split out the concept of a pixel, which is just concerned with representation, with a tile, which is an actual game object with constraints it places on the game.

I find a good way to disentangle things like this is to start out sketching out the rough API of what you want. Something like:

public class Board {
  public Board (int width, int height){.. }
  public boolean isOccupied(int x, int y){.. }
  public void moveTo(Point from, Point to) { .. 
    (maybe throws an exception for outofbounds )

where all internal units of the board are in tiles, not pixels.
Then pixel information can be derived from the board independantly from the tile representation with a bit of internal multiplication-

  public Point getPixelPosition(int xTilePos, int yTilePos, int pixelsPerTile)..

The tiles can be internally represented as a 2d array or a single array, in which case you'd use some kind of internal representation scheme to map your array to the board squares, thus the mod arithmetic.

绝情姑娘 2024-07-21 21:07:39

简短回答:乘法和模运算。

但如果这让您感到困惑,我建议您在尝试编写游戏之前认真复习一下数学。

还有你的发言

我最小的精灵是 4 像素,所以我们
可以说 1 个瓦片 = 4 个像素。 这
玩家和敌方精灵都是 20 x
20,所以每个玩家/坏人都会占据
5 块。

不适用于任何合理的几何形状。 如果“1 个图块 = 4 个像素”意味着图块为 2x2,那么玩家需要 100 个,而不是 5 个。 如果你的意思是他们是 4x4,那么玩家会选择 25,但这仍然不是 5。

Short answer: Multiplication and Modulo operations.

But if this is stumping you, I'd suggest you do a serious math refresher before trying to write a game.

Also your statement

My smallest sprite is 4 pixels, so we
can say that 1 tile = 4 pixels. The
player and enemy sprites are all 20 x
20, so each player/bad guy will occupy
5 tiles.

doesn't work out for any reasonable geometry. If by "1 tile = 4 pixels" you mean that the tiles are 2x2, then a player takes 100, not five. If you mean they are 4x4 then players take 25, which still isn't 5.

青丝拂面 2024-07-21 21:07:39
/** size of a tile in pixel (for one dimension)*/
int TILE_SIZE_IN_PIXEL = 4;
/** size of a piece in tiles (for one dimension)*/
int PIECE_SIZE_IN_TILE = 5;


public int tileToPixel(int positionInTiles){
    return TILE_SIZE_IN_PIXEL * positionInTiles;
}

/** returns the tile coordinate to which the given tile coordinate belongs 

Note: tileToPixel(pixelToTile(x)) only returns x if x is the upper or left edge of a tile
*/
public int pixelToTile(int positionInPixel){
    return positionInPixel / TILE_SIZE_IN_PIXEL;
}

您可能还需要对两个参数(x 和 y at)进行操作的方法。

对于 ID-> 件转换(反之亦然),您可以使用多种方法。 选择哪一种取决于具体的要求(速度、游戏大小……)。 因此,请确保隐藏实现细节,以便稍后可以更改它们。

我将从一个真正简单的解决方案开始:

public class Piece{
    /** x position measured in tiles */
    private int x;
    /** y position measured in tiles */
    private int y;

    /** I don't think you need this, but you asked for it. I'd pass around Piece instances instead */
    private final  Long id;

    public void getX(){
        return x;
    }
    public void getY(){
        return y;
    }

    public void getID(){
        return id;
    }

}

public class Board(){
    private Set<Long,Piece> pieces = new HashMap<Piece>(pieces);

    public Piece getPieceOnTile(int tileX, int tileY){ 
        for(Piece piece:pieces){
             if (isPieceOnTile(piece, tileX, tileY)) return piece;
        }
    }

    private boolean isPieceOnTile(piece, tileX, tileY){
        if (piece.getX() < tileX) return false;
        if (piece.getX() > tileX + PIECE_SIZE_IN_TILE) return false;

        if (piece.getY() < tileY) return false;
        if (piece.getY() > tileY + PIECE_SIZE_IN_TILE) return false;

        return true;
    }
}

希望能让您开始。 所有代码都是在附近没有编译器的情况下编写的,因此会包含拼写错误,当然还有错误,这些错误可能会在知识共享许可下分发。

如果棋子数量不多,那么将棋子保留在一组中的方法应该会很有效。 只要大多数板区域不包含一块,它应该比 2D 阵列工作得更好。 目前整个事情假设没有重叠的部分。 如果您需要那些 getPieceOnTile 必须返回一个碎片集合。 如果顺序不重要,则为集合;如果顺序重要,则为列表。

/** size of a tile in pixel (for one dimension)*/
int TILE_SIZE_IN_PIXEL = 4;
/** size of a piece in tiles (for one dimension)*/
int PIECE_SIZE_IN_TILE = 5;


public int tileToPixel(int positionInTiles){
    return TILE_SIZE_IN_PIXEL * positionInTiles;
}

/** returns the tile coordinate to which the given tile coordinate belongs 

Note: tileToPixel(pixelToTile(x)) only returns x if x is the upper or left edge of a tile
*/
public int pixelToTile(int positionInPixel){
    return positionInPixel / TILE_SIZE_IN_PIXEL;
}

You'll probably want methods operating on two arguments (x and y at) as well.

For the ID->piece conversion and vice versa you have various approaches available. Which one to choose depends on the exact requirements (speed, size of game ...). So make sure that you are hiding the implementation details, so you can change them later on.

I'd start with a real easy solution:

public class Piece{
    /** x position measured in tiles */
    private int x;
    /** y position measured in tiles */
    private int y;

    /** I don't think you need this, but you asked for it. I'd pass around Piece instances instead */
    private final  Long id;

    public void getX(){
        return x;
    }
    public void getY(){
        return y;
    }

    public void getID(){
        return id;
    }

}

public class Board(){
    private Set<Long,Piece> pieces = new HashMap<Piece>(pieces);

    public Piece getPieceOnTile(int tileX, int tileY){ 
        for(Piece piece:pieces){
             if (isPieceOnTile(piece, tileX, tileY)) return piece;
        }
    }

    private boolean isPieceOnTile(piece, tileX, tileY){
        if (piece.getX() < tileX) return false;
        if (piece.getX() > tileX + PIECE_SIZE_IN_TILE) return false;

        if (piece.getY() < tileY) return false;
        if (piece.getY() > tileY + PIECE_SIZE_IN_TILE) return false;

        return true;
    }
}

Hope that gets you started. All code is writen without a compiler nearby so it will include typos and of course bugs, which may be distributed under the creative commons license.

The approach of keeping the pieces in a set should work well if there are not to many pieces. It should work better than a 2D array as long as most board area does not contain a piece. The whole thing currently assumes there are no overlapping pieces. If you need those getPieceOnTile must return a Collection of pieces. A set if order does not matter, a List if it does.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文