Browse Source

made a /src folder

master
churchianity 6 years ago
parent
commit
0df10e2796
  1. 161
      src/hex.lua
  2. 96
      src/main.lua

161
hex.lua → src/hex.lua

@ -1,6 +1,6 @@
--[[============================================================================ --[[============================================================================
----- GENERALLY USEFUL FUNCTIONS -----
----- GENERALLY USEFUL FUNCTIONS -----
============================================================================]]-- ============================================================================]]--
-- rounds numbers. would've been cool to have math.round in lua. -- rounds numbers. would've been cool to have math.round in lua.
@ -9,11 +9,11 @@ local function round(n)
end end
--[[============================================================================ --[[============================================================================
----- HEX CONSTANTS AND UTILITY FUNCTIONS -----
----- HEX CONSTANTS AND UTILITY FUNCTIONS -----
============================================================================]]-- ============================================================================]]--
-- all possible vector directions from a given hex by edge -- all possible vector directions from a given hex by edge
local CUBE_DIRECTIONS = {vec2( 0 , 1),
local HEX_DIRECTIONS = {vec2( 0 , 1),
vec2( 1 , 0), vec2( 1 , 0),
vec2( 1 , -1), vec2( 1 , -1),
vec2( 0 , -1), vec2( 0 , -1),
@ -21,27 +21,27 @@ local CUBE_DIRECTIONS = {vec2( 0 , 1),
vec2(-1 , 1)} vec2(-1 , 1)}
-- return hex vector direction via integer index |direction|. -- return hex vector direction via integer index |direction|.
function cube_direction(direction)
return CUBE_DIRECTIONS[(direction % 6) % 6 + 1]
function hex_direction(direction)
return HEX_DIRECTIONS[(direction % 6) % 6 + 1]
end end
-- return hexagon adjacent to |hex| in integer index |direction|. -- return hexagon adjacent to |hex| in integer index |direction|.
function cube_neighbour(hex, direction)
return hex + CUBE_DIRECTIONS[(direction % 6) % 6 + 1]
function hex_neighbour(hex, direction)
return hex + HEX_DIRECTIONS[(direction % 6) % 6 + 1]
end end
-- return cube coords at location 60deg away to the left; counter-clockwise -- return cube coords at location 60deg away to the left; counter-clockwise
function cube_rotate_left(hex)
function hex_rotate_left(hex)
return vec2(hex.x + hex.y, -hex.x) return vec2(hex.x + hex.y, -hex.x)
end end
-- return cube coords at location 60deg away to the right; clockwise -- return cube coords at location 60deg away to the right; clockwise
function cube_rotate_right(hex)
function hex_rotate_right(hex)
return vec2(-hex.y, hex.x + hex.y) return vec2(-hex.y, hex.x + hex.y)
end end
-- rounds a float coordinate trio |x, y, z| to nearest integer coordinate trio -- rounds a float coordinate trio |x, y, z| to nearest integer coordinate trio
local function cube_round(x, y, z)
local function hex_round(x, y, z)
local rx = round(x) local rx = round(x)
local ry = round(y) local ry = round(y)
local rz = round(z) or round(-x - y) local rz = round(z) or round(-x - y)
@ -61,7 +61,7 @@ local function cube_round(x, y, z)
end end
--[[============================================================================ --[[============================================================================
----- ORIENTATION & LAYOUT -----
----- ORIENTATION & LAYOUT -----
============================================================================]]-- ============================================================================]]--
-- forward & inverse matrices used for the flat orientation -- forward & inverse matrices used for the flat orientation
@ -82,17 +82,17 @@ function layout(origin, size, orientation)
end end
-- hex to screen -- hex to screen
function cube_to_pixel(cube, layout)
function hex_to_pixel(hex, layout)
local M = layout.orientation.M local M = layout.orientation.M
local x = (M[1][1] * cube[1] + M[1][2] * cube[2]) * layout.size[1]
local y = (M[2][1] * cube[1] + M[2][2] * cube[2]) * layout.size[2]
local x = (M[1][1] * hex[1] + M[1][2] * hex[2]) * layout.size[1]
local y = (M[2][1] * hex[1] + M[2][2] * hex[2]) * layout.size[2]
return vec2(x + layout.origin[1], y + layout.origin[2]) return vec2(x + layout.origin[1], y + layout.origin[2])
end end
-- screen to hex -- screen to hex
function pixel_to_cube(pix, layout)
function pixel_to_hex(pix, layout)
local W = layout.orientation.W local W = layout.orientation.W
local pix = (pix - layout.origin) / layout.size local pix = (pix - layout.origin) / layout.size
@ -100,7 +100,7 @@ function pixel_to_cube(pix, layout)
local s = W[1][1] * pix[1] + W[1][2] * pix[2] local s = W[1][1] * pix[1] + W[1][2] * pix[2]
local t = W[2][1] * pix[1] + W[2][2] * pix[2] local t = W[2][1] * pix[1] + W[2][2] * pix[2]
return cube_round(s, t, -s - t)
return hex_round(s, t, -s - t)
end end
-- TODO test, learn am.draw -- TODO test, learn am.draw
@ -116,23 +116,22 @@ function hex_corners(hex, layout)
end end
-- offset coordinates are prettier to look at -- offset coordinates are prettier to look at
function cube_to_offset(cube)
return vec2(cube[1], -cube[1] - cube[2] + (cube[1] + (cube[1] % 2)) / 2)
function hex_to_offset(hex)
return vec2(hex[1], -hex[1] - hex[2] + (hex[1] + (hex[1] % 2)) / 2)
end end
-- back to cube coordinates -- back to cube coordinates
function offset_to_cube(off)
function offset_to_hex(off)
return vec2(off[1], off[2] - off[1] * (off[1] % 2) / 2) return vec2(off[1], off[2] - off[1] * (off[1] % 2) / 2)
end end
--[[============================================================================ --[[============================================================================
----- MAPS & STORAGE ----- ----- MAPS & STORAGE -----
MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COORDINATES. MAPS STORE CUBE COOR
This means, you are not to draw using the coordinates stored in your map. This means, you are not to draw using the coordinates stored in your map.
You are to draw using the cube_to_pixel of those coordinates.
You are to draw using the hex_to_pixel of those coordinates.
If you wish to draw a hexagon to the screen, you must first use cube_to_pixel
If you wish to draw a hexagon to the screen, you must first use hex_to_pixel
to retrieve the center of the hexagon on each set of cube coordinates stored to retrieve the center of the hexagon on each set of cube coordinates stored
in your map. Then, depending on how you are going to draw, either call in your map. Then, depending on how you are going to draw, either call
am.circle with |sides| = 6, or gather the vertices with hex_corners and am.circle with |sides| = 6, or gather the vertices with hex_corners and
@ -143,17 +142,16 @@ end
----- NOISE ----- ----- NOISE -----
To simplify terrain generation, unordered, hash-like maps automatically To simplify terrain generation, unordered, hash-like maps automatically
calculate and store perlin noise as their values. You can modify the nature
calculate and store simplex noise as their values. You can modify the nature
of the noise by providing different |frequencies| as a tables of values, for of the noise by providing different |frequencies| as a tables of values, for
example: {1, 2, 4, 8} or {1, 0.5, 0.25, 0.125}. These just increase the example: {1, 2, 4, 8} or {1, 0.5, 0.25, 0.125}. These just increase the
complexity of the curvature of the noise. The default is {1}. complexity of the curvature of the noise. The default is {1}.
----- TODO ----- ----- TODO -----
TODO make all functions work regardless of layout. as it stands, they kind
make all functions work regardless of layout. as it stands, they kind
of do, just not always nicely. of do, just not always nicely.
============================================================================]]-- ============================================================================]]--
----- ORDERED MAPS -----
-- returns ordered ring-shaped map of |radius| from |center|. -- returns ordered ring-shaped map of |radius| from |center|.
function ring_map(center, radius) function ring_map(center, radius)
@ -162,21 +160,18 @@ function ring_map(center, radius)
setmetatable(map, mt) setmetatable(map, mt)
local walk = center + CUBE_DIRECTIONS[6] * radius
local walk = center + HEX_DIRECTIONS[6] * radius
for i = 1, 6 do for i = 1, 6 do
for j = 1, radius do for j = 1, radius do
table.insert(map, walk) table.insert(map, walk)
walk = cube_neighbour(walk, i)
walk = hex_neighbour(walk, i)
end end
end end
return map return map
end end
-- returns ordered hexagonal map of |radius| rings from |center|.
-- the only difference between spiral_map and hexagonal_map is that
-- spiral_map is ordered, in a spiral path from the |center|.
-- returns ordered spiral hexagonal map of |radius| rings from |center|.
function spiral_map(center, radius) function spiral_map(center, radius)
local map = {center} local map = {center}
local mt = {__index={center=center, radius=radius}} local mt = {__index={center=center, radius=radius}}
@ -189,42 +184,67 @@ function spiral_map(center, radius)
return map return map
end end
----- UNORDERED, HASH-LIKE MAPS -----
-- returns unordered parallelogram-shaped map of |width| and |height| with perlin noise
function parallelogram_map(width, height)
-- returns unordered parallelogram-shaped map of |width| and |height| with simplex noise
function parallelogram_map(width, height, frequencies)
local map = {} local map = {}
local mt = {__index={width=width, height=height}}
local mt = {__index={width=width, height=height, frequencies=frequencies}}
local frequencies = frequencies or {1}
setmetatable(map, mt) setmetatable(map, mt)
for i = 0, width do for i = 0, width do
for j = 0, height do for j = 0, height do
map[vec2(i, j)] = true
-- calculate noise
local idelta = assert(i / width, "width must be greater than 0")
local jdelta = assert(j / height, "height must be greater than 0")
local noise = 0
for _,freq in pairs(frequencies) do
noise = noise
+ assert(1/freq, "frequencies must be non-zero")
* math.simplex(vec2(freq * idelta, freq * jdelta))
end
-- straightforward iteration produces a parallelogram
map[vec2(i, j)] = noise
end end
end end
return map return map
end end
-- returns unordered triangular map of |size| with perlin noise
function triangular_map(size)
-- returns unordered triangular map of |size| with simplex noise
function triangular_map(size, frequencies)
local map = {} local map = {}
local mt = {__index={size=size}}
local mt = {__index={size=size, frequencies=frequencies}}
local frequencies = frequencies or {1}
setmetatable(map, mt) setmetatable(map, mt)
for i = 0, size do for i = 0, size do
for j = size - s, size do
map[vec2(i, j)] = true
for j = size - i, size do
-- calculate noise
local idelta = assert(i / size, "size must be greater than 0")
local jdelta = assert(j / -size, "size must be greater than 0")
local noise = 0
for _,freq in pairs(frequencies) do
noise = noise
+ assert(1/freq, "frequencies must be non-zero")
* math.simplex(vec2(freq * idelta, freq * jdelta))
end
map[vec2(i, j)] = noise
end end
end end
return map return map
end end
-- returns unordered hexagonal map of |radius| with perlin noise
function hexagonal_map(radius)
-- returns unordered hexagonal map of |radius| with simplex noise
function hexagonal_map(radius, frequencies)
local map = {} local map = {}
local mt = {__index={radius=radius}}
local mt = {__index={radius=radius, frequencies=frequencies}}
local frequencies = frequencies or {1}
setmetatable(map, mt) setmetatable(map, mt)
@ -233,17 +253,30 @@ function hexagonal_map(radius)
local j2 = math.min(radius, -i + radius) local j2 = math.min(radius, -i + radius)
for j = j1, j2 do for j = j1, j2 do
map[vec2(i, j)] = true
-- calculate noise
local idelta = assert(i / radius*2, "radius must be greater than 0")
local jdelta = assert(j / (j2-j1), "radius must be greater than 0")
local noise = 0
for _,freq in pairs(frequencies) do
noise = noise
+ assert(1/freq, "frequencies must be non-zero")
* math.perlin(vec2(freq * idelta, freq * jdelta))
end
-- populate
map[vec2(i, j)] = noise
end end
end end
return map return map
end end
-- returns unordered rectangular map of |width| and |height| with perlin noise
-- returns unordered rectangular map of |width| and |height| with simplex noise
function rectangular_map(width, height, frequencies) function rectangular_map(width, height, frequencies)
local map = {} local map = {}
local mt = {__index={width=width, height=height}}
local mt = {__index={width=width, height=height, frequencies=frequencies}}
local frequencies = frequencies or {1} local frequencies = frequencies or {1}
setmetatable(map, mt) setmetatable(map, mt)
@ -257,42 +290,18 @@ function rectangular_map(width, height, frequencies)
local noise = 0 local noise = 0
for _,freq in pairs(frequencies) do for _,freq in pairs(frequencies) do
noise = noise + 1/freq * math.perlin(vec2(freq * idelta,
freq * jdelta))
noise = noise
+ assert(1/freq, "frequencies must be non-zero")
* math.simplex(vec2(freq * idelta, freq * jdelta))
end end
-- this is what makes it a rectangle
local hex = vec2(i, j - math.floor(i/2))
-- store hex in the map paired with its associated noise value -- store hex in the map paired with its associated noise value
map[hex] = noise
map[vec2(i, j - math.floor(i/2))] = noise
end end
end end
return map return map
end end
--[[============================================================================
----- NOISE -----
============================================================================]]--
function simplex_map(frequency, exponent, width, height)
local map = {}
for i = 0, height do
for j = 0, width do
local idelta = i/width - 0.5
local jdelta = j/height - 0.5
map[vec2(i, j)] = math.simplex(idelta, jdelta)
end
end
end
--[[============================================================================ --[[============================================================================
----- PATHFINDING ----- ----- PATHFINDING -----
============================================================================]]-- ============================================================================]]--

96
main.lua → src/main.lua

@ -1,10 +1,8 @@
require"hex" require"hex"
require"util"
require"sprites"
--[[============================================================================ --[[============================================================================
----- COLOR CONSTANTS -----
----- COLOR CONSTANTS -----
============================================================================]]-- ============================================================================]]--
local EIGENGRAU = vec4(0.08, 0.08, 0.11, 1) local EIGENGRAU = vec4(0.08, 0.08, 0.11, 1)
@ -48,21 +46,23 @@ am.ascii_color_map =
} }
--[[============================================================================ --[[============================================================================
----- SETUP -----
----- SETUP -----
============================================================================]]-- ============================================================================]]--
local win = am.window local win = am.window
{ -- base resolution = 3/4 * WXGA standard 16:10
{
-- base resolution = 3/4 * WXGA standard 16:10
width = 1280 * 3/4, -- 960px width = 1280 * 3/4, -- 960px
height = 800 * 3/4, -- 600px height = 800 * 3/4, -- 600px
clear_color = BASE03 clear_color = BASE03
} }
local map = rectangular_map(45, 31)
local layout = layout(vec2(-268, win.top - 10))
local map = rectangular_map(45, 31, {2, 4, 8})
local layout = layout(vec2(-268, win.bottom))
local home = hex_to_pixel(vec2(23, 4), layout)
--[[============================================================================ --[[============================================================================
----- SCENE GRAPH / NODES -----
----- SCENE GRAPH / NODES -----
============================================================================]]-- ============================================================================]]--
local panel; local world; local game --[[ local panel; local world; local game --[[
@ -82,17 +82,19 @@ local backdrop; local menu; local title --[[
menu menu
--[[============================================================================ --[[============================================================================
----- FUNCTIONS -----
----- FUNCTIONS -----
============================================================================]]-- ============================================================================]]--
--
function keep_time() function keep_time()
local offset = am.current_time() local offset = am.current_time()
world:action(function()
world:remove("time")
game:action(function()
game:remove("time")
local time_str = string.format("%.2f", am.current_time() - offset) local time_str = string.format("%.2f", am.current_time() - offset)
world:append(
game:append(
am.translate(-374, win.top - 10) am.translate(-374, win.top - 10)
^ am.text(time_str):tag"time") ^ am.text(time_str):tag"time")
end) end)
@ -104,34 +106,35 @@ function show_coords()
game:remove("coords") game:remove("coords")
game:remove("selected") game:remove("selected")
local hex = pixel_to_cube(win:mouse_position(), layout)
local mouse = cube_to_offset(hex)
local hex = pixel_to_hex(win:mouse_position(), layout)
local mouse = hex_to_offset(hex)
-- check mouse is within bounds of game map -- check mouse is within bounds of game map
if mouse.x > 0 and mouse.x < map.width and if mouse.x > 0 and mouse.x < map.width and
mouse.y > 0 and mouse.y < map.height then
-mouse.y > 0 and -mouse.y < map.height then -- north is positive
local text = am.text(string.format("%d,%d", mouse.x, mouse.y)) local text = am.text(string.format("%d,%d", mouse.x, mouse.y))
local coords = am.group{ local coords = am.group{
am.translate(win.right - 25, win.top - 10) am.translate(win.right - 25, win.top - 10)
^ am.text(string.format("%d,%d", mouse.x, mouse.y)):tag"coords"}
^ am.text(string.format("%d,%d", mouse.x,-mouse.y)):tag"coords"}
world:append(coords) world:append(coords)
local color = vec4(1)
local pix = cube_to_pixel(hex, layout)
local color = vec4(0, 0, 0, 0.2)
local pix = hex_to_pixel(hex, layout)
world:append(am.circle(pix, layout.size.x, color, 6):tag"selected") world:append(am.circle(pix, layout.size.x, color, 6):tag"selected")
end end
end) end)
end end
--
function title_init() function title_init()
backdrop = am.group{}:tag"backdrop" backdrop = am.group{}:tag"backdrop"
menu = am.group{}:tag"menu" menu = am.group{}:tag"menu"
title = am.group{menu, backdrop}:tag"title" title = am.group{menu, backdrop}:tag"title"
end end
--
function game_init() function game_init()
-- setup nodes -- setup nodes
world = am.group{}:tag"world" world = am.group{}:tag"world"
@ -148,34 +151,65 @@ function game_init()
for hex,noise in pairs(map) do for hex,noise in pairs(map) do
-- determine cell color based on noise -- determine cell color based on noise
local color = vec4((noise + 1) / 2)
local color
-- impassable
if noise < -0.5 then
color = vec4(0.10, 0.30, 0.20, (noise + 1) / 2)
-- passable
elseif noise < 0 then
color = vec4(0.10, 0.25, 0.05, (noise + 1.9) / 2)
-- passable
elseif noise < 0.5 then
color = vec4(0.25, 0.20, 0.10, (noise + 1.9) / 2)
-- impassable
else
color = vec4(0.10, 0.30, 0.20, (noise + 1) / 2)
end
-- determine cell shading mask based on map position -- determine cell shading mask based on map position
local off = cube_to_offset(hex)
local mask = vec4(0, 0, 0, math.max(((off.x-23)/30)^2,
((off.y-16)/20)^2))
local off = hex_to_offset(hex)
local mask = vec4(0, 0, 0, math.max(((off.x-23)/45)^2,
((-off.y-16)/31)^2))
color = color - mask
-- determine hexagon center for drawing -- determine hexagon center for drawing
local center = cube_to_pixel(hex, layout)
local center = hex_to_pixel(hex, layout)
-- prepend hexagon to screen -- prepend hexagon to screen
world:prepend(am.circle(center, 11, color, 6):tag(tostring(hex))) world:prepend(am.circle(center, 11, color, 6):tag(tostring(hex)))
am.wait(am.delay(0.01))
-- fade in bg panel -- fade in bg panel
panel"bg".color = BASE03/am.frame_time
panel"bg".color = BASE03
-- sleep
--am.wait(am.delay(0.01))
end end
-- home base
world:append(am.translate(home)
^ am.rotate(0):tag"homer"
^ am.circle(vec2(0), 22, ORANGE, 3)):tag"home"
world:append(am.translate(home)
^ am.rotate(60):tag"homer2"
^ am.circle(vec2(0), 22, YELLOW, 3)):tag"home"
world:action(function()
world"homer".angle = am.frame_time / 6
world"homer2".angle = am.frame_time / 3
end)
show_coords() -- mouse-hover events show_coords() -- mouse-hover events
keep_time() -- scoring keep_time() -- scoring
end)) end))
-- make it so
win.scene = game
win.scene = game -- make it so
end end
--[[============================================================================ --[[============================================================================
----- MAIN -----
----- MAIN -----
============================================================================]]-- ============================================================================]]--
game_init() game_init()
Loading…
Cancel
Save