六角形グリッド上で六角形タイルの構造を回転させるにはどうすればよいですか?


10

私の2Dアイソメトリックゲームでは、六角形のグリッドマップを使用しています。下の画像を参照して、ピンクの六角形を中心に水色の六角形構造を60度回転するにはどうすればよいですか?

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

編集:

主なヘクスは(0,0)です。他のヘクスは子供であり、それらの数は固定されています。1つの位置(この場合はその右)のみを定義し、必要に応じて他の方向(左下、右下、右上、左上、左)を計算します。他のヘクスは、Package.Add(-1,0)、Package.Add(-2,0)などのように定義されています。

ここに画像の説明を入力してください

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

このコードNumberではメインのヘクスでPointあり、回転させたいヘクスですが、機能しません。

ここに画像の説明を入力してください


1
正確には何が問題ですか?それを実装する方法またはいくつかの悪い結果?
Ali1S232 2011

ピンクの六角形の6つのエッジに回転をスナップしていますか、それとも回転角度は任意ですか?また、右側の構造のピンクの六角形のうち、回転しているものはどれですか。
Keeblebrox、2011

個々のタイルを回転させる方が簡単かもしれませんが、これは既にそこにあるタイルに何が起こるかという疑問につながります。これは、私が応答を試みる前に一般的に知っておくとよいでしょう。
James

申し訳ありません。画像の左側について話しています。私は悪い結果を出しました、いくつかのヘクスは間違った場所にあります。ピンクのヘクスがメインで、明るい青のヘクスが子です。メインの16進数が(5,5)であるとすると、子の16進数(-1,0)を定義して、ピンクの左側に子を配置します。この子ヘクスを60度回転させる方法を知りたいです(ピンクの左上になります)。より簡単:私は私の戦略ゲームでビルドシステムに取り組んでいます。多くの場合、戦略ゲームでは、配置する前に建物を回転させることができます。構築する必要のあるヘクスを計算します。
ruzsoo

選択したヘクスのセットは毎回まったく同じ数でなければなりませんか?つまり、たとえば、ピンクのヘクスの両側にあるヘクスに3つのオブジェクトを具体的に配置していますか?または、特定の長さの線を描き、どれだけのヘクスがそれと交差するかを、それがいくつになるかに関係なく決定したいだけですか?固定した数のヘクス、または任意の数でこれを実行しますか?
Tim Holt、

回答:


11

以下のようマーティンSojkaの別の座標系に変換する場合の注意事項、回転が回転を行い、単純であり、その後、戻って変換します。

ラベルが付けられたマーティンとは異なる座標系を使用していx,y,zます。このシステムにはぐらつきはなく、多くの16進アルゴリズムに役立ちます。このシステムでは、あなたの周りの六角を回転させることができます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,160度右に回転します:

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

あなたがここに見るように:

-2,1,1の16進回転の例

次に元に-1,2,-1戻す:

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

したがって、(X = -2、Y = 1)は(X = -2、Y = -1)に右に60度回転します。


4

まず、新しい番号を定義しましょう。心配はいりません。簡単です。

  • ff × 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)に戻ります。単純にそれを乗算します。

もちろん、これらの点を座標から回転を実行する座標に変換し、その後再び戻す方法が必要です。これには、もう1つの情報が必要です。回転を行う点が垂直線の「左」または「右」である場合。わかりやすくするため、左側にある場合(下の2つの画像の回転の中心[0,0]のように)は「ウォブル」値wは0、右側にある場合は1と宣言します。それの。これにより、元のポイントが3次元に拡張されます。(xyw)、正規化後の "w"は0または1です。正規化関数は次のとおりです。

NORM:(xyw)->(x + floor(w / 2)、yw mod 2)。正の値またはゼロのみを返すように「mod」演算が定義されています。

アルゴリズムは次のようになります。

  1. a - xb - yc - w)を計算し、結果を正規化することにより、ポイント(abc)を回転中心(xyw)を基準にした位置に変換します。これは明らかに回転中心を(0,0,0)に置きます。

  2. ポイントを「ネイティブ」座標から回転複素座標に変換します:(abc)->(2× a + cb)= 2× a + c + b × f

  3. 必要に応じて、上記の回転数のいずれかを乗算してポイントを回転させます。

  4. 上記のように定義された「mod」を使用して、回転座標から「ネイティブ」なものにポイントをra変換します:(rs)->(floor(r / 2)、sr mod 2)。

  5. ポイントを回転中心(xyz)に追加して正規化することにより、ポイントを元の位置に再変換します。


C ++での「トリプレックス」に基づくfの単純なバージョンは、次のようになります。

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));
        }
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.