Completely Stumped with Hexagons :(
Ok, I've been trying to do this for far longer than I care to admit, but its obvious even though I CLEPed geometry and trigonometry my understanding of it is pretty pathetic.
I've successfully made hexmaps with the point up, and the point on the side, and drew them in various scales. I've also got pretty darned reliable pixel to hexagon routines for both. BUT, I have no way to really rotate it and do exactly what I want real time :(
Basically, I'm trying to make a hexmap that is actually a portion of a larger map, is scrollable, and can be rotated any angle and scaled any scale.
I will be providing the following information:
W (Total width of a hex)
H (Total height of a hex)
P (Width of the hex part)
A (Angle of rotation for the entire MAP (NOT each individual hex))
S (Scale of the map/hex, .5=half, 2=double)
R (Row of the hex)
C (Column of the hex)
X (X offset of the MAP)
Y (Y offset of the MAP)
And I need it to return the pixel's X and Y location for the upper left hand point of the hexagon square (basically a point in space at the upper left hand portion of the hex, so I can blt stuff to it later).
I also need a function that takes the above information, PLUS the pixel X/Y coordinates and returns the hexagon row and column.
This allows me to have any shape of hexagon and a map that can rotate any angle. I am basically creating a map of a planet with 10km accuracy (roughly 8mb per pixel) where each pixel is a sector of around 10km (1024 pixel square, as each pixel is a 10m "hex"). A texture will be drawn in the background and a hexagonal grid will overlay it (thus it won't look like a crappy hexmap). There will be another file that determines the predominate terrain in each hex, as well as another for altitude (earth would be around 50mb total for this, plus up to 250GB for 65000 unique 10km sectors). Each of these maps will be a bitmap sorta format where a sector is pulled (or up to 4 if your on a corner) and the particular area drawn thats necessary.
I know I'm asking a lot, but I've tried for a LONG time to get this and have never gotten it to the point I could consider it a "production" piece of code. I don't care if its in VB, C, C#, Java, ASM, whatever (ASM would be nice!) but just want it to work. If you know how to do it and just dont wanna help cause I'm basically asking somebody else to write 2 functions for me, I'd be happy to share anything else I have or perhaps even pay (need a new $50 computer book?).
I'm trying to do a generic hexagonal game engine that'll have plugins for a HUGE # of board games out there. But I need the code to be very versatile and modular and allow quick coding of the game engines. I'm going to *try* to do it with the .NET GDI to avoid any 3D dependencies, but DX may have to be used if I can't get the 3 layers plus borders and such drawn quick enough (with maybe 2500 hexes on screen max).
Anyway, thanks for any help you can provide (I've already searched here and all over google with no avail) as I'm pretty darned desparate at this point.
...<--------W------->
................<-P->
^...../``````````\
|..../............\
|.../..............\
|../................\
H..\................/
|...\............../
|....\............/
|.....\__________/
V
Re: Completely Stumped with Hexagons :(
Public Class Form1
Private Sub ShapeMakerForm_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim yellowBrush As New SolidBrush(Color.Yellow)
Dim WidthX = 100.0 'Width
Dim HeightY = 100.0 'Height
Dim LocX = 125.0 'Width
Dim LocY = 125.0 'Height
Dim v As Integer = CInt(WidthX / 2 * Math.Sin(30 * Math.PI / 180))
Dim point1 As New Point((WidthX \ 2) + LocX, 0 + LocY)
Dim point2 As New Point(WidthX + LocX, v + LocY)
Dim point3 As New Point(WidthX + LocX, (HeightY - v) + LocY)
Dim point4 As New Point((WidthX \ 2) + LocX, HeightY + LocY)
Dim point5 As New Point(0 + LocX, (HeightY - v) + LocY)
Dim point6 As New Point(0 + LocX, v + LocY)
Dim curvePoints As Point() = {point1, point2, point3, point4, point5, point6}
e.Graphics.FillPolygon(yellowBrush, curvePoints)
End Sub
End Class
1 Attachment(s)
Re: Completely Stumped with Hexagons :(
TonyMan's code is very inadequate. At most it appears to draw a single hexagon, though I'd have to inspect it more to say that for sure. Anywho, the first function you want is in the attached VB6 project. The code quality isn't great, but it's easy to translate and improve upon. I'm pasting it in this post as well in case you don't have a VB6 IDE. In that case it should still be fairly self-explanatory. If you have questions about the math or trig please ask.
Code:
Dim OldAngle
Private Sub PrintDot(W, H, P, A, S, R, C, X, Y)
'1. Find unrotated, unscaled hexagon center
Cx = W / 2 + C * (W - P)
Cy = H / 2 + R * H
If C Mod 2 = 1 Then
Cy = Cy + H / 2
End If
'2. Move to upper left corner of hexagon from the center
Cx = Cx - W / 2
Cy = Cy - H / 2
'3. Calculate the point about which rotation and scaling takes place
' This could be passed in place of the X and Y variables, though scrolling
' then becomes harder than just adding to X or Y.
nX = (X) * Cos(-A) - (Y) * Sin(-A)
nY = (X) * Sin(-A) + (Y) * Cos(-A)
'4. Move the origin to rotate about the above center of rotation and scaling
Cx = Cx - nX
Cy = Cy - nY
'4. Apply global scaling
Cx = Cx * S
Cy = Cy * S
'5. Apply global rotation
' 2D rotation matrix:
' [cos A -sin A][Cx] = [Cx * cos A - Cy * sin A]
' [sin A cos A][Cy] [Cx * sin A + Cy * cos A]
Tx = Cx * Cos(A) - Cy * Sin(A)
Ty = Cx * Sin(A) + Cy * Cos(A)
Cx = Tx
Cy = Ty
'6. Center the point on the middle of the screen instead of the upper left corner
Cx = Cx + Me.Width / 2
Cy = Cy + Me.Height / 2
'(Cx, Cy) is the value you want. Do something with it.
Me.Circle (Cx, Cy), 60, vbRed
End Sub
Private Sub RedrawGrid()
'Random example
Me.Cls
For R = 0 To 10
For C = 0 To 10
PrintDot 700, 500, 150, sldAngle.Value * 3.14159 / 180, sldScale.Value / 10, R, C, sldOffsetX.Value, sldOffsetY.Value
Next C
Next R
End Sub
Private Sub sldAngle_Change()
'Modify X and Y so that the center of rotation is unchanged.
'Need to keep around the previous angle so that we can (implicitly) compute
' the center of rotation and scaling.
NewAngle = sldAngle.Value * 3.14159 / 180
X = sldOffsetX.Value
Y = sldOffsetY.Value
Tx = X * Cos(NewAngle - OldAngle) - Y * Sin(NewAngle - OldAngle)
Ty = X * Sin(NewAngle - OldAngle) + Y * Cos(NewAngle - OldAngle)
sldOffsetX.Value = Tx
sldOffsetY.Value = Ty
RedrawGrid
OldAngle = sldAngle.Value * 3.14159 / 180
End Sub
Private Sub sldOffsetX_Change()
RedrawGrid
End Sub
Private Sub sldOffsetY_Change()
RedrawGrid
End Sub
Private Sub sldScale_Change()
RedrawGrid
End Sub
I haven't done the second routine. Ideally you would be able to do it by inverting the logic above, but that could be difficult. If you need help with that I can write something.