Как создать плиточную карту на Java для 2D-игры?
Вопрос
Не знаю, как подойти к этой проблеме.
По сути, мне нужно представление Pixel -> Tile для окна размером 400x400.Каждая координата на экране, например 120x300
должен быть частью плитки.Мой самый маленький спрайт — 4 пикселя, поэтому можно сказать, что 1 тайл = 4 пикселя.Спрайты игрока и врага имеют размер 20 x 20, поэтому каждый игрок/плохой парень будет занимать 5 плиток.
Затем я хочу использовать этот класс Map, чтобы:
Получите координаты x/y спрайта игрока/монстра, указав индекс/идентификатор плитки.
Знать, где находятся границы, чтобы спрайт не выходил за их пределы.
400x400
, тем самым скрывая это.Обнаружение столкновений, зная, свободна ли плитка или нет.
Как это может быть сделано?Здесь речь конкретно идет о преобразовании x,y->tile или tile index->x,y (для правильного рисования спрайтов).
Решение
Во-первых, разделите концепцию пикселя, который занимается только представлением, на тайл, который является реальным игровым объектом с ограничениями, которые он накладывает на игру.
Я считаю, что хороший способ разобраться в подобных вещах — начать с наброска примерного 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)..
Плитки могут быть внутренне представлены как двумерный массив или одиночный массив, и в этом случае вы должны использовать какую-то внутреннюю схему представления для сопоставления вашего массива с квадратами доски, то есть мод-арифметику.
Другие советы
Короткий ответ:Операции умножения и модуля.
Но если вас это ставит в тупик, я бы посоветовал вам серьезно освежить знания по математике, прежде чем пытаться написать игру.
Также ваше заявление
Мой самый маленький спрайт - 4 пикселя, поэтому мы можем сказать, что 1 плитка = 4 пикселя.Игрок и вражеские спрайты - это 20 х 20, поэтому каждый игрок/плохой парень будет занимать 5 плиток.
не работает ни для какой разумной геометрии.Если под «1 плитка = 4 пикселя» вы подразумеваете, что плитки имеют размер 2х2, то игрок берет 100, а не пять.Если вы имеете в виду, что это 4x4, то игроки берут 25, что все равно не 5.
/** 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;
}
}
Надеюсь, это поможет вам начать.Весь код пишется без компилятора, поэтому он будет содержать опечатки и, конечно же, ошибки, которые могут распространяться по лицензии Creative Commons.
Подход к хранению частей в наборе должен работать хорошо, если их не так много.Он должен работать лучше, чем 2D-массив, если большая часть доски не содержит фигур.В настоящее время все это предполагает отсутствие перекрывающихся частей.Если они вам нужны, getPieceOnTile должен вернуть коллекцию частей.Набор, если порядок не имеет значения, и список, если имеет значение.