如何在六角形网格上旋转六角形瓷砖的结构?


10

我的2D等距游戏使用六角形网格图。参考下图,如何将浅蓝色六边形结构围绕粉红色六边形旋转60度?

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

编辑:

主十六进制是(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是主要的十六进制,Point也是我要旋转的十六进制,但是它不起作用:

在此处输入图片说明


1
到底是什么问题?如何执行该结果或一些不良结果?
Ali1S232 2011年

您是将旋转捕捉到粉红色六边形的6个边缘,还是旋转角度是任意的?另外,您在旋转右侧结构中的哪些粉红色六边形?
Keeblebrox 2011年

旋转单个磁贴可能会更容易,但这会引发一个问题,即已经存在的磁贴发生了什么变化,因此在我尝试给出响应之前,通常最好先知道这一点。
詹姆斯,

为失误抱歉。我说的是图像的左侧。我遇到了不好的结果,曾经有一些错误的地方。粉色的六角形为主要色,明亮的蓝色六角形为孩子色。假设主十六进制是(5,5),那么我定义了一个子十六进制(-1,0),因此该子在粉红色的左侧,依此类推。我想知道如何将此儿童六角形旋转60度(然后它将位于粉红色的左上方)。更容易:我正在策略游戏中构建系统。通常,在策略游戏中,您可以在放置建筑物之前旋转建筑物。我将计算需要构建的十六进制。
ruzsoo 2011年

每次选择的十六进制数是否必须完全相同?也就是说,例如您是否在粉红色六角形的任一侧的六角形上专门放置了3个对象?或者,您只是想画一条给定长度的线,并确定哪条六角形最好与之相交,而不管其长度是多少?您要使用固定数量的十六进制还是任意数量的十六进制?
蒂姆·霍尔特

Answers:


11

正如Martin Sojka所指出的那样,如果转换为其他坐标系,然后执行旋转,然后再转换回去,则旋转会更简单。

我使用了与Martin不同的坐标系,标记为x,y,z。该系统没有任何摆动,对于许多十六进制算法很有用。在此系统中,您可以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的十六进制旋转示例

然后转换-1,2,-1回:

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

因此(X = -2,Y = 1)向右旋转60°到(X = -2,Y = -1)。


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)。

当然,我们需要一种方法将这些点从坐标转换为进行旋转的点,然后再次返回。为此,还需要一点信息:如果我们旋转的点是垂直线的“左”或“右”。为简单起见,我们声明“摆动”值w如果在其左侧(如底部两张图片的旋转中心[0,0]),则为0;如果在右侧,则为1。它的。这将我们的原始点扩展为三维;(xyw),归一化后的“ w”为0或1。归一化函数为:

规范:(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. 将点从旋转坐标转换为它们的“本机”坐标:(rs)->(floor(r / 2),sr mod 2),其中“ mod”的定义如上所述。

  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));
        }
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.