육각형 격자에서 육각형 타일의 구조를 어떻게 회전합니까?


10

내 2D 아이소 메트릭 게임은 6 각형 그리드 맵을 사용합니다. 아래 이미지를 참조하여 연한 파란색 육각형 구조를 분홍색 육각형 주위에서 60도 회전시키는 방법은 무엇입니까?

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

편집하다:

메인 16 진수는 (0,0)입니다. 다른 육각형은 어린이이며 그 수는 고정되어 있습니다. 하나의 위치 (이 경우 오른쪽) 만 정의하고 필요한 경우 다른 방향 (왼쪽 하단, 오른쪽 하단, 오른쪽 상단, 왼쪽 상단 및 왼쪽)을 계산합니다. 다른 육각형은 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에서 주요 16 진수이며 Point회전하려는 16 진수이지만 작동하지 않습니다.

여기에 이미지 설명을 입력하십시오


1
정확히 무엇이 문제입니까? 그 또는 일부 나쁜 결과를 구현하는 방법?
Ali1S232

분홍색 육각형의 6 개의 모서리에 회전을 스냅하거나 회전 각도가 임의입니까? 또한 오른쪽 구조의 분홍색 육각형 중 어느 것이 회전합니까?
Keeblebrox

개별 타일을 회전하는 것이 더 쉬울 수도 있지만 이미 존재하는 타일에 어떤 일이 발생하는지에 대한 질문으로 이어 지므로 응답을 시도하기 전에 일반적으로 알아야합니다.
James

실수해서 죄송합니다. 이미지의 왼쪽 부분에 대해 이야기하고 있습니다. 나는 나쁜 결과를 얻었습니다. 일부 육각형은 잘못된 장소에 있습니다. 분홍색 육각형은 주색이고 밝은 파란색 육각형은 자식입니다. 메인 16 진수가 (5,5)라고 가정하고 자식 16 진수 (-1,0)를 정의하여 자식이 분홍색의 왼쪽에 있도록하십시오. 이 아이 16 진수를 60도 회전시키는 방법을 알고 싶습니다 (분홍색의 왼쪽 상단에 있음). 더 쉬워요 : 전략 게임에서 빌드 시스템을 만들고 있습니다. 전략 게임에서는 종종 배치하기 전에 건물을 회전시킬 수 있습니다. 빌드해야하는 육각형을 계산하겠습니다.
ruzsoo

선택한 육각형 세트는 매번 정확히 같은 개수 여야합니까? 즉, 예를 들어 분홍색 육각의 양쪽에있는 육각형에 3 개의 물체를 구체적으로 배치합니까? 또는 주어진 길이의 선을 그리고 어느 육각형이 될 것인지에 관계없이 어떤 육각형이 그것을 가로 지르는 것을 결정하고 싶습니까? 고정 된 수의 헥스 또는 임의의 수로이 작업을 수행 하시겠습니까?
Tim Holt

답변:


11

Martin Sojka가 지적한 것처럼 다른 좌표계로 변환하고 회전을 수행 한 다음 다시 변환하면 회전이 더 간단합니다.

나는 Martin과 다른 좌표계를 사용합니다 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,1하여 60 ° 오른쪽으로 회전합니다 .

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)은 60 °를 (X = -2, Y = -1)로 오른쪽으로 회전시킵니다.


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)으로 돌아갑니다.

물론 좌표에서 회전을 한 지점으로 해당 지점을 변환 한 다음 다시 되돌릴 수있는 방법이 필요합니다. 이를 위해 또 다른 정보가 필요합니다. 회전하는 지점이 세로선의 "왼쪽"또는 "오른쪽"입니다. 간단히 하기 위해 왼쪽에있는 경우 (아래 두 그림의 회전 중심 [0,0]과 같이) 0이고 오른쪽에 있으면 1 인 "흔들림"값 w 가 0 임을 선언합니다 . 그것의. 이것은 원래의 점을 3 차원으로 확장합니다. 정규화 후 "w"는 0 또는 1입니다 ( x , y , w ). 정규화 기능은 다음과 같습니다.

NORM : ( x , y , w )-> ( x + floor ( w / 2), y , w mod 2). "mod"연산을 정의하면 양수 값 또는 0 만 반환합니다.

우리 알고리즘은 다음과 같습니다.

  1. ( a - x , b - y , c - w ) 를 계산 하여 결과를 정규화하여 점 ( a , b , c )을 회전 중심 ( x , y , w )을 기준으로 해당 위치로 변환합니다 . 이것은 회전 중심을 (0,0,0)에 분명히 둡니다.

  2. 점을 "기본"좌표에서 회전 복합 좌표로 변환합니다 : ( a , b , c )-> (2 × a + c , b ) = 2 × a + c + b × f

  3. 필요에 따라 위의 회전 숫자 중 하나를 곱하여 점을 회전시킵니다.

  4. 회전 좌표에서 "기본"좌표로 점을 다시 변환합니다. ( r , s )-> (floor ( r / 2), s , r mod 2), "mod"는 위와 같이 정의됩니다.

  5. 회전 중심 ( x , y , z )에 추가하고 정규화 하여 점을 원래 위치로 다시 변형합니다 .


C ++에서 f 를 기반으로하는 "triplex"숫자의 간단한 버전 은 다음과 같습니다.

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.