Browse Source

cleaned up a bunch of library functions.

master
churchianity 6 years ago
parent
commit
2291bcad45
  1. 163
      hex.lua
  2. 122
      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
-- INTRODUCTION
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)
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.
http://amulet.xyz/doc - amulet documentation
TODO that place that had the inner circle/outer circle ratio??
]]
----- [[ GENERALLY USEFUL FUNCTIONS ]] -----------------------------------------
@ -35,7 +18,7 @@ local function round(n)
return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
end
----- [[ HEX CONSTANTS ]] ------------------------------------------------------
----- [[ HEX CONSTANTS & UTILITY FUNCTIONS ]] ----------------------------------
-- all possible vector directions from a given hex by edge
local HEX_DIRECTIONS = {vec2( 1 , 0),
@ -45,20 +28,19 @@ local HEX_DIRECTIONS = {vec2( 1 , 0),
vec2(-1 , 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
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
-- 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)
local rs = round(s)
local rt = round(t)
@ -82,15 +64,16 @@ 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}
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.
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
function layout_init(origin, size, orientation)
function hex_layout(origin, size, orientation)
return {origin = origin or vec2(0),
size = size or vec2(11),
orientation = orientation or FLAT}
@ -98,116 +81,65 @@ end
-- hex to screen
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)
end
-- screen to hex
function pixel_to_hex(pix, layout)
local M = layout.orientation
local W = layout.orientation.W
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)
end
----- [[ 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 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)
for s = 0, width do
for t = 0, height do
table.insert(map, hex_to_pixel(vec2(s, t), layout))
map[vec2(s, t)] = true
end
end
return map
end
-- returns triangular map.
function trimap_init(layout, size)
-- returns unordered triangular map of |size|.
function hex_triangular_map(size)
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)
for s = 0, size do
for t = size - s, size do
map.store(vec2(s, t))
map[vec2(s, t)] = true
end
end
return map
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 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)
@ -216,33 +148,22 @@ function hexmap_init(layout, radius)
local t2 = math.min(radius, -s + radius)
for t = t1, t2 do
table.insert(map, hex_to_pixel(vec2(s, t), layout))
map[vec2(s, t)] = true
end
end
return map
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 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)
for s = 0, width do
for t = 0, height do
map.store(vec2(s, t))
map[vec2(s, t)] = true
end
end
return map

122
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
]]
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
----- [[ BLAH BLAH LBAH ]] -----------------------------------------------
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
----- [[ 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))
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))
world:append(lgui)
world:append(rgui)
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
return true
end)
end))
grid:append(am.translate(350, 200)
^ am.scale(2)
^ am.sprite("2.png"))
show_hex_coords()
return grid
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
end
function game_init()
return am.group{grid_init(), toolbar_init()}
function init()
world_init()
show_axes()
win.scene = world
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