Altıgen bir ızgaradaki altıgen fayans yapısını nasıl döndürebilirim?


10

2D izometrik oyunum altıgen ızgaralı bir harita kullanıyor. Aşağıdaki resme referans olarak, açık mavi altıgen yapıları pembe altıgenlerin etrafında 60 derece nasıl döndürebilirim?

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

DÜZENLE:

Ana altıgen (0,0) 'dır. Diğer altıgenler çocuktur, sayıları sabittir. Sadece bir konum tanımlayacağım (bu durumda sağ) ve gerekirse diğer yönleri hesaplayacağım (sol alt, sağ botom, sağ üst, sol üst ve sol). Diğer altıgenler şu şekilde tanımlanır: Package.Add (-1,0), Package.Add (-2,0) vb.

resim açıklamasını buraya girin

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

Bu kodda Numberana hex ve Pointdöndürmek istediğiniz hex, ama çalışmıyor:

resim açıklamasını buraya girin


1
sorun tam olarak nedir? bunu veya bazı kötü sonuçları nasıl uygulayabilirim?
Ali1S232

Pembe altıgenin 6 kenarına döndürmeler mi yapıyorsunuz, yoksa dönüş açıları keyfi mi? Ayrıca, sağ taraftaki pembe altıgenlerden hangisini döndürüyorsunuz?
Keeblebrox

Tek tek fayansları döndürmek daha kolay olabilir, ancak bu zaten orada bulunan fayanslara ne olduğu sorusuna yol açar ve bu, bir cevap vermeden önce genel olarak bilmek iyi olur.
James

Hata için üzgünüm. Resmin sol kısmından bahsediyorum. Kötü sonuçlar aldım, bazı altıgenler yanlış yerlerde. Pembe altıgen ana ve parlak mavi altıgenler çocuktur. Ana hex'in (5,5) olduğunu varsayalım ki çocuk hex'i (-1,0) tanımlıyorum, böylece çocuk pembenin sol tarafında vb. Bu çocuğu altıgen 60 derece nasıl döndürdüğünü bilmek istiyorum (o zaman pembenin sol üst tarafında olacak). daha kolay: Strateji oyunumda sistem kurmak üzerine çalışıyorum. Strateji oyunlarında genellikle binayı yerleştirmeden önce döndürebilirsiniz. İnşa edilmesi gereken altıgenleri hesaplayacağım.
ruzsoo

Seçili onaltılı kümelerin her seferinde tam olarak aynı olması gerekir mi? Yani, özellikle pembe altıgenin her iki tarafındaki altıgenlere 3 nesne mi yerleştiriyorsunuz? Yoksa belirli bir uzunlukta bir çizgi çizmek ve kaç tane olursa olsun hangi altıgenlerin onunla en iyi kesiştiğine karar vermek mi istiyorsunuz? Bunu sabit sayıda altıgen veya rasgele bir sayı ile yapmak istiyor musunuz?
Tim Holt

Yanıtlar:


11

As Martin Sojka Eğer başka bir koordinat sistemine dönüştürmek rotasyon gerçekleştirirseniz notlar, rotasyonlar sonra tekrar dönüştürmek, basittir.

Martin'in etiketlediğinden farklı bir koordinat sistemi kullanıyorum x,y,z. Bu sistemde yalpalama yoktur ve birçok hex algoritması için yararlıdır. Bu sistemde 0,0,0koordinatları “döndürerek” ve işaretlerini çevirerek altıgeni döndürebilirsiniz : bir yöne ve diğer yöne x,y,zdönüşür . Bu sayfada bir diyagramım var .-y,-z,-x-z,-x,-y

(X / y / z vs X / Y için özür dilerim ama sitemde x / y / z kullanıyorum ve kodunuzda X / Y kullanıyorsunuz, bu nedenle bu cevapta durum önemlidir! xx,yy,zzaşağıdaki değişken adları olarak ayırt etmeyi kolaylaştırmak için deneyin.)

Senin dönüştürün X,Ykoordinatları için x,y,zformatında:

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

Şu veya bu şekilde 60 ° döndürme yapın:

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

x,y,zSırtınızı şuraya dönüştürün X,Y:

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

Örneğin, (X = -2, Y = 1) ile başlayıp 60 ° sağa döndürmek istiyorsanız, şunu dönüştürürsünüz:

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

sonra -2,1,160 ° sağa döndürerek :

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

burada gördüğünüz gibi:

-2,1,1 için onaltılık dönüş örneği

sonra -1,2,-1geri dönüştürün :

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

Böylece (X = -2, Y = 1) 60 ° sağa (X = -2, Y = -1) döndürür.


4

Önce yeni bir numara tanımlayalım. Endişelenme, kolay bir soru.

  • f : f × f = -3

Veya, sadece koymak için: f = √3 x i ile ı olan sanal birim . Bununla, saat yönünde 60 derece döndürme 1/2 × (1 - f ) çarpımı ile aynıdır ve saat yönünün tersine 60 derece döndürme 1/2 × (1 + f ) çarpımı ile aynıdır . Bu garip geliyorsa, karmaşık bir sayıyla çarpmanın 2B düzlemindeki döndürmeyle aynı olduğunu unutmayın. Biz sadece hayali yöndeki karmaşık sayıları biraz "(3 ile) kare köklerle ... ya da tamsayı olmayanlarla uğraşmak zorunda kalmamak için" eziyoruz ".

(A, b) noktasını + b × f olarak da yazabiliriz .

Bu, düzlemdeki herhangi bir noktayı döndürmemizi sağlar; örneğin, (2,0) = 2 + 0 × f noktası (1, -1), sonra (-1, -1), (-2,0), (-1,1), ( 1,1) ve son olarak (2,0) 'a geri dönerek, sadece çarparak.

Tabii ki, bu noktaları koordinatlarımızdan rotasyonları yaptığımız noktalara çevirip sonra tekrar geri çevirmenin bir yoluna ihtiyacımız var. Bunun için başka bir bilgiye ihtiyaç duyulur: Eğer döndürdüğümüz nokta dikey çizginin "sol "una veya" sağına "doğruysa. Basit olması için, solundaysa "wbble" değeri w olan 0 olduğunu (alt iki resminizde dönme merkezi [0,0] gibi) ve sağda ise 1 olduğunu beyan ederiz. onun. Bu, orijinal noktalarımızı üç boyutlu olarak genişletir; ( x , y , w ), normalleştirmeden sonra "w" 0 veya 1'dir. Normalleştirme fonksiyonu:

NORM: ( x , y , w ) -> ( x + kat ( w / 2), y , w mod 2), "mod" işlemi yalnızca pozitif değerler veya sıfır döndürecek şekilde tanımlanmış.

Algoritmamız şimdi aşağıdaki gibi görünüyor:

  1. Noktalarımızı ( a , b , c ) ( a - x , b - y , c - w ) ' yi hesaplayarak dönme merkezine ( x , y , w ) göre konumlarına dönüştürün ve sonucu normalleştirin. Bu, dönme merkezini açıkça (0,0,0) yapar.

  2. Noktalarımızı "doğal" koordinatlarından dönme karmaşık olanlarına dönüştürün: ( a , b , c ) -> (2 × a + c , b ) = 2 × a + c + b × f

  3. Noktalarımızı gerektiği gibi yukarıdaki dönme sayılarından biriyle çarparak döndürün.

  4. Noktaları dönme koordinatlarından "doğal" olanlarına geri dönüştürün: ( r , s ) -> (zemin ( r / 2), s , r mod 2), yukarıda "mod" olarak tanımlanmıştır.

  5. Dönme merkezine ( x , y , z ) ekleyerek ve normalleştirerek noktaları orijinal konumlarına geri dönüştürün .


Tabanlı bizim "tripleks" sayıların basit versiyonu f C ++ şu şekilde görünecektir:

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));
        }
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.