--[[ AXIAL/CUBE COORDINATE SYSTEM FOR AMULET/LUA]] --[[ all hexes in functions are assumed to be amulet vectors. in amulet, vector arithmetic works already with [ + - * / ] things like equality and distance are implemented here. some algorithms use axial coordinates for hexes: vec2(s, t) others use cube coordinates: vec3(s, t, z) where s + t + z = 0 this is for simplicity - many algorithms don't care about the third coordinate, and if they do, the missing coordinate can be calculated from the other two. -- note on orientation: because of the way amulet draws hexagons, it's much easier to assume the user wants to use the flat map. rotation after the fact to achieve other orienations is probably possible, but might have some aliasing issues. TODO work on this. consequently, I have not implemented stretching. all hexagons are assumed to be regular. you could implement this yourself by making layout.size a vec2(sizex, sizey), but you would have to play with transforms in the amulet library if you wanted to use amulet. some of the primary resources used to develop this library: - https://redblobgames.com/grid/hexagons - simply amazing. - http://amulet.xyz/doc - amulet documentation - TODO that place that had the inner circle/outer circle ratio?? ]] -- GENERALLY USEFUL CONSTANTS ------------------------------------------------- -- GENERALLY USEFUL FUNCTIONS -------------------------------------------------- function round(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) end function draw_axes(window, node) xaxis = am.line(vec2(-window.width / 2, 0) , vec2(window.width / 2, 0)) yaxis = am.line(vec2(0, -window.height / 2), vec2(0, window.height / 2)) node:append(xaxis) node:append(yaxis) end -- HEX CONSTANTS --------------------------------------------------------------- -- all possible vector directions from a given hex by edge HEX_DIRECTIONS = {vec2( 1 , 0), vec2( 1 , -1), vec2( 0 , -1), vec2(-1 , 0), vec2(-1 , 1), vec2( 0 , 1)} -- HEX UTILITY FUNCTIONS ------------------------------------------------------- function hex_equals(a, b) return a.s == a.t and b.s == b.t end function hex_nequals(a, b) return not hex_equals(a, b) end function hex_length(hex) return ((math.abs(hex.s) + math.abs(hex.t) + math.abs(-hex.s - hex.t)) / 2) end function hex_distance(a, b) return hex_length(a - b) end function hex_direction(direction) return HEX_DIRECTIONS[direction] end function hex_neighbour(hex, direction) return hex + HEX_DIRECTIONS[direction] end function hex_round(hex) rs = round(hex.s) rt = round(hex.t) rz = round(-hex.s + -hex.t) sdelta = math.abs(rs - hex.s) tdelta = math.abs(rt - hex.t) zdelta = math.abs(rz + hex.s + hex.t) if sdelta > tdelta and sdelta > zdelta then rs = -rt - rz elseif tdelta > zdelta then rt = -rs - rz else rz = -rs - rt end return vec2(rs, rt) end -- COORDINATE CONVERSION FUNCTIONS --------------------------------------------- -- forward & inverse matrices used for coordinate conversion local M = mat2(3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5 ) local W = mat2(2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0) -- hex to screen function hex_to_pixel(hex, origin) x = (M[1][1] * hex.s + M[1][2] * hex.t) * SIZE y = (M[2][1] * hex.s + M[2][2] * hex.t) * SIZE return vec2(x + origin.x, y + origin.y) end -- screen to hex function pixel_to_hex(pix, origin) pix = vec2(pix.x - origin.x) / SIZE, (pix.y - origin.y) / SIZE s = W[1][1] * pix.x + W[1][2] * pix.y t = W[2][1] * pix.x + W[2][2] * pix.y return hex_round(vec2(s, t)) end -- MAP FUNCTIONS --------------------------------------------------------------- function hexagonal_map(radius, origin) for s = -radius, radius do t1 = math.max(-radius, -s - radius) t2 = math.min(radius, -s + radius) for t = t1, t2 do color = vec4(math.random(20, 80) / 100, math.random(20, 80) / 100, math.random(20, 80) / 100, 1) map:append(am.circle(hex_to_pixel(vec2(s, t)), 24, color, 6)) end end end function rectangular_map(width, height, origin) for s = 0, height do soffset = math.floor(s / 2) for t = -soffset, width - soffset do center = hex_to_pixel(vec2(s, t)) end end end --]]