2014-03-04 49 views
3

我正在嘗試創建基於網格的遊戲。到目前爲止,我有一個六角形的基於區塊的網格,以協調方案,如下圖所示:在六角形網格中捕捉到最近的六角形中心

col 0 
| col 1 
| | col 2 
| | | 
__ | __ __ __ __ 
/00\__/02\__/04\__/06\__/08\__ 
\__/01\__/03\__/05\__/07\__/09\--- row 0 
/10\__/12\__/14\__/16\__/18\__/ 
\__/11\__/13\__/15\__/17\__/19\--- row 1 
/20\__/22\__/24\__/26\__/28\__/ 
\__/21\__/23\__/25\__/27\__/29\--- row 2 
/30\__/32\__/34\__/36\__/38\__/ 
\__/ \__/ \__/ \__/ \__/ --- row 3 

,看起來像這樣在現實生活中只是隨機顏色的每一個六邊形:

什麼我正在努力弄清楚的是,當用戶點擊一個六邊形時,我如何確定他們點擊了哪個六邊形?

到目前爲止,我已經嘗試過的代碼如下:

private: System::Void MyForm_MouseDown(System::Object^ sender, 
    System::Windows::Forms::MouseEventArgs^ e) { 

    int CloseI=0,CloseJ=0; 
    CloseJ = FindNearesetX(e->X); 
    CloseI = FindNearesetY(e->Y); 
    //Grid[down(y)][along(x)] 
    P1.X = Grid[CloseI][CloseJ].GetX(); 
    P1.Y = Grid[CloseI][CloseJ].GetY(); 
} // END MOUSE DOWN EVENT 

int FindNearesetX(int ActualX){ 
    int ClosestJPos; 
    ClosestJPos = ((ActualX-Grid[0][0].GetX())/(1.5*HexSideLength)); 
    return ClosestJPos; 
}//END FIND NEAREST X 

int FindNearesetY(int ActualY){ 
    int ClosestIPos; 
    ClosestIPos = ((ActualY-Grid[0][0].getY())/(HexHeight)); 
    return ClosestIPos; 
}//END FIND NEAREST Y 

private: System::Void MyForm_MouseMove(System::Object^ sender, 
    System::Windows::Forms::MouseEventArgs^ e) { 
    this->Invalidate(); 

    P2.X = e->X; 
    P2.Y = e->Y; 
} // END MOUSE MOVE EVENT  

然而,這並沒有工作,我怎麼想,這是因爲當用戶點擊一個六邊形的中心點左側它卡到他們點擊的那個左邊的六邊形,並且如果他們點擊所有奇數列上的中心點上面,它就會對齊他們點擊的那個上面的六邊形。

我一直堅持這個爲期2天,真的想弄明白。 謝謝

+1

[六角形網格,你如何找到一個點是在六邊形?(可能的重複http://stackoverflow.com/questions/7705228/hexagonal-grids-how-do-you-find-其中-hexagon-a-point-is-in) – Troyseph

+1

我發佈這個問題已經2年了,但我確實記得看到那篇文章,我相信它沒有解決我的問題(儘管我確定它有幫助),但是,然而,對於我來說,記得它爲什麼沒有回答我的問題的具體內容太長了。奇怪的是,在這麼長時間後看到這篇文章的活動! aha – JabbaWook

回答

4

點擊的點總是最接近發生點擊的六邊形的中心,除非點恰好在兩個六邊形之間,在這種情況下它將與兩個中心等距。兩點之間距離的等式是SQRT((x1-x2)^ 2 +(y1-y2)^ 2)。

您不必測試每個六邊形的距離。通過創建x/y閾值,您可以將測試限制在附近的六邊形。例如,如果六邊形的寬度爲10,並且點位於(51,73)處,則不必測試x座標爲< 40或> 70的六邊形。

+3

此外,由於您只是想找到最接近的六邊形,您應該可以省略平方根檢查,因爲實際長度不會用於任何事情。如果您正在檢查大量多邊形,這可能會爲您節省一些週期。泰勒基於寬度的選擇點也是一個非常快速的優化,您應該考慮實施,並且絕對應該用作預測試。 –

+1

對,我只是爲了完整而包括sqrt。在實際的實現中,您不需要執行sqrt,只需要差異的平方和,即點之間的差異。 –

0

實際上,由於六邊形(所有邊都是相同的長度),這就像循環瀏覽六邊形瓷磚列表一樣簡單,並找出哪個瓷磚的中心最接近鼠標點擊。

C++僞代碼:

//assuming "map" is an array of "Tile" pointers 

Tile *closest = nullptr; 
int fromClosestCenterToClick = INT_MAX; 

for (int row = 0; row < map.numRows(); row++) 
{ 
    for (int col = 0; col < map.numCols(); col++) 
    { 
     int distance = std::sqrt(std::pow(map[row][column]->center.x - mouseClickX, 2) + std::pow(map[row][column]->center.y - mouseClickY, 2) < fromClosestCenterToClick); 
     if (distance < fromClosestCenterToClick) 
     { 
     closest = map[row][column]; 
     fromClosestCenterToClick = distance; 
     } 
    } 
} 
//closest now holds the correct tile 
+0

嘎,你複製我的答案 –

+0

@TylerDurden xD我可能開始打字,但是。具有諷刺意味的是,你的更完整。閾值是一個好主意。 +1 – Proxy

3

人們應該能夠找到與O(1)複雜最接近六邊形:

odd  even odd even 
0 +----+ | | +----+ | 
    | 00 |\ | | | 02 | | 
    | | \+----+ | | + 
    | | /| 01 | | | | 
H +----+/ | | +----+ | 
    | 10 |\ | | | 12 | | 
    | | \+----+ | | + 
    | | /| 11 | | | | 
2H +----+/ | | +----+ | 
    0....X..W.......2W......3W 

拐角 '+' 也是六邊形的角上。 'x'DIV 2 * W和y DIV H確定'x'mod W時的正確平方。當W < = x mod 2W < = W + X時,該點位於偶數列上。上的奇數列中,行號爲ý DIV ħ,在偶數列,它是(ý + ħ/2)DIV ħ

用鋸齒形圖案很難說明的灰色區域需要求解兩個線性方程(或點積)來確定點落在對角線的哪一側。無論如何,最多有兩名候選人可供選擇。

0

事實上,這可以在數學上很容易地完成,而不訴諸於通過大量潛在值迭代的刺激性,尺度限制方法。我與以下網站的優秀信息勾結,提出了以下代碼。祕訣是想象你的六角網格實際上是一個三維立方體的平面。

http://www.redblobgames.com/grids/hexagons/

N.B. SS2DCoordinates和SS3DCOordinates是簡單的結構,其中有兩個或三個整數變量,分別表示2D和3D網格上的座標(x/y代表2D,x/y/z代表3D)還要注意,我的六角形網格始於1/1而不是0/0。

SS2DCoordinates coordinatesForHexAtPoint(float a, float b) 
{ 
    // Get basic hex information - pseudocode 
    float radius = <radius of one hexagon> 

    // Estimate the most likely hex and round to nearest values 
    float x = 2.0/3.0*a/radius; 
    float z = (1.0/3.0*sqrt(3.0)*b-1.0/3.0*a)/radius; 
    float y = -x-z; 

    int ix = (int)round((floor(x-y)-floor(z-x))/3.0); 
    int iy = (int)round((floor(y-z)-floor(x-y))/3.0); 
    int iz = (int)round((floor(z-x)-floor(y-z))/3.0); 

    // Adjust to flat coordinates on the offset numbering system 
    SS2DCoordinates corrected = hexToFlatCoordinates(SS3DCoordinatesMake(ix, iy, iz)); 
    corrected.x --; 
    return axialToOffsetCoordinates(corrected); 
} 


SS2DCoordinates hexToFlatCoordinates(SS3DCoordinates hex) 
{ 
    SS2DCoordinates coordinates; 
    coordinates.x = hex.x; 
    coordinates.y = hex.z; 
    return coordinates; 
} 


SS2DCoordinates axialToOffsetCoordinates(SS2DCoordinates axial) 
{ 
    SS2DCoordinates offset; 
    offset.x = axial.x; 
    offset.y = axial.y + (NSInteger)ceilf((float)axial.x/2.0); 
    return offset; 
}