Yeah, it's true, you do have a way with words, Richard.
My own code was probably rather un-self-explanatory, so I'm going to post another version, with a hexagon-drawing routine, and some more commenty goodness.
Our methods are completely different - Richard's maps to the hexagon coordinate system and finds the closest match, which, happily enough, gives exact hexagons - if you had a set of soap bubbles, and arranged them tightly together in that pattern, you would indeed see that behaviour with the edges.
Code: Select all
declare sub drawhex(byval hx as integer, byval hy as integer)
declare sub findhexpos(byref hx as integer, byref hy as integer, _
byval x as integer, byval y as integer)
declare sub findhexdxdy(byref hdx as integer, byref hdy as integer, _
byval x as integer, byval y as integer)
function modp(byval a as integer, byval b as integer) as integer
var c = a mod b: if c < 0 then: c += abs(b): end if: return c
end function
'' Set the screen size
const WID = 320, HEI = 200
'' Set the dimensions of the hexagon (max width, min width, height)
'' it doesn't need to be regular, but if it is, you can just change HEXSIDE
const HEXSIDE = 16
const HEXWIDMIN = HEXSIDE, HEXWIDMAX = 2 * HEXSIDE
const HEXHEI = 2 * cint(HEXSIDE * sqr(3) / 2)
const DY = HEXHEI, DX = (HEXWIDMAX - HEXWIDMIN)
const TILEWID = HEXWIDMIN + HEXWIDMAX, TILEHEI = HEXHEI
screenres WID, HEI, 8, 2
dim as integer x, y, mx, my, hx, hy
'' Draw hexagon map on screen
for y = 0 to HEI - 1
screenlock
for x = 0 to WID - 1
findhexpos( hx, hy, x, y )
pset (x, y), (hx * 2 + hy * 6) mod 24 + 32
next x
screenunlock
sleep 1
if len(inkey) then end
next y
screencopy 0, 1
do until len(inkey)
getmouse mx, my
'' Find current hexagon and draw it
findhexpos( hx, hy, mx, my )
screenlock
screencopy 1, 0
draw string (0, 0), (hx & ", " & hy)
drawhex( hx, hy )
screenunlock
sleep 1
loop
'''''''''''''''''''''''''
sub drawhex(byval hx as integer, byval hy as integer)
'' Draws a hexagon, given the hexagon position
dim as integer x, y '' Centre cooridnates
x = (hx * (HEXWIDMIN + HEXWIDMAX)) \ 2
y = hy * HEXHEI + (hx and 1) * HEXHEI \ 2
'pset(x, y)
''Draw lines to form a hexagon
line (x - HEXWIDMAX \ 2, y) - (x - HEXWIDMIN \ 2, y - HEXHEI \ 2)
line - (x + HEXWIDMIN \ 2, y - HEXHEI \ 2)
line - (x + HEXWIDMAX \ 2, y)
line - (x + HEXWIDMIN \ 2, y + HEXHEI \ 2)
line - (x - HEXWIDMIN \ 2, y + HEXHEI \ 2)
line - (x - HEXWIDMAX \ 2, y)
end sub
sub findhexpos(byref hx as integer, byref hy as integer, _
byval x as integer, byval y as integer)
'' Find the matching hexagon position(finds the right tile (see below), then
'' uses hexdxdy to find the exact hexagon, given the position in the tile)
dim as integer hdx, hdy
dim as integer tx = modp(x, TILEWID), ty = modp(y, TILEHEI)
dim as integer x2 = x - tx, y2 = y - ty
'' Find the right tile (each tile has the
'' width of two hexagons and the height of one)
hx = (x2 * 2) \ TILEWID
hy = y2 \ TILEHEI
''adjust to find the correct position in the tile
findhexdxdy( hdx, hdy, tx, ty )
hx += hdx
hy += hdy
end sub
sub findhexdxdy(byref hdx as integer, byref hdy as integer, _
byval tx as integer, byval ty as integer)
'' The screen is split into tiles like this:
'' ^
'' |
'' ''''''----'''''
'' ' / \ '
'' --- ---
'' ' \ / '
'' ''''''----'''''-->
if tx < 0 or tx >= TILEWID then tx = modp(tx, TILEWID)
if ty < 0 or ty >= TILEHEI then ty = modp(ty, TILEHEI)
'' This is symmetrical, so we only deal with one quadrant:
'' ^
'' |
'' '--''''''
'' ' \ '
'' ----''''''--'--->
'' |
dim as integer x = tx - TILEWID \ 2, xa = abs(x)
dim as integer y = ty - TILEHEI \ 2, ya = abs(y)
'' To find out whether it's the center hexagon or a corner hexagon,
'' we just have to check what side of the line it's on
'' ^
'' | \
'' '''\''''
'' ' \ '
'' -----+'''-\-'->
'' | \
if ya * DX >= (xa - HEXWIDMAX \ 2) * -DY then
'' corner hexagon
hdx = 2 and (x > 0)
hdy = 1 and (y > 0)
else
'' centre hexagon
hdx = 1
hdy = 0
end if
end sub
My method uses rectagonal tiles, each tile overlapping five different hexagons (four at the corners, plus one in the centre). The tile is easy to calculate, and finding which hexagon it belongs to within the tile isn't too bad.
Because it's symmetrical, you just have to work out which quadrant it's in, then you only have to work out what side of the line it's on to find out whether it's in the centre hexagon, or the corresponding corner hexagon.
Overall, I think my method might be more complicated. On the plus side, though, it does support non-regular hexagons.
Hopefully, you can understand both methods, and learn different things from each.