diff --git a/hex.lua b/hex.lua index 22c2a45..443de0a 100644 --- a/hex.lua +++ b/hex.lua @@ -1,38 +1,26 @@ ----- [[ AXIAL/CUBE COORDINATE SYSTEM FOR AMULET/LUA]] ------------------------- --[[ author@churchianity.ca -- INTRODUCTION - this is a library for making grids of hexagons using lua. - it has made exclusive (though not thorough) use of standard lua - 5.2 functionality, making it as portable as possible. it - doesn't even use a point class, simply returning tables - of integers, which can later be unpacked into your amulet - vectors, or whatever else you want to use. in honor of amulet, - when necessary to name cube/hex coordinates, (s, t, z) is the - convention. - - only returning tables can result in some nasty looking lines - with lots of table unpacks, but if your graphics library likes - traditional lua types, you will be better off. - - it supports triangular, hexagonal, rectangular, and - parallelogram map shapes. + this is a hexagonal grid library for amulet/lua. + it uses axial coordinates or cube/hex coordinates when necessary. + by amulet convention, hexes are either vec2(s, t) or vec3(s, t, z) + but nearly always the former. - it supports non-regular hexagons, though it's trickier to get - working in amulet. TODO work on this. - - -- NOTE ON ORIENTATION + AMULET - because of the way amulet draws hexagons (amulet essentially - draws a 6-sided circle from a centerpoint, instead of of a - series of lines connecting points), the flat orientation is - default and recommended. other orientations are possible - with am.rotate, but can cause aliasing issues. TODO work on this. - -- TODO NOTE - - amulet has another draw function I neglected, simply am.draw. - i don't understand how it works, but it seems to be able to - draw arbitrary polygons via a list of vertices. so. + in some rare cases, coordinates will be passed individually, usually + because they are only passed internally and should never be adjusted + directly. + + in amulet, vector arithmetic already works via: + - * / + additional things such as equality, and distance are implemented here. + + +support for parallelogram, triangular, hexagonal and rectangular maps. + +support for simple irregular hexagons (horizontal and vertical stretching). + + classes are used sparsely. maps implement a few constructors, for storing + your maps elsewhere. -- RESOURCES USED TO DEVELOP THIS LIBRARY - https://redblobgames.com/grid/hexagons - simply amazing. amit is a god. + https://redblobgames.com/grid/hexagons - simply amazing. http://amulet.xyz/doc - amulet documentation TODO that place that had the inner circle/outer circle ratio?? @@ -41,23 +29,23 @@ ----- [[ GENERALLY USEFUL FUNCTIONS ]] ----------------------------------------- -- just incase you don't already have a rounding function. -function round(n) +local function round(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) end ---- [[ HEX CONSTANTS ]] ------------------------------------------------------- -- all possible vector directions from a given hex by edge -HEX_DIRECTIONS = {{ 1 , 0}, - { 1 , -1}, - { 0 , -1}, - {-1 , 0}, - {-1 , 1}, - { 0 , 1}} +local 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_round(s, t) +local function hex_round(s, t) rs = round(s) rt = round(t) rz = round(-s - t) @@ -74,7 +62,7 @@ function hex_round(s, t) rz = -rs - rt end - return {rs, rt} + return vec2(rs, rt) end ----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] ----------------------- @@ -89,30 +77,29 @@ local POINTY = {3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0, -- layout. function layout_init(origin, size, orientation) - return {origin = origin or {0, 0}, - size = size or {11, 11}, + return {origin = origin or vec2(0), + size = size or vec2(11), orientation = orientation or FLAT} end -- hex to screen -function hex_to_pixel(s, t, layout) +function hex_to_pixel(hex, layout) M = layout.orientation - x = (M[1] * s + M[2] * t) * layout.size[1] - y = (M[3] * s + M[4] * t) * layout.size[2] + x = (M[1] * hex.s + M[2] * hex.t) * layout.size.x + y = (M[3] * hex.s + M[4] * hex.t) * layout.size.y - return {x + layout.origin[1], y + layout.origin[2]} + return vec2(x + layout.origin.x, y + layout.origin.y) end -- screen to hex -function pixel_to_hex(x, y, layout) +function pixel_to_hex(pix, layout) M = layout.orientation - px = {(x - layout.origin[1]) / layout.size[1], - (y - layout.origin[2]) / layout.size[2]} + pix = (pix - layout.origin) / layout.size - s = M[5] * px[1] + M[6] * px[2] - t = M[7] * px[1] + M[8] * px[2] + s = M[5] * pix.x + M[6] * pix.y + t = M[7] * pix.x + M[8] * pix.y return hex_round(s, t) end @@ -129,12 +116,12 @@ end function map_parallelogram_init(layout, width, height) map = {} setmetatable(map, {__index={layout=layout, - shape="parallelogram", - width=width, - height=height}}) + width=width, + height=height, + shape="parallelogram"}}) for s = 0, width do for t = 0, height do - table.insert(map, hex_to_pixel(s, t, layout)) + table.insert(map, hex_to_pixel(vec2(s, t), layout)) end end return map @@ -144,11 +131,11 @@ end function map_triangular_init(layout, size) map = {} setmetatable(map, {__index={layout=layout, - shape="triangular", - size=size}}) + size=size, + shape="triangular"}}) for s = 0, size do for t = size - s, size do - table.insert(map, hex_to_pixel(s, t, layout)) + table.insert(map, hex_to_pixel(vec2(s, t), layout)) end end return map @@ -158,14 +145,14 @@ end function map_hexagonal_init(layout, radius) map = {} setmetatable(map, {__index={layout=layout, - shape="hexagonal", - radius=radius}}) + radius=radius, + shape="hexagonal"}}) for s = -radius, radius do t1 = math.max(-radius, -s - radius) t2 = math.min(radius, -s + radius) for t = t1, t2 do - table.insert(map, hex_to_pixel(s, t, layout)) + table.insert(map, hex_to_pixel(vec2(s, t), layout)) end end return map @@ -174,49 +161,28 @@ end -- returns rectangular map. function map_rectangular_init(layout, width, height) map = {} - setmetatable(map, {__index={layout=layout, - shape="rectangular", - width=width, - height=height}}) + mt = {__index = {layout = layout, width = width, height = height, + + retrieve = function(pix) + hex = pixel_to_hex(pix, layout) + print(tostring(hex)) + print(map[tostring(hex)]) + return vec2(hex.s, hex.t + math.floor(hex.s / 2)) + end, + + store = function(hex) + pix = hex_to_pixel(hex, layout) + return vec2(pix.x - math.floor(pix.y / 2), pix.y) + end}} + for s = 0, width do soffset = math.floor(s/2) for t = -soffset, height - soffset do - table.insert(map, hex_to_pixel(s, t, layout)) - end - end - return map -end - --- places single hex into map table, if it is not already present. -function map_store(map) - -end - --- retrieves single hex from map table. explodes if can't find it. -function map_retrieve(map, hex) - if map.shape == "rectangular" then - if map.layout.orientation == FLAT then - return {hex[1] + math.floor(hex[2]/2), hex[2]} - else - return {hex[1], hex[2] + math.floor(hex[1]/2)} - end - elseif map.shape == "hexagonal" then - if map.layout.orientation == FLAT then - - else - + map[tostring(vec2(s, t))] = hex_to_pixel(vec2(s, t), layout) end - elseif map.shape == "parallelogram" then - if map.layout.orientation == FLAT then - - else - - end - else - end - - + setmetatable(map, mt) + return map end diff --git a/main.lua b/main.lua index 623d3c5..58333d6 100644 --- a/main.lua +++ b/main.lua @@ -5,14 +5,16 @@ require "hex" ------ [[ DUMMY FUNCTIONS ]] ------------------------------------------------------ - -function draw_axes() - xaxis = am.line(vec2(-win.width / 2, 0) , vec2(win.width / 2, 0)) - yaxis = am.line(vec2(0, -win.height / 2), vec2(0, win.height / 2)) - - title_scene:append(xaxis) - title_scene:append(yaxis) +----- [[ DUMMY FUNCTIONS ]] ---------------------------------------------------- + +function show_hex_coords(map) + test_scene:action(function() + mouse_position = vec2(win:mouse_position().x, win:mouse_position().y) + hex = map.retrieve(mouse_position) + test_scene:remove("text") + test_scene:append(am.translate(win.right - 30, win.top - 10) + ^ am.text(string.format("%d,%d", hex.s, hex.t))) + end) end function rcolor() @@ -21,37 +23,34 @@ end ----- [[ BLAH BLAH LBAH ]] ----------------------------------------------- -local win = am.window { - title = "Warzone 2: Electric Boogaloo", +win = am.window { + title = "Warzone 2: Electric Boogaloo", - -- BASE RESOLUTION = 3/4 * WXGA Standard 16:10 Aspect Ratio - width = 1280 * 3 / 4, -- 960 - height = 800 * 3 / 4} -- 600 - -local layout = layout_init({win.left, win.bottom}) + -- BASE RESOLUTION = 3/4 * WXGA Standard 16:10 Aspect Ratio + width = 1280 * 3 / 4, -- 960 + height = 800 * 3 / 4} -- 600 ----- [[ MAP RENDERING ]] ------------------------------------------------ -function render_map(layout) +function game_scene(layout) map = map_rectangular_init(layout, 45, 31) hexagons = am.group() - for _,v in pairs(map) do - hexagons:append(am.circle(vec2(unpack(v)), layout.size[1], rcolor(), 6)) + for _,hex in pairs(map) do + hexagons:append( + am.circle(hex, layout.size.x, rcolor(), 6):tag(tostring(hex))) end return hexagons end ----- [[ MAIN ]] ----------------------------------------------------------- -local game_scene = render_map(layout) -local test_scene = am.group() +map = {} +game_scene = game_scene(layout_init(vec2(win.left, win.bottom))) + +test_scene = am.group() win.scene = am.group{test_scene, game_scene} -test_scene:action(function() - hexpos = pixel_to_hex(win:mouse_position().x, win:mouse_position().y, layout) - x, y = unpack(map_retrieve(map, hexpos)) - test_scene:remove_all("text") - test_scene:append(am.translate(x, y) ^ am.text(string.format("%d, %d", hexpos[1], hexpos[2]))) -end) +show_hex_coords(map) +