Galaxy2D Tutorials Галактика 2D
Конвертирование координат экрана на изометрическую карту.

Оговорка

 

Делайте то, что Вы хотите с этой информацией, хотя на весь текст - авторское право (c) 1998 Jim Adams, и текст может не быть дублирован, скопирован, отремонтирован или еще что-нибудь, если Вы сможете удумать сделать копию с него. Я не ответственен за то, что Вы сделаете с этой информацией или за любой ущерб, который вызвал этот текст, при попытке его использовать. Если Вы отправляете по почте эту статью, то укажите меня автором! И Вы не должны требовать деньги за эту статью.

 

Никакие животные не были повреждены во время создания этой статьи. Для дальнейшей информации относительно этого предмета, посетите вашу любимую библиотеку. Признаки!?! Признаки?!?! Мы не нуждаемся ни в каких воняющих признаках!!!!

 

if(overdoing_it_a_bit)

  exit(1);

 

(Отсылая к нашей Sci-Fi изометрической игре, 'Проишествие со светом')

 

Наш первый спосою преобразования из пространства экрана в пространство карты состоял в том, чтобы 'нарезать' экран на разделы размером с наши клетки - 64x32. Если только мы поместим координаты внутри одного из разделов, мы могли бы, затем изучить массив размером 64x32, и посмотреть, где точно это было, или указать на раздел карты вверх-влево, вверх-вправо, вниз-влево, вниз-вправо или на разделы карты непосредственно.

 

ПРИМЕЧАНИЕ:

В действительности, клетки - 64x31, но они дополняются до 32 самой нижней пустою строкой так что это, все подгоняется вместе правильно. Добавление работает ТОЛЬКО для вычислений. Не тратьте впустую память, чтобы хранить дополнительную строку. Это - все, потому что, когда мы выводим клетку на экран, два крайних левых и правых пикселя касаются клетки, с участком для верхней и самой нижней строк, чтобы обеспечить корректную стыковку.

 

Вот рисунок чтобы понять, что я делаю.

 

                 Край Нижней части Клетки

 

                      ............

                      ##........**

                      ####....****                  

  Правый край Клетки  ######******  Левый Край Клетки

                      ####....****

                      ##........**

                      ............

 

                  Верхний Край Клетки

 

Имеется функция:

 

void       pointer_get_map_position

       ( short pointx, short pointy,

         signed short mapxo, signed short mapyo,

         short *mapx, short *mapy )

{

  short mx, my;

  short rmx, rmy;

  short xo, yo;

  signed char xoff[5] = { -1,  0, 0, 0, 1};

  signed char yoff[5] = {  0, -1, 0, 1, 0};

  char off_map[32][64] = {

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1 },

    { 0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1 },

    { 0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1 },

    { 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1 },

    { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 },

    { 3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4 },

    { 3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4 },

    { 3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 3,3,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 },

    { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 3,3,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4 }

  };

 

  // Делим на основной размер клетки, настроено для отсечения

  mx = (short)((pointx + 32 + mapxo) / 64);

  my = (short)((pointy + 16 + mapyo) / 32);

 

  // Из них вычислить приблизительную оценку координаты карты

  rmx = mx + my;

  rmy = my - mx;

 

  // позиция указателя внутри приблизительной карты пространства

  xo = (pointx + 32 + mapxo) & 63;

  yo = (pointy + 16 + mapyo) & 31;

 

  // Далее корректируйте позиции карты, основываясь на указателях

  // точной позиции внутри тех координат карты

  rmx += xoff[off_map[yo][xo]];

  rmy += yoff[off_map[yo][xo]];

 

  // Запомним

  *mapx = (short)rmx;

  *mapy = (short)rmy;

}

 

Это быстрый и не точный метод. Хотя он и не супер, поскольку он использует массив, в котором уже почти все сделано. Те, кто были внимательны, то вы обратили внимание на маленькую ошибку - но она настолько маленькая, что я не исправил ее. Не волнуйтесь, код работает.

 

После нескольких ночей разборок, я придумал следующие формулы, чтобы заменить вышеупомянутую функцию:

 

signed short xo = pointer_xpos - (center_x + xadjust);

signed short yo = pointer_ypos - (center_y + yadjust);

signed short x  = yo + (xo/2);

signed short y  = yo + (-xo/2);

 

Этот расчет возвращает значение со знаком в x и y, которые содержат разницу между центром карты и координатами того места, где указатель мыши. Центральная координата карты должна быть та, где Вы рисуете 0, 0 координату карты, которая для нас является левым верхним углом  экрана (0, 0). Обратите внимание, что значения x и y находятся в точной КАРТЕ пространстве (опережающие чтение).

 

Xadjust и yadjust - точные переменные для скроллинга, если ваш движок их поддерживает. Обратите внимание на координаты 0, 0 клетки - это верх середина, при этом x идет справа вниз и y слева вниз (по диагонали).

 

Запутано? Скажем, мы начинаем рисовать наш экран в ЭКРАННЫХ координатах 0,0. Середина верх клетки рисуются там, поэтому левая сторона клетки обрезана по экрану. Мы помещаем наш указатель в точку в ЭКРАННЫХ координатах 125, 304. Мы - не делаем точный скроллинг, поэтому они будут 0.

 

Итак:

 

1)

xo = 125 - (0 + 0);

yo = 304 - (0 + 0);

x  = xo + (xo / 2);

y  = yo + (-xo / 2);

 

2)

xo = 125;

yo = 304;

x  = 125 + (125 / 2);

y  = 304 + (-125 / 2);

 

3)

x  = 125 + (62);

y  = 304 + -62);

 

4)

x  = 187;

y  = 242;

 

Теперь только разделите эти значения на ваш размер секции на КАРТЕ (32x32 в нашем случае) и все! Мы имеем координаты карты 5, 7! Что является ответом на ваш вопрос? Почему размер секции КАРТЫ? Я не смогу помочь вам объяснять это подробно - я не имею достаточное время или пространства, но это - точный координатный размер внутри одиночной секции карты. Если Вы не знаете его, используйте высоту клетки (32).

 

Я уверен, что это работает со всеми размерами клетки, которые имеют соотношение 2:1 (16x8, 32x16, 64x32, и т.д). Если Вы используете соотношение 3:1, то замените 2 на 3.

 

Copyright (c) 1998 by Jim Adams.  All rights reserved.

 

PMG  26 февраля 2004 (c)  Сергей Анисимов