Browse Source

cleaned up a bunch of library functions.

master
churchianity 6 years ago
parent
commit
2291bcad45
  1. 163
      hex.lua
  2. 118
      main.lua
  3. 9
      util.lua

163
hex.lua

@ -1,4 +1,4 @@
----- [[ AXIAL/CUBE COORDINATE SYSTEM FOR AMULET/LUA]] -------------------------
----- [[ AXIAL/CUBE COORDINATE HEXAGON LIBRARY FOR AMULET/LUA]] ----------------
--[[ author@churchianity.ca --[[ author@churchianity.ca
-- INTRODUCTION -- INTRODUCTION
this is a hexagonal grid library for amulet/lua. this is a hexagonal grid library for amulet/lua.
@ -6,26 +6,9 @@
by amulet convention, hexes are either vec2(s, t) or vec3(s, t, z) by amulet convention, hexes are either vec2(s, t) or vec3(s, t, z)
but nearly always the former. but nearly always the former.
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 arbitrary maps with gaps via hashmaps-like storage
+support for simple irregular hexagons (horizontal and vertical stretching).
classes are used sparsely. maps implement a few constructors for storing
your maps elsewhere, and should be the only field that is necessarily
visible outside the library.
-- RESOURCES USED TO DEVELOP THIS LIBRARY
-- RESOURCES USED TO DEVELOP THIS LIBRARY, AND FOR WHICH I AM GRATEFUL
https://redblobgames.com/grid/hexagons - simply amazing. https://redblobgames.com/grid/hexagons - simply amazing.
http://amulet.xyz/doc - amulet documentation http://amulet.xyz/doc - amulet documentation
TODO that place that had the inner circle/outer circle ratio??
]] ]]
----- [[ GENERALLY USEFUL FUNCTIONS ]] ----------------------------------------- ----- [[ GENERALLY USEFUL FUNCTIONS ]] -----------------------------------------
@ -35,7 +18,7 @@ local function round(n)
return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
end end
----- [[ HEX CONSTANTS ]] ------------------------------------------------------
----- [[ HEX CONSTANTS & UTILITY FUNCTIONS ]] ----------------------------------
-- all possible vector directions from a given hex by edge -- all possible vector directions from a given hex by edge
local HEX_DIRECTIONS = {vec2( 1 , 0), local HEX_DIRECTIONS = {vec2( 1 , 0),
@ -45,20 +28,19 @@ local HEX_DIRECTIONS = {vec2( 1 , 0),
vec2(-1 , 1), vec2(-1 , 1),
vec2( 0 , 1)} vec2( 0 , 1)}
----- [[ HEX UTILITY FUNCTIONS ]] ----------------------------------------------
function hex_equals(a, b)
return a.s == b.s and a.t == b.t
-- return hex vector direction via index |direction|.
function hex_direction(direction)
return HEX_DIRECTIONS[direction]
end end
function hex_length(hex)
return round(math.abs(hex.s) + math.abs(hex.r) + math.abs(-hex.s - hex.t)/2)
end
function hex_distance(a, b)
return hex_length(a - b)
-- return hexagon adjacent to |hex| in |direction|
function hex_neighbour(hex, direction)
return hex + HEX_DIRECTION[direction]
end end
-- rounds hexes. without this, pixel_to_hex returns fractional coordinates.
-- using single coordinates instead of a vector, because this should only
-- ever be called internally.
function hex_round(s, t) function hex_round(s, t)
local rs = round(s) local rs = round(s)
local rt = round(t) local rt = round(t)
@ -82,15 +64,16 @@ end
----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] ----------------------- ----- [[ LAYOUT, ORIENTATION & COORDINATE CONVERSION ]] -----------------------
-- forward & inverse matrices used for the flat orientation. -- 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}
local FLAT = {M = mat2(3.0/2.0, 0.0, 3.0^0.5/2.0, 3.0^0.5 ),
W = mat2(2.0/3.0, 0.0, -1.0/3.0 , 3.0^0.5/3.0)}
-- forward & inverse matrices used for the pointy orientation. -- 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}
local POINTY = {M = mat2(3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0),
W = mat2(3.0^0.5/3.0, -1.0/3.0, 0.0, 2.0/3.0)}
-- TODO encapsulate hex_to_pixel and pixel_to_hex in layout table.
-- stores layout information that does not pertain to map shape -- stores layout information that does not pertain to map shape
function layout_init(origin, size, orientation)
function hex_layout(origin, size, orientation)
return {origin = origin or vec2(0), return {origin = origin or vec2(0),
size = size or vec2(11), size = size or vec2(11),
orientation = orientation or FLAT} orientation = orientation or FLAT}
@ -98,116 +81,65 @@ end
-- hex to screen -- hex to screen
function hex_to_pixel(hex, layout) function hex_to_pixel(hex, layout)
local M = layout.orientation
local M = layout.orientation.M
local x = (M[1] * hex.s + M[2] * hex.t) * layout.size.x
local y = (M[3] * hex.s + M[4] * hex.t) * layout.size.y
local x = (M[1][1] * hex.s + M[1][2] * hex.t) * layout.size.x
local y = (M[2][1] * hex.s + M[2][2] * hex.t) * layout.size.y
return vec2(x + layout.origin.x, y + layout.origin.y) return vec2(x + layout.origin.x, y + layout.origin.y)
end end
-- screen to hex -- screen to hex
function pixel_to_hex(pix, layout) function pixel_to_hex(pix, layout)
local M = layout.orientation
local W = layout.orientation.W
local pix = (pix - layout.origin) / layout.size local pix = (pix - layout.origin) / layout.size
local s = M[5] * pix.x + M[6] * pix.y
local t = M[7] * pix.x + M[8] * pix.y
local s = W[1][1] * pix.x + W[1][2] * pix.y
local t = W[2][1] * pix.x + W[2][2] * pix.y
return hex_round(s, t) return hex_round(s, t)
end end
----- [[ MAP STORAGE & RETRIEVAL ]] -------------------------------------------- ----- [[ MAP STORAGE & RETRIEVAL ]] --------------------------------------------
--[[ _init functions return a table of tables;
a map of points in a chosen shape and specified layout.
grammap_init - parallelogram map
trimap_init - triangular map
hexmap_init - hexagonal map
rectmap_init - rectangular map
calling .retrieve(pix) on your map will get the hexagon at that pixel.
calling .store(hex) on your map will store that hex as pixel coords.
maps store coordinates like this:
map[hex] = hex_to_pixel(hex)
this means you should be able to get all the information you need about
various coordinates completely within the map 'class', without calling
any internal functions. indeed, *map_init, map.retrieve, and map.store
is all you need.
--[[
]] ]]
-- TODO make all functions work regardless of layout.
-- returns parallelogram-shaped map.
function grammap_init(layout, width, height)
-- returns unordered parallelogram-shaped map of |width| and |height|.
function hex_parallelogram_map(width, height)
local map = {} local map = {}
local mt = {__index={layout=layout,
-- get hex in map from pixel coordinate
retrieve=function(pix)
return pixel_to_hex(pix, layout)
end,
-- store pixel in map from hex coordinate
store=function(hex)
map[hex]=hex_to_pixel(hex, layout)
end
}}
local mt = {__index={width=width, height=height}}
setmetatable(map, mt) setmetatable(map, mt)
for s = 0, width do for s = 0, width do
for t = 0, height do for t = 0, height do
table.insert(map, hex_to_pixel(vec2(s, t), layout))
map[vec2(s, t)] = true
end end
end end
return map return map
end end
-- returns triangular map.
function trimap_init(layout, size)
-- returns unordered triangular map of |size|.
function hex_triangular_map(size)
local map = {} local map = {}
local mt = {__index={layout=layout,
-- get hex in map from pixel coordinate
retrieve=function(pix)
return pixel_to_hex(pix, layout)
end,
-- store pixel in map from hex coordinate
store=function(hex)
map[hex]=hex_to_pixel(hex, layout)
end
}}
local mt = {__index={size=size}}
setmetatable(map, mt) setmetatable(map, mt)
for s = 0, size do for s = 0, size do
for t = size - s, size do for t = size - s, size do
map.store(vec2(s, t))
map[vec2(s, t)] = true
end end
end end
return map return map
end end
-- returns hexagonal map. length of map is radius * 2 + 1
function hexmap_init(layout, radius)
-- returns unordered hexagonal map of |radius|.
function hex_hexagonal_map(radius)
local map = {} local map = {}
local mt = {__index={layout=layout,
-- get hex in map from pixel coordinate
retrieve=function(pix)
return pixel_to_hex(pix, layout)
end,
-- store pixel in map from hex coordinate
store=function(hex)
map[hex]=hex_to_pixel(hex, layout)
end
}}
local mt = {__index={radius=radius}}
setmetatable(map, mt) setmetatable(map, mt)
@ -216,33 +148,22 @@ function hexmap_init(layout, radius)
local t2 = math.min(radius, -s + radius) local t2 = math.min(radius, -s + radius)
for t = t1, t2 do for t = t1, t2 do
table.insert(map, hex_to_pixel(vec2(s, t), layout))
map[vec2(s, t)] = true
end end
end end
return map return map
end end
-- returns rectangular map.
function rectmap_init(layout, width, height)
-- returns unordered rectangular map of |width| and |height|.
function hex_rectangular_map(width, height)
local map = {} local map = {}
local mt = {__index={layout=layout,
-- get hex in map from pixel coordinate
retrieve=function(pix)
return pixel_to_hex(pix, layout)
end,
-- store pixel in map from hex coordinate
store=function(hex)
map[hex]=hex_to_pixel(hex - vec2(0, math.floor(hex.s/2)), layout)
end
}}
local mt = {__index={width=width, height=height}}
setmetatable(map, mt) setmetatable(map, mt)
for s = 0, width do for s = 0, width do
for t = 0, height do for t = 0, height do
map.store(vec2(s, t))
map[vec2(s, t)] = true
end end
end end
return map return map

118
main.lua

@ -1,107 +1,57 @@
----- [[ WARZONE 2 - HEXAGONAL GRID RESOURCE BASED TOWER DEFENSE GAME]] -------
----- [[ WARZONE 2 - HEXAGONAL GRID RESOURCE BASED TOWER DEFENSE GAME]] --------
--[[ author@churchianity.ca --[[ author@churchianity.ca
]] ]]
require "hex" require "hex"
require "util"
----- [[ DUMMY FUNCTIONS ]] ----------------------------------------------------
local world
function show_hex_coords()
grid:action(function()
grid:remove("text")
mouse_position = vec2(win:mouse_position().x, win:mouse_position().y)
local guibgcolor = vec4(0.5, 0.5, 0.2, 0)
if mouse_position.x < 268 then
hex = map.retrieve(mouse_position)
grid:append(am.translate(win.left + 30, win.top - 10)
^ am.text(string.format("%d,%d", hex.s, hex.t)))
end
end)
end
local win = am.window{
-- BASE RESOLUTION = 3/4 * WXGA Standard 16:10
width = 1280 * 3 / 4, -- 960px
height = 800 * 3 / 4, -- 600px
function rcolor()
return vec4(math.random(20, 80) / 100,
math.random(20, 80) / 100,
math.random(20, 80) / 100,
1)
end
title = "Warzone 2: Electric Boogaloo"}
SPRITES = {"BoulderHills1.png", "BoulderHills2.png", "BoulderHills2.png",
"Brambles1.png", "Brambles2.png", "Brambles3.png", "Brambles4.png",
"BrownHills1.png", "BrownHills2.png", "BrownHills3.png",
"Grass1.png", "Grass2.png", "Grass3.png", "Grass4.png", "Grass5.png", "Hills1.png", "Hills2.png", "Hills3.png", "Hills4.png", "Hills5.png",
"HillsGreen1.png", "HillsGreen2.png", "HillsGreen3.png",
"LightGrass1.png", "LightGrass2.png", "LightGrass3.png",
"LowHills1.png", "LowHills2.png", "LowHills3.png", "LowHills4.png",
"Mountains1.png", "Mountains2.png", "Mountains3.png",
"Mud1.png", "Mud2.png", "Mud3.png", "Mud4.png", "Mud5.png",
"Orchards1.png", "Orchards2.png", "Orchards3.png", "Orchards4.png",
"PineForest1.png", "PineForest2.png", "PineForest3.png",
"Woods1.png", "Woods2.png", "Woods3.png", "Woods4.png"}
function rsprite()
return string.format("res/%s", SPRITES[math.random(#SPRITES)])
function show_axes()
xaxis = am.line(vec2(win.left, 0), vec2(win.right, 0))
yaxis = am.line(vec2(0, win.top), vec2(0, win.bottom))
world:append(am.group{xaxis, yaxis}:tag("axes"))
end end
----- [[ BLAH BLAH LBAH ]] -----------------------------------------------
win = am.window {
title = "Warzone 2: Electric Boogaloo",
function world_init()
world = am.group()
local layout = layout_init(vec2(-402, win.bottom))
local map = rectmap_init(45, 31)
local lgui = am.group(
am.rect(win.left, win.top, -402, win.bottom, guibgcolor))
local rgui = am.group(
am.rect(win.right, win.top, 402, win.bottom, guibgcolor))
-- BASE RESOLUTION = 3/4 * WXGA Standard 16:10 Aspect Ratio
width = 1280 * 3 / 4, -- 960
height = 800 * 3 / 4} -- 600
world:append(lgui)
world:append(rgui)
----- [[ MAP RENDERING ]] ------------------------------------------------
function grid_init()
grid = am.group()
map = rectmap_init(layout_init(vec2(win.left, win.bottom)), 45, 31)
grid:action(function()
for hex,pix in pairs(map) do
grid:append(am.circle(pix, map.layout.size.x, rcolor(), 6))
world:action(coroutine.create(function()
for hex,_ in pairs(map) do
world:append(am.circle(hex_to_pixel(hex, layout), 11, rrgb(1), 6))
am.wait(am.delay(0.01))
end end
return true
end)
grid:append(am.translate(350, 200)
^ am.scale(2)
^ am.sprite("2.png"))
end))
show_hex_coords()
return grid
end end
function toolbar_init()
local toolbar = am.group()
local toolbar_bg = vec4(0.4, 0.6, 0.8, 1)
toolbar:append(am.rect(268, win.top, win.right, win.bottom, toolbar_bg))
toolbar:append(am.particles2d({source_pos=vec2(win.width/2-268, win.top),
source_pos_var=vec2(0, 600),
angle=math.pi/4,
start_color=vec4(0.9),
gravity=vec2(100),
start_color_var=rcolor(),
start_size=3}))
return toolbar
function init()
world_init()
show_axes()
win.scene = world
end end
function game_init()
return am.group{grid_init(), toolbar_init()}
end
----- [[ MAIN ]] -----------------------------------------------------------
local map = {}
win.scene = game_init()
----- [[ MAIN ]] ---------------------------------------------------------------
show_hex_coords()
init()

9
util.lua

@ -0,0 +1,9 @@
function rrgb(a)
local R = math.random(20, 80) / 100
local G = math.random(20, 80) / 100
local B = math.random(20, 80) / 100
local A = a or math.random()
return vec4(R, G, B, A)
end
Loading…
Cancel
Save