Browse Source

testing menus

master
churchianity 5 years ago
parent
commit
76a43946de
  1. 46
      src/hexyz.lua
  2. 211
      src/main.lua

46
src/hexyz.lua

@ -3,9 +3,9 @@
local function round(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) end
--[[============================================================================
----- HEX CONSTANTS AND UTILITY FUNCTIONS -----
============================================================================]]--
-- HEX CONSTANTS AND UTILITY FUNCTIONS
]]
-- All Non-Diagonal Vector Directions from a Given Hex by Edge
HEX_DIRECTIONS = {vec2( 1 , -1), vec2( 1 , 0), vec2(0 , 1),
vec2(-1 , 1), vec2(-1 , 0), vec2(0 , -1)}
@ -48,11 +48,10 @@ local function hex_round(x, y, z)
rz = -rx - ry end
return vec2(rx, ry)
end
--[[==========================================================================--
----- ORIENTATION & LAYOUT -----
============================================================================]]--
-- ORIENTATION & LAYOUT
]]
-- Forward & Inverse Matrices used for the Flat Orientation
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),
@ -64,11 +63,11 @@ local POINTY = {M = mat2(3.0^0.5, 3.0^0.5/2.0, 0.0, 3.0/2.0),
angle = 0.5}
-- Hex to Screen -- Orientation Must be Either POINTY or FLAT
function hex_to_pixel(hex, size, orientation_M, offset)
function hex_to_pixel(hex, size, orientation_M)
local M = orientation_M or FLAT.M
local x = (M[1][1] * hex[1] + M[1][2] * hex[2]) * size[1]
local y = (M[2][1] * hex[1] + M[2][2] * hex[2]) * size[2]
local x = (M[1][1] * hex[1] + M[1][2] * hex[2]) * (size and size[1] or 11)
local y = (M[2][1] * hex[1] + M[2][2] * hex[2]) * (size and size[2] or 11)
return vec2(x, y)
end
@ -78,7 +77,7 @@ end
function pixel_to_hex(pix, size, orientation_W)
local W = orientation_W or FLAT.W
local pix = pix / size
local pix = pix / (size or vec2(11))
local x = W[1][1] * pix[1] + W[1][2] * pix[2]
local y = W[2][1] * pix[1] + W[2][2] * pix[2]
@ -111,15 +110,14 @@ function hex_to_offset(hex)
return vec2(hex[1], -hex[1] - hex[2] + (hex[1] + (hex[1] % 2)) / 2) end
-- ... Back to Cube Coordinates
-- Back to Cube Coordinates
function offset_to_hex(off)
return vec2(off[1], off[2] - math.floor((off[1] - 1 * (off[1] % 2))) / 2) end
--[[============================================================================
----- MAPS & STORAGE -----
============================================================================]]--
-- MAPS & STORAGE
]]
-- Returns Ordered Ring-Shaped Map of |radius| from |center|
function ring_map(center, radius)
local map = {}
@ -149,23 +147,13 @@ function spiral_map(center, radius)
end
function hash_retrieve(map, entry)
for k,v in pairs(map) do
if k == entry then
return v
end
end
return nil
end
-- Returns Unordered Parallelogram-Shaped Map of |width| and |height| with Simplex Noise
function parallelogram_map(width, height, seed)
local seed = seed or math.random(width * height)
local map = {}
for i = 0, width do
map[i] = {}
for j = 0, height do
-- Calculate Noise
@ -179,7 +167,7 @@ function parallelogram_map(width, height, seed)
local pos = vec2(idelta + seed * width, jdelta + seed * height)
noise = noise + f * math.simplex(pos * l)
end
map[vec2(i, j)] = noise
map[i][j] = noise
end
end
setmetatable(map, {__index={width=width, height=height, seed=seed}})
@ -193,6 +181,7 @@ function triangular_map(size, seed)
local map = {}
for i = 0, size do
map[i] = {}
for j = size - i, size do
-- Generate Noise
@ -206,7 +195,7 @@ function triangular_map(size, seed)
local pos = vec2(idelta + seed * size, jdelta + seed * size)
noise = noise + f * math.simplex(pos * l)
end
map[vec2(i, j)] = noise
map[i][j] = noise
end
end
setmetatable(map, {__index={size=size, seed=seed}})
@ -220,6 +209,8 @@ function hexagonal_map(radius, seed)
local map = {}
for i = -radius, radius do
map[i] = {}
local j1 = math.max(-radius, -i - radius)
local j2 = math.min(radius, -i + radius)
@ -234,9 +225,10 @@ function hexagonal_map(radius, seed)
local f = 2/3^oct
local l = 2^oct
local pos = vec2(idelta + seed * radius, jdelta + seed * radius)
noise = noise + f * math.simplex(pos * l)
end
map[vec2(i, j)] = noise
map[i][j] = noise
end
end
setmetatable(map, {__index={radius=radius, seed=seed}})

211
src/main.lua

@ -2,30 +2,30 @@
require"hexyz"
math.randomseed(os.time()); math.random(); math.random(); math.random()
--[[============================================================================
function explosion(position, size, color, color_var, sound) end
]]
--
win = am.window
{ -- Base Resolution = 3/4 * WXGA standard 16:10
width = 1280 * 3/4, height = 800 * 3/4, -- 960px -- 600px
}
bias = "right"
state = {
score = 0,
{ -- Base Resolution = 3/4 * WXGA standard 16:10 -- 960px, 600px
width = 1280 * 3/4, height = 800 * 3/4,
clear_color = vec4(0.08, 0.08, 0.11, 1)
}
local map
local world
local home
local home_node
local spawn_chance = 25
--[[============================================================================
]]
-- ensure home-base is somewhat of an open area.
function find_home(preferred_radius)
home = spiral_map(vec2(23, 4), preferred_radius or 2)
home_node = am.group()
local home_node = am.group()
repeat
local happy = true
@ -42,7 +42,7 @@ function find_home(preferred_radius)
home_node = am.group()
else
local center = hex_to_pixel(h, vec2(11))
local center = hex_to_pixel(h)
local color = vec4(1, 0, 0.5, 1)
local node = am.circle(center, 4, color, 4)
home_node:append(node)
@ -55,26 +55,25 @@ end
-- map elevation to appropriate tile color.
function color_at(elevation)
if elevation < -0.5 then -- Lowest Elevation : Impassable
if elevation < -0.5 then -- lowest elevation : impassable
return vec4(0.10, 0.30, 0.40, (elevation + 1.4) / 2 + 0.2)
elseif elevation < 0 then -- Med-Low Elevation : Passable
elseif elevation < 0 then -- med-low elevation : passable
return vec4(0.10, 0.25, 0.10, (elevation + 1.8) / 2 + 0.2)
elseif elevation < 0.5 then -- Med-High Elevation : Passable
elseif elevation < 0.5 then -- med-high elevation : passable
return vec4(0.25, 0.20, 0.10, (elevation + 1.6) / 2 + 0.2)
elseif elevation < 1 then -- Highest Elevation : Impassable
elseif elevation < 1 then -- highest elevation : impassable
return vec4(0.15, 0.30, 0.20, (elevation + 1.0) / 2 + 0.2)
else
return vec4(0.6)
end
end
function cartograph()
map = rectangular_map(46, 33); math.randomseed(map.seed)
world = am.translate(vec2(-278, -318)) ^ am.group():tag"world"
--
function random_map(seed)
map = rectangular_map(46, 33, seed); math.randomseed(map.seed)
local world = am.translate(vec2(-278, -318)) ^ am.group():tag"world"
for i,_ in pairs(map) do
for j,elevation in pairs(map[i]) do
@ -85,25 +84,24 @@ function cartograph()
((-off.y - 16.5) / 32) ^ 2))
local color = color_at(elevation) - mask
local node = am.circle(hex_to_pixel(vec2(i, j), vec2(11)), 11, vec4(0), 6)
:action(am.tween(1, {color=color}, am.ease.out(am.ease.hyperbola)))
local node = am.circle(hex_to_pixel(vec2(i, j)), 11, vec4(0), 6)
:action(am.tween(2, {color=color}, am.ease.out(am.ease.hyperbola)))
world:append(node)
end
end
world:append(find_home())
world:append(find_home(2))
world:action(spawner)
return world
return world:tag"world"
end
-- determines when, where, and how often to spawn mobs.
function spawner(world)
if math.random(25) == 1 then -- chance to spawn
if math.random(spawn_chance) == 1 then -- chance to spawn
local spawn_position
repeat
-- ensure we spawn on an random tile along the map's edges
local x, y = math.random(46), math.random(33)
local x,y = math.random(46), math.random(33)
if math.random() < 0.5 then
x = math.random(0, 1) * 46
else
@ -115,13 +113,7 @@ function spawner(world)
local e = map[spawn_position.x][spawn_position.y]
until e and e < 0.5 and e > -0.5
local mob
if bias == "right" then
mob = am.translate(-278, -318) ^ am.circle(hex_to_pixel(spawn_position, vec2(11)), 4)
elseif bias == "left" then
mob = am.translate(-480, -318) ^ am.circle(hex_to_pixel(spawn_position, vec2(11)), 4)
end
local mob = am.translate(-278, -318) ^ am.circle(hex_to_pixel(spawn_position), 4)
world:append(mob"circle":action(coroutine.create(live)))
end
end
@ -131,11 +123,12 @@ end
function live(mob)
local dead = false
local visited = {}; visited[mob.center] = true
local visited = {}
visited[mob.center.x] = {}; visited[mob.center.x][mob.center.y] = true
-- begin life
repeat
local neighbours = hex_neighbours(pixel_to_hex(mob.center, vec2(11)))
local neighbours = hex_neighbours(pixel_to_hex(mob.center))
local candidates = {}
-- get list of candidates: hex positions to consider moving to.
@ -147,7 +140,11 @@ function live(mob)
end
if e and e < 0.5 and e > -0.5 then
if not hash_retrieve(visited, h) then
if visited[h.x] then
if not visited[h.x][h.y] then
table.insert(candidates, h)
end
else
table.insert(candidates, h)
end
end
@ -165,62 +162,134 @@ function live(mob)
end -- bug
local speed = map[move.x][move.y] ^ 2 + 0.5
am.wait(am.tween(mob, speed, {center=hex_to_pixel(move, vec2(11))}))
visited[move] = true
am.wait(am.tween(mob, speed, {center=hex_to_pixel(move)}))
visited[move.x] = {}; visited[move.x][move.y] = true
if move == home.center then dead = true end
until dead
explosion(mob.center)
win.scene:remove(mob)
end
--
function init()
local score = am.translate(-264, 290) ^ am.text("0", "left"):tag"score"
local coords = am.translate(440, 290) ^ am.text():tag"coords"
local bg = am.rect(win.left, win.top, win.right, win.bottom, vec4(0.12, 0.3, 0.3, 1)):tag"curtain"
-- -480, 300, -268, -300
main_scene = am.group
{
cartograph(),
bg,
score,
coords,
}
main_scene:append(am.circle(home.center, 11, vec4(0.4), 6):tag"selected")
function main_action(scene)
-- POLL MOUSE
function poll_mouse()
if win:mouse_position().x > -268 then -- mouse is inside game map
-- get info about mouse position
local hex = pixel_to_hex(win:mouse_position() - vec2(-278, -318), vec2(11))
local hex = pixel_to_hex(win:mouse_position() - vec2(-278, -318))
local off = hex_to_offset(hex)
-- check if cursor location outside of map bounds
if map[hex.x] == nil or map[hex.x][hex.y] == nil or off.x <= 1 or -off.y <= 1 or off.x >= 46 or -off.y >= 32 then
scene"coords".text = ""
if off.x <= 1 or -off.y <= 1 or off.x >= 46 or -off.y >= 32 then
win.scene"coords".text = ""
else
-- check if mouse clicked
if win:mouse_down"left" then
if win:mouse_down"left" then -- check if mouse clicked
if map[hex.x][hex.y] <= -0.5 or map[hex.x][hex.y] >= 0.5 then
else
map[hex.x][hex.y] = 2
world:append(am.circle(hex_to_pixel(hex, vec2(11)), 11, vec4(0.2, 0.2, 0.2, 1), 6))
win.scene"world":append(am.circle(hex_to_pixel(hex), 11, vec4(0, 0, 0, 1), 6))
end
end
scene"coords".text = string.format("%d,%d", off.x, -off.y)
scene"selected".center = hex_to_pixel(hex, vec2(11)) + vec2(-278, -318)
win.scene"coords".text = string.format("%2d,%2d", off.x, -off.y)
win.scene"selected".center = hex_to_pixel(hex) + vec2(-278, -318)
end
else -- mouse is over background bar, (or outside window!!!!)
if win:key_pressed"escape" then
init()
end
scene"score".text = string.format("SCORE: %.2f", am.current_time() + state.score)
end
main_scene:action(am.series
end
--
function update_score()
win.scene"score".text = string.format("SCORE: %.2f", am.current_time())
end
function update_mobs()
end
--
function button(x, y)
local color = (x + y) % 2 == 0 and vec4(0.4, 0.4, 0.5, 1) or vec4(0.5, 0.4, 0.4, 1)
return am.translate(x * 80, y * 80) ^ am.rect(-40, 40, 40, -40, color)
end
-- GAME INITIALIZATION FUNCTION
function game_init()
local score = am.translate(-264, 290) ^ am.text("", "left"):tag"score"
local coords = am.translate(440, 290) ^ am.text(""):tag"coords"
local selected = am.circle(vec2(win.left, win.top), 11, vec4(0.4), 6):tag"selected"
local bg = am.rect(win.left, win.top, win.right, win.bottom, vec4(0.12, 0.3, 0.3, 1)):tag"curtain"
local buttons = am.translate(-500, -300) ^ am.group()
for i = 1, 2 do
for j = 1, 6 do
buttons:append(button(i, j))
end
end
local main_scene = am.group{random_map(9), bg, buttons, score, coords, selected}
:action(am.series
{
am.tween(bg, 1, {x2 = -268}, am.ease.bounce),
main_action
am.tween(bg, 0.8, {x2 = -268}, am.ease.bounce), -- INTRO TRANSITION
function(scene) -- MAIN ACTION
update_score()
-- update mobs
-- update towers
-- update environment
poll_mouse() -- check if player did anything
end
})
win.scene = main_scene
end
-- TITLE SCREEN
function init()
local map = hexagonal_map(15, 9)
local backdrop = am.group()
for i,_ in pairs(map) do
for j,e in pairs(map[i]) do
backdrop:append(am.circle(hex_to_pixel(vec2(i, j)), 11, color_at(e), 6))
end
end
local title_text = am.group
{
am.translate(0, 200) ^ am.scale(5) ^ am.text("hexyz", vec4(0.8, 0.8, 0.7, 1), "right"),
am.translate(0, 130) ^ am.scale(4) ^ am.text("a tower defense", vec4(0.8, 0.8, 0.7, 1)),
am.circle(vec2(0), 100, vec4(0.6), 6):tag"b", am.scale(4) ^ am.text("START", vec4(0, 0, 0, 1))
}
win.scene = am.group
{
backdrop,
title_text
}
:action(function(s)
local mouse = win:mouse_position()
if math.length(mouse) < 100 then
s"b":action(am.series
{
am.tween(0.1, {color = vec4(0.8, 0.8, 0.7, 1)}),
am.tween(0.1, {color = vec4(0.6)})
})
if win:mouse_pressed"left" then
game_init()
end
end
end)
end
init()
noglobals()
Loading…
Cancel
Save