ฉันจะหมุนโครงสร้างของแผ่นกระเบื้องหกเหลี่ยมบนตารางหกเหลี่ยมได้อย่างไร


10

เกมสามมิติแบบสามมิติของฉันใช้แผนที่กริดหกเหลี่ยม จากภาพด้านล่างฉันจะหมุนโครงสร้างหกเหลี่ยมสีฟ้าอ่อนได้ 60 องศารอบ ๆ รูปหกเหลี่ยมสีชมพูได้อย่างไร

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

แก้ไข:

เลขฐานสิบหกหลักคือ (0,0) Hexes อื่น ๆ คือ children การนับจะคงที่ ฉันจะกำหนดตำแหน่งเดียวเท่านั้น (ในกรณีนี้คือด้านขวา) และคำนวณทิศทางอื่น ๆ หากจำเป็น (ซ้ายล่าง, ขวา - botom, ขวาบน, ซ้ายบนและซ้าย) เลขฐานสิบหกอื่น ๆ ที่มีการกำหนดเช่น: 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

คุณหักมุมการหมุนไปที่ขอบ 6 ของรูปหกเหลี่ยมสีชมพูหรือมุมการหมุนโดยพลการหรือไม่? รูปหกเหลี่ยมสีชมพูรูปใดในโครงสร้างด้านขวาที่คุณหมุนไปรอบ ๆ
Keeblebrox

มันอาจจะง่ายกว่าที่จะหมุนไพ่แต่ละใบ แต่สิ่งนี้นำไปสู่คำถามว่าเกิดอะไรขึ้นกับกระเบื้องที่มีอยู่แล้วและจะเป็นการดีที่จะรู้โดยทั่วไปก่อนที่ฉันจะสามารถลองตอบกลับได้
James

ขออภัยด้วยความผิดพลาด ฉันกำลังพูดถึงส่วนที่เหลือของภาพ ฉันมีผลลัพธ์ที่ไม่ดีเคยมีบาง hexes อยู่ในสถานที่ที่ไม่ถูกต้อง ฐานสิบหกสีชมพูเป็นหลักและหกเหลี่ยมสีฟ้าสดใสเป็นเด็ก สมมติว่าเลขฐานสิบหกหลักคือ (5,5) จากนั้นฉันจะกำหนดค่าฐานสิบหกของเด็ก (-1,0) ดังนั้นเด็กจะอยู่ทางด้านซ้ายของสีชมพูและอื่น ๆ ฉันต้องการรู้วิธีหมุน hex เด็กนี้ 60 องศา (แล้วมันจะอยู่ที่ด้านซ้ายของสีชมพู) ง่ายขึ้น: ฉันกำลังทำงานเกี่ยวกับการสร้างระบบในเกมกลยุทธ์ของฉัน บ่อยครั้งในเกมวางแผนคุณสามารถหมุนสิ่งปลูกสร้างก่อนที่จะวาง ฉันจะคำนวณเลขฐานสิบหกที่ต้องสร้าง
ruzsoo

ชุดของเลขฐานสิบหกที่เลือกจะต้องมีค่าเท่ากันทุกครั้งหรือไม่ คุณกำลังวางวัตถุ 3 รายการบน hexes ที่ด้านใดด้านหนึ่งของ hex สีชมพูหรือไม่ หรือคุณแค่อยากวาดเส้นที่มีความยาวที่กำหนดและตัดสินใจว่า hexes ใดที่ตัดกันได้ดีที่สุดโดยไม่คำนึงว่าจะมีกี่อัน? คุณต้องการที่จะทำเช่นนี้ด้วยจำนวน hexes คงที่หรือจำนวนโดยพลการ?
ทิมโฮลท์

คำตอบ:


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

ตามที่คุณเห็นที่นี่:

ตัวอย่างการหมุน Hex สำหรับ -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

ก่อนอื่นเรามากำหนดหมายเลขใหม่ ไม่ต้องกังวลมันเป็นเรื่องง่าย

  • f : f × f = -3

หรือจะนำมันก็: f = √3× ฉันด้วยฉันเป็นหน่วยจินตภาพ ด้วยเหตุนี้การหมุน 60 องศาตามเข็มนาฬิกาเป็นเช่นเดียวกับการคูณโดย1/2 × (1 - )และการหมุน 60 องศาทวนเข็มนาฬิกาเช่นเดียวกับการคูณโดย1/2 × (1 + F ) หากฟังดูแปลก ๆ โปรดจำไว้ว่าการคูณด้วยจำนวนเชิงซ้อนนั้นเหมือนกับการหมุนในระนาบ 2D เราแค่ "สควอช" จำนวนเชิงซ้อนในทิศทางจินตภาพเล็กน้อย (โดย√3) เพื่อไม่ต้องจัดการกับสแควร์รูท ... หรือไม่ใช่จำนวนเต็มสำหรับเรื่องนั้น

นอกจากนี้เรายังสามารถเขียนจุด (A, B) เป็น A + B × ฉ

สิ่งนี้ทำให้เราหมุนจุดใดก็ได้ในระนาบ ตัวอย่างเช่นจุด (2,0) = 2 + 0 × fหมุนไปที่ (1, -1) จากนั้นถึง (-1, -1), (-2,0), (-1,1), ( 1,1) และในที่สุดก็กลับมาที่ (2,0) เพียงแค่คูณมัน

แน่นอนว่าเราต้องการวิธีในการแปลคะแนนเหล่านั้นจากพิกัดของเราเป็นผู้ที่เราทำการหมุนเวียนแล้วกลับมาอีกครั้ง สำหรับสิ่งนี้จำเป็นต้องใช้ข้อมูลอีกเล็กน้อย: ถ้าจุดที่เราหมุนรอบนั้นคือ "ซ้าย" หรือ "ขวา" ของเส้นแนวตั้ง สำหรับความเรียบง่ายที่เราประกาศว่าจะมี "โยกเยก" ค่าW 0 ถ้ามันไปทางซ้ายของมัน (เหมือนศูนย์กลางของการหมุน [0,0] ในด้านล่างสองภาพของคุณ) และ 1 ถ้ามันไปทางขวา ของมัน สิ่งนี้ขยายคะแนนดั้งเดิมของเราเป็นสามมิติ ( x , y , w ) โดยที่ "w" เป็น 0 หรือ 1 หลังจากการทำให้เป็นมาตรฐาน ฟังก์ชันการทำให้เป็นมาตรฐานคือ:

NORM: ( x , y , w ) -> ( x + floor ( w / 2), y , w mod 2) โดยมีการดำเนินการ "mod" ที่กำหนดไว้ซึ่งจะส่งกลับเฉพาะค่าบวกหรือศูนย์

อัลกอริทึมของเราตอนนี้มีลักษณะดังนี้:

  1. เปลี่ยนคะแนนของเรา ( a , b , c ) เป็นตำแหน่งที่สัมพันธ์กับศูนย์การหมุน ( x , y , w ) โดยการคำนวณ ( a - x , b - y , c - w ) จากนั้นปรับผลลัพธ์ให้เป็นมาตรฐาน นี่ทำให้ศูนย์กลางการหมุนที่ (0,0,0) ชัดเจน

  2. เปลี่ยนคะแนนของเราจากพิกัด "ดั้งเดิม" ของพวกเขาไปเป็นค่าที่ซับซ้อนในการหมุน: ( a , b , c ) -> (2 × a + c , b ) = 2 × a + c + b × f

  3. หมุนจุดของเราด้วยการคูณพวกมันด้วยหนึ่งในจำนวนการหมุนด้านบนตามต้องการ

  4. Ra- เปลี่ยนจุดกลับจากพิกัดการหมุนเป็นคน "ดั้งเดิม" ของพวกเขา: ( r , s ) -> (พื้น ( r / 2), s , r mod 2) โดยมี "mod" กำหนดไว้ข้างต้น

  5. แปลงคะแนนกลับไปที่ตำแหน่งเดิมโดยเพิ่มเข้าไปในศูนย์การหมุน ( x , y , z ) และการทำให้เป็นมาตรฐาน


ตัวเลขแบบง่าย ๆ ของเรา "สามเท่า" ที่ใช้ตัวเลขfใน C ++ จะเป็นดังนี้:

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.