Làm cách nào để xoay cấu trúc của các hình lục giác trên lưới lục giác?


10

Trò chơi isometric 2D của tôi sử dụng bản đồ lưới lục giác. Để tham khảo hình ảnh bên dưới, làm cách nào để xoay các cấu trúc hình lục giác màu xanh nhạt 60 độ quanh các hình lục giác màu hồng?

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

BIÊN TẬP:

Hex chính là (0,0). Các hình lục giác khác là trẻ em, số lượng của chúng là cố định. Tôi sẽ chỉ xác định một vị trí (trong trường hợp này là bên phải) và tính các hướng khác nếu cần (phía dưới bên trái, bên phải botom, bên phải trên cùng, bên trái và bên trái). Các hình lục giác khác được định nghĩa như: Gói.Add (-1,0), Gói.Add (-2,0), v.v.

nhập mô tả hình ảnh ở đây

switch(Direction)
{
case DirRightDown:
    if(Number.Y % 2 && Point.X % 2)
        Number.X += 1;
    Number.Y += Point.X + Point.Y / 2;

    Number.X += Point.X / 2 - Point.Y / 1.5;
    break;
}

Trong mã Numbernày là hex chính và Pointlà hex mà tôi muốn xoay, nhưng nó không hoạt động:

nhập mô tả hình ảnh ở đây


1
chính xác vấn đề là gì? Làm thế nào để thực hiện điều đó hoặc một số kết quả xấu?
Ali1S232

Bạn đang chụp các góc quay đến 6 cạnh của hình lục giác màu hồng, hay các góc xoay là tùy ý? Ngoài ra, hình lục giác màu hồng nào trong cấu trúc bên phải bạn đang xoay quanh?
Keeblebrox

Có thể dễ dàng hơn để xoay các ô riêng lẻ nhưng điều này dẫn đến câu hỏi điều gì xảy ra với các ô đã có sẵn và nói chung sẽ rất tốt để biết trước khi tôi có thể thử và đưa ra phản hồi.
James

Xin lỗi vì sai lầm. Tôi đang nói về phần bên trái của hình ảnh. Tôi đã có kết quả xấu, bao giờ một số hình lục giác ở sai vị trí. Các hình lục giác màu hồng là hình lục giác chính và màu xanh sáng là trẻ em. Giả sử hex chính là (5,5) thì tôi xác định hex con (-1,0) để con nằm ở bên trái màu hồng và cứ thế. Tôi muốn biết làm thế nào xoay đứa trẻ này 60 độ (sau đó nó sẽ ở phía trên bên trái của màu hồng). dễ dàng hơn: tôi đang làm việc trên hệ thống xây dựng trong trò chơi chiến lược của mình. Thông thường trong các trò chơi chiến lược, bạn có thể xoay tòa nhà trước khi đặt nó. Tôi sẽ tính toán các hình lục giác cần xây dựng.
ruzsoo

Tập hợp các hình lục giác được chọn có phải chính xác cùng một số đếm mỗi lần không? Đó là, ví dụ, bạn có đặc biệt đặt 3 đối tượng trên các hình lục giác ở hai bên của hình lục giác màu hồng không? Hay bạn chỉ muốn vẽ một đường có độ dài nhất định và quyết định hình lục giác nào giao nhau tốt nhất, bất kể số đó sẽ là bao nhiêu? Bạn có muốn làm điều này với một số lượng hình lục giác cố định, hoặc một số tùy ý?
Tim Holt

Câu trả lời:


11

Như Martin Sojka lưu ý, các phép quay sẽ đơn giản hơn nếu bạn chuyển đổi sang một hệ tọa độ khác, thực hiện xoay, sau đó chuyển đổi trở lại.

Tôi sử dụng một hệ tọa độ khác với Martin, được dán nhãn x,y,z. Không có sự chao đảo trong hệ thống này và nó rất hữu ích cho nhiều thuật toán hex. Trong hệ thống này, bạn có thể xoay hình lục giác xung quanh 0,0,0bằng cách xoay xoay tọa độ và lật các dấu hiệu của chúng: x,y,zbiến thành -y,-z,-xmột cách và một cách -z,-x,-ykhác. Tôi có một sơ đồ trên trang này .

(Tôi xin lỗi về x / y / z so với X / Y nhưng tôi sử dụng x / y / z trên trang web của tôi và bạn sử dụng X / Y trong mã của mình để trong câu trả lời này có vấn đề! Vì vậy, tôi sẽ sử dụng xx,yy,zznhư các tên biến dưới đây để cố gắng phân biệt dễ dàng hơn.)

Chuyển đổi X,Ytọa độ của bạn sang x,y,zđịnh dạng:

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

Thực hiện xoay 60 ° theo cách này hay cách khác:

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

Chuyển đổi x,y,ztrở lại của bạn X,Y:

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

Ví dụ: nếu bạn bắt đầu bằng (X = -2, Y = 1) và muốn xoay phải 60 °, bạn sẽ chuyển đổi:

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

sau đó xoay -2,1,160 ° sang phải với:

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

như bạn thấy ở đây:

Ví dụ xoay hex cho -2,1,1

sau đó chuyển đổi -1,2,-1trở lại:

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

Vậy (X = -2, Y = 1) quay 60 ° phải vào (X = -2, Y = -1).


4

Trước tiên hãy xác định một số mới. Đừng lo lắng, đó là một điều dễ dàng.

  • f : f × f = -3

Hay nói một cách đơn giản: f = 3 × i , với iđơn vị tưởng tượng . Với điều này, xoay 60 độ theo chiều kim đồng hồ giống như nhân với 1/2 × (1 - f ) và xoay 60 độ ngược chiều kim đồng hồ giống như nhân với 1/2 × (1 + f ) . Nếu điều này nghe có vẻ lạ, hãy nhớ rằng phép nhân với một số phức giống như phép quay trong mặt phẳng 2D. Chúng tôi chỉ "nén" các số phức theo hướng tưởng tượng một chút (bằng √3) để không phải xử lý căn bậc hai ... hoặc không phải là số nguyên, cho vấn đề đó.

Chúng ta cũng có thể viết điểm (a, b) là a + b × f .

Điều này cho phép chúng ta xoay bất kỳ điểm nào trong mặt phẳng; ví dụ: điểm (2,0) = 2 + 0 × f quay sang (1, -1), sau đó đến (-1, -1), (-2,0), (-1,1), ( 1,1) và cuối cùng trở lại (2,0), đơn giản bằng cách nhân nó.

Tất nhiên, chúng ta cần một cách để dịch những điểm đó từ tọa độ của chúng ta sang những điểm chúng ta thực hiện các phép quay, và sau đó quay lại. Đối với điều này, một thông tin khác là cần thiết: Nếu điểm chúng ta thực hiện xoay quanh là "bên trái" hoặc "bên phải" của đường thẳng đứng. Để đơn giản, chúng tôi tuyên bố rằng đang có một giá trị "lung lay" w 0 nếu nó sang trái của nó (như tâm xoay [0,0] ở phía dưới hai hình ảnh của bạn), và trong tổng số 1 nếu nó sang bên phải của nó Điều này mở rộng các điểm ban đầu của chúng tôi là ba chiều; ( x , y , w ), với "w" là 0 hoặc 1 sau khi chuẩn hóa. Hàm chuẩn hóa là:

BÌNH THƯỜNG: ( x , y , w ) -> ( x + floor ( w / 2), y , w mod 2), với thao tác "mod" được xác định sao cho nó chỉ trả về giá trị dương hoặc bằng không.

Thuật toán của chúng tôi bây giờ trông như sau:

  1. Biến đổi điểm của chúng tôi ( a , b , c ) thành vị trí của chúng so với tâm quay ( x , y , w ) bằng cách tính ( a - x , b - y , c - w ), sau đó bình thường hóa kết quả. Điều này đặt trung tâm quay ở (0,0,0) rõ ràng.

  2. Chuyển đổi các điểm của chúng tôi từ tọa độ "gốc" của chúng sang các tọa độ quay: ( a , b , c ) -> (2 × a + c , b ) = 2 × a + c + b × f

  3. Xoay điểm của chúng tôi bằng cách nhân chúng với một trong các số quay ở trên, nếu cần.

  4. Biến đổi các điểm trở lại từ tọa độ quay thành các điểm "gốc" của chúng: ( r , s ) -> (floor ( r / 2), s , r mod 2), với "mod" được định nghĩa như trên.

  5. Chuyển đổi lại các điểm trở lại vị trí ban đầu bằng cách thêm chúng vào tâm quay ( x , y , z ) và chuẩn hóa.


Một phiên bản đơn giản của các số "triplex" của chúng tôi dựa trên f trong C ++ sẽ giống như thế này:

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));
        }
};
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.