Множество старых игр выводят графику используя изометрическую проекцию и Fallout 2 входит в их число. В этой статье я расскажу об изометрии и о сложностях, которые возникают при ее использовании на примере движка Fallout 2.
Тайлы Fallout
Каждый тайл Fallout 2 состоит из изображения размером 80 на 36 точек. Как видно из рисунка тайл сохраняет некоторые пропорции:
В пропорциональном соотношении он имеет:
int width = 5*sx;
int height = 3*sy;
Где sx = 16, sy = 12. Эти величины используются при расчете всех остальных координат. Если допустим вы делаете свою игру с другими размерами тайла, но тайл сохраняет те же пропорции, вы можете поменять константы sx, sy и все координаты будут считаться под ваши размеры.
Центр тайла расположен ровно посредине картинки, с координатами (40, 18). Перевод координат работает с центром тайла.
Перевод координат
Первая задача с которой я столкнулся при написании вывода графики это естественно перевод координат из декартовой системы в изометрическую. Сложность состоит еще и в том, что Fallout использует два вида карт:
int tx = t%cols;
int ty = t/cols;
int x = 2*stx*ty - 3*stx*tx;
int y = 2*sty*ty + sty*tx;
где:
cols - это константа, показывающая ширину карты в тайлах. Допустим она равна 100.
t - это индекс тайла, координаты которого необходимо найти.
Обращаем внимание, что угол с координатами (0,0) соответствует правому верхнему углу карты и формула это учитывает. При выводе к полученному x и y необходимо добавить текущее положение камеры.
- Тайловый вид карт используется для вывода ландшафта.
- Гексагональный для вывода персонажей, объектов и вещей, лежащих на карте. Также к гексагональному виду карт привязан гексагон, который появляется под курсором на карте и указывает точку назначения при движении.
Перевод из тайловых индексов в координаты экрана
Такой перевод необходим для осуществления вывода тайлов на экран. Когда я рисую, например, тайлы ландшафта, мне необходимо знать по каким координатам рисовать тайл с определенным индексом. Для перевода используется функция:int tx = t%cols;
int ty = t/cols;
int x = 2*stx*ty - 3*stx*tx;
int y = 2*sty*ty + sty*tx;
где:
cols - это константа, показывающая ширину карты в тайлах. Допустим она равна 100.
t - это индекс тайла, координаты которого необходимо найти.
Обращаем внимание, что угол с координатами (0,0) соответствует правому верхнему углу карты и формула это учитывает. При выводе к полученному x и y необходимо добавить текущее положение камеры.
Перевод из гексоганальных индексов в координаты экрана
Учитывая то, что хэксовые индексы отличаются от тайловых тем, что в их в два раза больше и нечетные ряды немного сдвинуты получаем следующую формулу:
int tx = t%(cols*2);
int ty = t/(cols*2);
int x = stx*(ty - tx - tx/2) - 8;
int y = sty*(ty + tx - tx/2) - 32;
Как и в предыдущем случае, при выводе к полученному x и y необходимо добавить текущее положение камеры.
Перевод из координат экрана в тайловые индексы
Такой перевод необходим для осуществления так называемого "хиттеста" то есть проверки в каком тайле в данный момент находится мышка. Для получения формулы перевода воспользуемся существующими формулами, описанными выше и решим два уравнения с двумя неизвестными. Стоит отметить - учитывая то, что тайлы несколько сдвинуты по координатам изменим входящие координаты x, y чтобы они были относительно того места, где мы выводим вершину тайла. В итоге получим:
x -= 8;
y += 20;
y += 20;
int tx = (x-4*y/3)/64;
int ty = (x+4*y)/128;
int ti = ty*cols - tx;
int ty = (x+4*y)/128;
int ti = ty*cols - tx;
Перевод координат экрана в индексы хэксовой карты
Также используется для определения индекса хекса над которым парит мышка. Чтобы вычислить формулу перевода преобразуем имеющиеся формулы и в результате получим:
x += 8;
y += 32;
int tx = (y/sty - x/stx)/2;
int ty = (3*y/sty + x/stx)/4;
int hi = ty*cols*2 + tx;
Но при такой формуле возникают ошибки из-за целочисленного деления и округления до целого. Поэтому данные формулы лучше преобразовать в следующий вид:
x += 8;
y += 32;
int tx = (y*stx - x*sty)/(2*stx*sty);
int ty = (3*y*stx + x*sty)/(4*stx*sty);
return ty*cols2 + tx;
int tx = (y/sty - x/stx)/2;
int ty = (3*y/sty + x/stx)/4;
int hi = ty*cols*2 + tx;
Но при такой формуле возникают ошибки из-за целочисленного деления и округления до целого. Поэтому данные формулы лучше преобразовать в следующий вид:
x += 8;
y += 32;
int tx = (y*stx - x*sty)/(2*stx*sty);
int ty = (3*y*stx + x*sty)/(4*stx*sty);
return ty*cols2 + tx;
Вот интересно, что заставило создателей Фаллоута, так извернутся? Ведь это надо же так всё усложнить...
ОтветитьУдалить