Мой проект использует изометрическую перспективу, пока я показываю координаты в сеточном формате над ними для отладки. Однако, когда дело доходит до столкновения / блокировки сетки игрока, у меня есть проблема.
Из-за характера рисования спрайтов моя математика создает некоторые проблемы с «треугольными» угловыми пустыми областями текстур. Я думаю, что проблема примерно такая, как показано ниже (синий цвет — это то, как я считаю, как обнаруживаются мои плитки, тогда как красный цвет — это то, как они в идеале должны обнаруживаться для точного перемещения по плиткам:
Как вы можете видеть, логическое значение, которое проверяет плитку, на которой я стою (которая переводит пиксель в центр ног игрока, позже игрок станет машиной и будет брать пиксель в зависимости от направления движения), возвращает ложное и отрицательное движение в нескольких сценариях, а также позволить игроку двигаться в некоторых местах, которые не должны быть разрешены.
Я думаю, это потому, что области обрезки каждой текстуры считаются (я думаю) частью области сетки, поэтому, когда игрок находится в одной из этих угловых областей, он не проверяет правильную плитку и возвращает неправильные результаты. ,
Код, который я использую для создания сетки:
int VisualComponent::TileConversion(Tile* tileToConvert, bool xOrY)
{
int X = (tileToConvert->x - tileToConvert->y) * 64; //change 64 to TILE_WIDTH_HALF
int Y = (tileToConvert->x + tileToConvert->y) * 25;
/*int X = (tileToConvert->x * 128 / 2) + (tileToConvert->y * 128 / 2) + 100;
int Y = (tileToConvert->y * 50 / 2) - (tileToConvert->x * 50 / 2) + 100;*/
if (xOrY)
{
return X;
}
else
{
return Y;
}
}
и код для проверки движения игрока:
bool Clsentity::CheckMovementTile(int xpos, int ypos, ClsMapData* mapData) //check if the movement will end on a legitimate road tile UNOPTIMISED AS RUNS EVERY FRAME FOR EVERY TILE
{
int x = xpos + 7; //get the center bottom pixel as this is more suitable than the first on an iso grid (more realistic 'foot' placement)
int y = ypos + 45;
int mapX = (x / 64 + y / 25) / 2; //64 is TILE-WIDTH HALF and 25 is TILE HEIGHT
int mapY = (y / 25 - (x / 64)) / 2;
for (int i = 0; i < mapData->tilesList.size(); i++) //for each tile of the map
{
if (mapData->tilesList[i]->x == mapX && mapData->tilesList[i]->y == mapY) //if there is an existing tile that will be entered
{
if (mapData->tilesList[i]->movementTile)
{
HAPI->DebugText(std::to_string(mapX) + " is the x and the y is " + std::to_string(mapY));
return true;
}
}
}
return false;
}
Я немного застрял в прогрессии, пока не исправил это в игровом цикле. Если кто-то думает, что он знает об этом или может помочь, это было бы здорово, и я был бы признателен. Для справки, мои текстуры листов имеют размер 128х64 пикселя, а математика, лежащая в основе их отрисовки на экране, обрабатывает их как 128х50 (для чистой связи друг с другом).
Вместо того чтобы писать конкретные процедуры для рендеринга и отображения кликов, серьезно подумайте о том, чтобы рассматривать их как два представления данных, которые можно преобразовать в терминах матричных преобразований координатного пространства. У вас может быть два координатных пространства — одно из них представляет собой красивую прямоугольную сетку, которую вы используете для позиционирования и логики. Другой — это изометрический вид, который вы используете для отображения и ввода.
Если вы не знакомы с линейной алгеброй, потребуется немного времени, чтобы обернуть вокруг нее голову, но как только вы это сделаете, все станет тривиально.
Итак, как это работает? Ваш изометрический вид — это просто поворот стандартного вида сетки болота, верно? Ну, близко. Изометрический вид также изменяет размеры, если вы начинаете с квадратной сетки. В любом случае: мы можем просто сделать простое преобразование координат?
Точка текстуры => Повернуть на 45 градусов => Масштабировать по sqrt (2), поскольку при повороте на 45 градусов размер блока изменяется на sqrt (1 * 1 + 1 * 1)
Нажмите точку => очистить от накипи по sqrt (2), чтобы расфиксировать => развернуть на 45 градусов
Если вы можете выполнять преобразования координат, то вам придется иметь дело со стандартной болотной прямоугольной сеткой для всего остального, что вы пишете, что сделает вашу любую другую логику НАМНОГО проще. Ваши вычисления там не будут включать вычисления углов или наклонов. Например. Теперь ваша логика «могу я сдвинуться вниз» стала намного проще.
Допустим, у вас есть плитки размером 64х64 для простоты. Теперь преобразование щелчка на экране в логическую плитку просто:
(int, int) whichTile(clickX, clickY) {
logicalX, logicalY = transform(clickX, clickY)
return (logicalX / 64, logicalY / 64)
}
Вы можете выполнять проверки, например, видеть, находятся ли x0, y0 и x1, y1 на одной и той же плитке в логическом пространстве, с помощью некоторого простого:
bool isSameTile(x0, y0, x1, y1) {
return floor(x0/64) == floor(x1/64) && floor(y0/64) == floor(y1/64)
}
Все становится намного проще, когда вы определяете преобразования и работаете в логическом пространстве.
http://en.wikipedia.org/wiki/Rotation_matrix
http://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation
http://www.alcove-games.com/advanced-tutorials/isometric-tile-picking/
Если вы не хотите иметь дело с какой-либо библиотекой матриц, вы можете довольно просто сделать эквивалентную математику, но если вы отделяете задачи управления логикой от отображения / ввода посредством этих преобразований, я подозреваю, что вам будет намного проще ,