Как повернуть структуру гексагональных плит на шестиугольной сетке?

В моей 2D-изометрической игре используется гексагональная сетка. Что касается изображения ниже, как мне повернуть синие шестиугольные структуры на 60 градусов вокруг розовых шестиугольников?

http://www.algonet.se/~afb/spriteworld/ongoing/HexMap.jpg

EDIT:

Главный гекс равен (0,0). Другие гексы - дети, их количество фиксировано. Я буду определять только одну позицию (в данном случае ее право) и рассчитать другие направления, если это необходимо (левый-правый, правый-ботом, правый-верхний, левый-верхний и левый). Другие гексы определяются как: Package.Add (-1,0), Package.Add (-2,0) и т. Д.

введите описание изображения здесь>> </p>

<pre><code>---- +: = 0 = + ----</code></pre>

<p> В этом коде <code>---- +: = 1 =: + ----</code> находится главный hex и <code>---- +: = 2 =: + --- -</code> - это шестнадцатеричный, который я хочу повернуть, но он не работает: </p>

<p> <img src =

10 голосов | спросил ruzsoo 26 J000000Tuesday11 2011, 23:17:50

2 ответа


11

Как отмечает Мартин Сойка , вращение проще, если вы конвертируете в другую систему координат, выполните вращение, а затем конвертировать назад.

Я использую другую систему координат, чем Мартин, обозначен как x,y,z. В этой системе нет колебания, и это полезно для множества шестнадцатеричных алгоритмов. В этой системе вы можете вращать шестнадцатеричный код вокруг 0,0,0 путем «поворота» координат и отображения их знаков: x,y,z превращается в -y,-z,-x в одну сторону и -z,-x,-y другим способом. У меня есть диаграмма на этой странице .

(Прошу прощения за x /y /z против X /Y, но я использую x /y /z на своем сайте, и вы используете X /Y в своем коде, поэтому в этом ответе дело имеет значение! собираюсь использовать xx,yy,zz как имена переменных ниже, чтобы попытаться сделать это легче.)

Преобразуйте свой X,Y в формате x,y,z:

xx = X - (Y - Y&1) / 2
zz = Y
yy = -xx - zz

Выполните поворот на 60 ° так или иначе:

xx, yy, zz = -zz, -xx, -yy
     # OR
xx, yy, zz = -yy, -zz, -xx

Преобразуйте x,y,z обратно в свой X,Y:

X = xx + (zz - zz&1) / 2
Y = zz

Например, если вы начинаете с (X = -2, Y = 1) и хотите повернуть на 60 ° вправо, вы должны преобразовать:

xx = -2 - (1 - 1&1) / 2 = -2
zz = 1
yy = 2-1 = 1

затем поверните -2,1,1 60 ° справа с помощью:

xx, yy, zz = -zz, -xx, -yy = -1, 2, -1

, как вы видите здесь:

Пример вращения шестнадцатеричного для -2,1,1

затем преобразуйте -1,2,-1 назад:

X = -1 + (-1 - -1&1) / 2 = -2
Y = -1

So (X = -2, Y = 1) поворачивается на 60 ° вправо (X = -2, Y = -1).

ответил amitp 14 Maypm13 2013, 21:22:55
4

Сначала определим новый номер. Не беспокойтесь, это легко.

  • f : f × f = -3

Или, проще говоря: f = √3 × i , причем i является мнимый блок . При этом вращение на 60 градусов по часовой стрелке такое же, как умножение на 1/2 × (1 - f ) , а вращение на 60 градусов против часовой стрелки такое же, как и умножение на 1/2 × (1 + f ) . Если это звучит странно, помните, что умножение на комплексное число совпадает с вращением в 2D-плоскости. Мы просто «сквошем» комплексные числа в мнимом направлении немного (на √3), чтобы не иметь дело с квадратными корнями ... или нецелыми, если на то пошло.

Мы также можем записать точку (a, b) как a + b × f .

Это позволяет нам вращать любую точку на плоскости; например, точка (2,0) = 2 + 0 × f поворачивается на (1, -1), затем на (-1, -1), (-2,0), ( -1,1), (1,1) и, наконец, обратно в (2,0), просто путем его умножения.

Конечно, нам нужен способ перевести эти точки из наших координат в те, которые мы делаем вращения, а затем снова. Для этого необходим другой бит информации: если точка, которую мы делаем, вращается вокруг «слева» или «справа» вертикальной линии. Для простоты мы объявляем, что имеет значение «wobble» w of 0, если оно находится слева от него (например, центр вращения [0,0] в ваших нижних двух изображениях) и 1, если он находится справа от него. Это расширяет наши исходные точки до трехмерных; ( x , y , w ), при этом "w" будет 0 или 1 после нормализации. Функция нормализации:

NORM: ( x , y , w ) -> ( x + floor ( w /2), y , w mod 2), с "mod" что он возвращает только положительные значения или ноль.

Теперь наш алгоритм выглядит следующим образом:

  1. Преобразуйте наши точки ( a , b , c ) в их позиции относительно центра вращения ( x , y , w ), вычисляя ( a - x , b - y , c - w ), затем нормализуя результат. Это означает, что центр вращения равен (0,0,0).

  2. Преобразуйте наши точки из их «родных» координат в вращательные сложные: ( a , b , c ) - > (2 × a + c , b ) = 2 × a + c + b × f

  3. Поверните наши точки, умножив их на одно из приведенных выше чисел вращения.

  4. Ra - преобразовать точки от вращательных координат к их «родным»: ( r , s ) -> (floor ( r /2), s , r mod 2), с "mod", как указано выше.

  5. Переверните точки обратно в исходное положение, добавив их в центр вращения ( x , y , z ) и нормализации.


Простая версия наших «триплексных» чисел на основе f в C ++ будет выглядеть так:

class hex {
    public:
        int x;
        int y;
        int w; /* "wobble"; for any given map, y+w is either odd or
                  even for ALL hexes of that map */
    hex(int x, int y, int w) : x(x), y(y), w(w) {}
    /* rest of the implementation */
};

class triplex {
    public:
        int r; /* real part */
        int s; /* f-imaginary part */
        triplex(int new_r, int new_s) : r(new_r), s(new_s) {}
        triplex(const hex &hexfield)
        {
            r = hexfield.x * 2 + hexfield.w;
            s = hexfield.y;
        }
        triplex(const triplex &other)
        {
            this->r = other.r; this->s = other.s;
        }
    private:
        /* C++ has crazy integer division and mod semantics. */
        int _div(int a, unsigned int b)
        {
            int res = a / b;
            if( a < 0 && a % b != 0 ) { res -= 1; }
            return res;
        }
        int _mod(int a, unsigned int b)
        {
            int res = a % b;
            if( res < 0 ) { res += a; }
            return res;
        }
    public:
        /*
         * Self-assignment operator; simple enough
         */
        triplex & operator=(const triplex &rhs)
        {
            this->r = rhs.r; this->s = rhs.s;
            return *this;
        }
        /*
         * Multiplication operators - our main workhorse
         * Watch out for overflows
         */
        triplex & operator*=(const triplex &rhs)
        {
            /*
             * (this->r + this->s * f) * (rhs.r + rhs.s * f)
             * = this->r * rhs.r + (this->r * rhs.s + this->s * rhs.r ) * f
             *   + this->s * rhs.s * f * f
             *
             * ... remembering that f * f = -3 ...
             *
             * = (this->r * rhs.r - 3 * this->s * rhs.s)
             *   + (this->r * rhs.s + this->s * rhs.r) * f
             */
            int new_r = this->r * rhs.r - 3 * this->s * rhs.s;
            int new_s = this->r * rhs.s + this->s * rhs.r;
            this->r = new_r; this->s = new_s;
            return *this;
        }
        const triplex operator*(const triplex &other)
        {
            return triplex(*this) *= other;
        }
        /*
         * Now for the rotations ...
         */
        triplex rotate60CW() /* rotate this by 60 degrees clockwise */
        {
            /*
             * The rotation is the same as multiplikation with (1,-1)
             * followed by halving all values (multiplication by (1/2, 0).
             * If the values come from transformation from a hex field,
             * they will always land back on the hex field; else
             * we might lose some information due to the last step.
             */
            (*this) *= triplex(1, -1);
            this->r /= 2;
            this->s /= 2;
        }
        triplex rotate60CCW() /* Same, counter-clockwise */
        {
            (*this) *= triplex(1, 1);
            this->r /= 2;
            this->s /= 2;
        }
        /*
         * Finally, we'd like to get a hex back (actually, I'd
         * typically create this as a constructor of the hex class)
         */
        operator hex()
        {
            return hex(_div(this->r, 2), this->s, _mod(this->r, 2));
        }
};
ответил Martin Sojka 28 J000000Thursday11 2011, 17:12:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132