You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
6.7 KiB
222 lines
6.7 KiB
----- [[ 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.
|
|
|
|
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.
|
|
|
|
-- RESOURCES USED TO DEVELOP THIS LIBRARY
|
|
https://redblobgames.com/grid/hexagons - simply amazing. amit is a god.
|
|
http://amulet.xyz/doc - amulet documentation
|
|
TODO that place that had the inner circle/outer circle ratio??
|
|
|
|
]]
|
|
|
|
----- [[ GENERALLY USEFUL FUNCTIONS ]] -----------------------------------------
|
|
|
|
-- just incase you don't already have a rounding function.
|
|
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}}
|
|
|
|
-- HEX UTILITY FUNCTIONS -------------------------------------------------------
|
|
|
|
function hex_round(s, t)
|
|
rs = round(s)
|
|
rt = round(t)
|
|
rz = round(-s - t)
|
|
|
|
sdelta = math.abs(rs - s)
|
|
tdelta = math.abs(rt - t)
|
|
zdelta = math.abs(rz - (-s - t))
|
|
|
|
if sdelta > tdelta and sdelta > zdelta then
|
|
rs = -rt - rz
|
|
elseif tdelta > zdelta then
|
|
rt = -rs - rz
|
|
else
|
|
rz = -rs - rt
|
|
end
|
|
|
|
return {rs, rt}
|
|
end
|
|
|
|
----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] -----------------------
|
|
|
|
-- forward & inverse matrices used for the flat orientation.
|
|
local FLAT = {3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5,
|
|
2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0}
|
|
|
|
-- forward & inverse matrices used for the pointy orientation.
|
|
local POINTY = {3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0,
|
|
3.0^0.5/3.0, -1.0/3.0, 0.0, 2.0/3.0}
|
|
|
|
-- layout.
|
|
function layout_init(origin, size, orientation)
|
|
return {origin = origin or {0, 0},
|
|
size = size or {11, 11},
|
|
orientation = orientation or FLAT}
|
|
end
|
|
|
|
-- hex to screen
|
|
function hex_to_pixel(s, t, layout)
|
|
M = layout.orientation
|
|
|
|
x = (M[1] * s + M[2] * t) * layout.size[1]
|
|
y = (M[3] * s + M[4] * t) * layout.size[2]
|
|
|
|
return {x + layout.origin[1], y + layout.origin[2]}
|
|
end
|
|
|
|
-- screen to hex
|
|
function pixel_to_hex(x, y, layout)
|
|
M = layout.orientation
|
|
|
|
px = {(x - layout.origin[1]) / layout.size[1],
|
|
(y - layout.origin[2]) / layout.size[2]}
|
|
|
|
s = M[5] * px[1] + M[6] * px[2]
|
|
t = M[7] * px[1] + M[8] * px[2]
|
|
|
|
return hex_round(s, t)
|
|
end
|
|
|
|
----- [[ MAP STORAGE & RETRIEVAL ]] --------------------------------------------
|
|
|
|
--[[ _init functions return a table of tables;
|
|
a map of points in a chosen shape and specified layout.
|
|
the shape, as well as the layout used is stored in a metatable
|
|
for reuse.
|
|
]]
|
|
|
|
-- returns parallelogram-shaped map.
|
|
function map_parallelogram_init(layout, width, height)
|
|
map = {}
|
|
setmetatable(map, {__index={layout=layout,
|
|
shape="parallelogram",
|
|
width=width,
|
|
height=height}})
|
|
for s = 0, width do
|
|
for t = 0, height do
|
|
table.insert(map, hex_to_pixel(s, t, layout))
|
|
end
|
|
end
|
|
return map
|
|
end
|
|
|
|
-- returns triangular map.
|
|
function map_triangular_init(layout, size)
|
|
map = {}
|
|
setmetatable(map, {__index={layout=layout,
|
|
shape="triangular",
|
|
size=size}})
|
|
for s = 0, size do
|
|
for t = size - s, size do
|
|
table.insert(map, hex_to_pixel(s, t, layout))
|
|
end
|
|
end
|
|
return map
|
|
end
|
|
|
|
-- returns hexagonal map. length of map is radius * 2 + 1
|
|
function map_hexagonal_init(layout, radius)
|
|
map = {}
|
|
setmetatable(map, {__index={layout=layout,
|
|
shape="hexagonal",
|
|
radius=radius}})
|
|
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))
|
|
end
|
|
end
|
|
return map
|
|
end
|
|
|
|
-- returns rectangular map.
|
|
function map_rectangular_init(layout, width, height)
|
|
map = {}
|
|
setmetatable(map, {__index={layout=layout,
|
|
shape="rectangular",
|
|
width=width,
|
|
height=height}})
|
|
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
|
|
|
|
end
|
|
elseif map.shape == "parallelogram" then
|
|
if map.layout.orientation == FLAT then
|
|
|
|
else
|
|
|
|
end
|
|
else
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|