Bagaimana cara memutar struktur ubin heksagonal pada kisi heksagonal?

10

Game isometrik 2D saya menggunakan peta kisi heksagonal. Mengacu pada gambar di bawah, bagaimana cara memutar struktur segi enam biru muda sebesar 60 derajat di sekitar segi enam merah muda?

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

EDIT:

Hex utama adalah (0,0). Hexes lainnya adalah anak-anak, jumlah mereka tetap. Saya akan mendefinisikan hanya satu posisi (dalam hal ini kanannya) dan menghitung arah lain jika diperlukan (kiri-bawah, bot-kanan, kanan-atas, kiri-atas dan kiri). Hex lainnya didefinisikan seperti: Package.Add (-1,0), Package.Add (-2,0) dan seterusnya.

masukkan deskripsi gambar di sini

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;
}

Dalam kode ini Numberadalah hex utama dan Pointhex yang ingin saya putar, tetapi tidak berfungsi:

masukkan deskripsi gambar di sini

ruzsoo
sumber
1
apa sebenarnya masalahnya? bagaimana menerapkannya atau beberapa hasil buruk?
Ali1S232
Apakah Anda menjentikkan rotasi ke 6 tepi hexagon pink, atau apakah sudut rotasi sewenang-wenang? Juga, yang mana dari heksagon pink di struktur sisi kanan yang Anda putar?
Keeblebrox
Mungkin lebih mudah untuk memutar ubin individu tetapi ini mengarah pada pertanyaan tentang apa yang terjadi pada ubin yang sudah ada dan ini akan baik untuk diketahui secara umum sebelum saya dapat mencoba dan memberikan tanggapan.
James
Maaf untuk kesalahan. Saya berbicara tentang bagian kiri gambar. Saya mendapat hasil yang buruk, bahkan beberapa heks ada di tempat yang salah. Heks pink adalah heks utama dan biru cerah adalah anak-anaknya. Misalkan hex utama adalah (5,5) maka saya mendefinisikan hex anak (-1,0) sehingga anak berada di sisi kiri pink dan seterusnya. Saya ingin tahu bagaimana memutar hex anak ini dengan 60 derajat (maka akan berada di kiri atas pink). lebih mudah: saya sedang mengerjakan sistem build di game strategi saya. Seringkali dalam gim strategi Anda dapat memutar bangunan sebelum menempatkannya. Saya akan menghitung heks yang perlu dibangun.
ruzsoo
Apakah himpunan heks yang dipilih harus persis sama dengan hitungan setiap waktu? Yaitu, apakah Anda misalnya secara khusus menempatkan 3 objek pada heksa di kedua sisi heks pink? Atau apakah Anda hanya ingin menggambar garis dengan panjang tertentu dan memutuskan mana heksa terbaik memotongnya, terlepas dari berapa banyak yang akan menjadi? Apakah Anda ingin melakukan ini dengan jumlah tetap hex, atau nomor sewenang-wenang?
Tim Holt

Jawaban:

11

Seperti yang dicatat Martin Sojka , rotasi lebih sederhana jika Anda mengonversi ke sistem koordinat yang berbeda, melakukan rotasi, lalu mengonversi kembali.

Saya menggunakan sistem koordinat yang berbeda dari yang dilakukan Martin, berlabel x,y,z. Tidak ada goyangan dalam sistem ini, dan ini berguna untuk banyak algoritma hex. Dalam sistem ini Anda dapat memutar heks sekitar 0,0,0dengan "memutar" koordinat dan membalik tanda-tanda mereka: x,y,zberubah menjadi -y,-z,-xsatu arah dan -z,-x,-yke arah lain. Saya punya diagram di halaman ini .

(Saya minta maaf tentang x / y / z vs X / Y tapi saya menggunakan x / y / z di situs saya dan Anda menggunakan X / Y dalam kode Anda sehingga dalam menjawab hal ini penting! Jadi saya akan menggunakan xx,yy,zzsebagai nama variabel di bawah ini untuk mencoba membuatnya lebih mudah untuk dibedakan.)

Konversi X,Ykoordinat Anda ke x,y,zformat:

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

Lakukan rotasi dengan 60 ° dengan satu cara atau yang lain:

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

Konversi x,y,zkembali ke Anda X,Y:

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

Misalnya, jika Anda mulai dengan (X = -2, Y = 1) dan ingin memutar 60 ° ke kanan, Anda akan mengonversi:

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

kemudian putar -2,1,160 ° ke kanan dengan:

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

seperti yang Anda lihat di sini:

Contoh rotasi heks untuk -2,1,1

lalu konversikan -1,2,-1kembali:

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

Jadi (X = -2, Y = 1) berputar 60 ° ke dalam (X = -2, Y = -1).

amitp
sumber
4

Mari kita tentukan nomor baru. Jangan khawatir, ini mudah.

  • f : f × f = -3

Atau, sederhananya: f = √3 × i , dengan i menjadi unit imajiner . Dengan ini, rotasi 60 derajat searah jarum jam sama dengan perkalian dengan 1/2 × (1 - f ) , dan rotasi 60 derajat berlawanan arah jarum jam sama dengan perkalian dengan 1/2 × (1 + f ) . Jika ini terdengar aneh, ingatlah bahwa perkalian dengan bilangan kompleks sama dengan rotasi pada bidang 2D. Kami hanya "menekan" bilangan kompleks dalam arah imajiner sedikit (oleh √3) untuk tidak harus berurusan dengan akar kuadrat ... atau bukan bilangan bulat, dalam hal ini.

Kita juga dapat menulis titik (a, b) sebagai a + b × f .

Ini memungkinkan kita memutar titik mana pun di pesawat; misalnya, titik (2,0) = 2 + 0 × f berputar ke (1, -1), lalu ke (-1, -1), (-2,0), (-1,1), ( 1,1) dan akhirnya kembali ke (2,0), cukup dengan mengalikannya.

Tentu saja, kita membutuhkan cara untuk menerjemahkan titik-titik itu dari koordinat kita ke titik-titik rotasi yang kita lakukan, dan kemudian kembali lagi. Untuk ini, sedikit informasi lain yang diperlukan: Jika titik yang kita lakukan rotasi di sekitar adalah ke "kiri" atau ke "kanan" dari garis vertikal. Untuk kesederhanaan, kami menyatakan bahwa memiliki nilai "goyangan" w dari 0 jika di sebelah kiri (seperti pusat rotasi [0,0] di dua gambar bawah Anda), dan dari 1 jika ke kanan itu. Ini memperluas poin asli kami menjadi tiga dimensi; ( x , y , w ), dengan "w" menjadi 0 atau 1 setelah normalisasi. Fungsi normalisasi adalah:

NORM: ( x , y , w ) -> ( x + lantai ( w / 2), y , w mod 2), dengan operasi "mod" yang ditentukan sehingga hanya mengembalikan nilai positif atau nol.

Algoritma kami sekarang terlihat sebagai berikut:

  1. Ubah titik kita ( a , b , c ) ke posisi mereka relatif terhadap pusat rotasi ( x , y , w ) dengan menghitung ( a - x , b - y , c - w ), lalu menormalkan hasilnya. Ini menempatkan pusat rotasi di (0,0,0) jelas.

  2. Ubah poin kami dari koordinat "asli" ke koordinat rotasi: ( a , b , c ) -> (2 × a + c , b ) = 2 × a + c + b × f

  3. Putar poin kami dengan mengalikannya dengan salah satu angka rotasi di atas, sesuai kebutuhan.

  4. Ra-mengubah titik kembali dari koordinat rotasi ke yang "asli": ( r , s ) -> (lantai ( r / 2), s , r mod 2), dengan "mod" didefinisikan seperti di atas.

  5. Ubah kembali poin kembali ke posisi semula dengan menambahkannya ke pusat rotasi ( x , y , z ) dan normalisasi.


Sebuah versi sederhana dari kami "tripleks" nomor berdasarkan f di C ++ akan terlihat seperti ini:

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
sumber