Browse Source

pathfinding is now functional. added screen transition.

master
churchianity 5 years ago
parent
commit
3a5e5e2c5d
  1. 16
      src/hexyz.lua
  2. 158
      src/main.lua

16
src/hexyz.lua

@ -6,11 +6,6 @@ local function round(n) return n % 1 >= 0.5 and math.ceil(n) or math.floor(n) en
----- HEX CONSTANTS AND UTILITY FUNCTIONS -----
============================================================================]]--
-- Hex Equality - Meant to Operate on two Amulet Vectors (vec2)
function hex_equals(a, b) return a[1] == b[1] and a[2] == b[2] end
function hex_not_equals(a, b) return not hex_equals(a, b) end
-- 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)}
@ -113,7 +108,7 @@ end
-- Offset Coordinates Look Nice / are Useful for UI-Implementations
function hex_to_offset(hex)
return vec2(hex[1], -hex[1]-hex[2] + (hex[1] + (hex[1] % 2)) / 2) end
return vec2(hex[1], -hex[1] - hex[2] + (hex[1] + (hex[1] % 2)) / 2) end
-- ... Back to Cube Coordinates
@ -157,7 +152,7 @@ end
-- Used to Retrieve Noise Values in Hashmap; t[vec2(x, y)] will always find nil
function hash_retrieve(map, hex)
for h,n in pairs(map) do
if hex_equals(hex, h) then
if hex == h then
return n
end
end
@ -224,7 +219,6 @@ function hexagonal_map(radius, seed)
local seed = seed or math.random(radius * 2 * math.pi)
local map = {}
local mt = {__index={radius=radius, seed=seed}}
for i = -radius, radius do
local j1 = math.max(-radius, -i - radius)
local j2 = math.min(radius, -i + radius)
@ -245,7 +239,7 @@ function hexagonal_map(radius, seed)
map[vec2(i, j)] = noise
end
end
setmetatable(map, mt)
setmetatable(map, {__index={radius=radius, seed=seed}})
return map
end
@ -255,8 +249,6 @@ function rectangular_map(width, height, seed)
local seed = seed or math.random(width * height)
local map = {}
local mt = {__index={width=width, height=height, seed=seed}}
for i = 0, width do
for j = 0, height do
@ -274,7 +266,7 @@ function rectangular_map(width, height, seed)
map[vec2(i, j - math.floor(i/2))] = noise
end
end
setmetatable(map, mt)
setmetatable(map, {__index={width=width, height=height, seed=seed}})
return map
end

158
src/main.lua

@ -1,29 +1,60 @@
require"hexyz"
math.randomseed(os.time())
math.randomseed(os.time()); math.random(); math.random(); math.random()
local win = am.window
win = am.window
{
-- Base Resolution = 3/4 * WXGA standard 16:10
width = 1280 * 3/4, -- 960px
height = 800 * 3/4, -- 600px
resizable = false,
clear_color = vec4(0.08, 0.08, 0.11, 1)
}
local bias = "right"
local map
local world
local home
local home_node
function find_home()
home = spiral_map(vec2(23, 4), 2)
function keep_score()
local offset = am.current_time()
local score = am.text(string.format("%.2f", am.current_time()))
win.scene:append(am.translate(-380, 290) ^ score)
win.scene:action(function()
score.text = string.format("%.2f", am.current_time())
end)
end
function show_hex_coords()
local hex = pixel_to_hex(win:mouse_position(), vec2(11))
local off = hex_to_offset(hex)
local coords = am.text(string.format("%d,%d", off.x, off.y))
win.scene:append(am.translate(380, 280) ^ coords
:action(function()
local hex = pixel_to_hex(win:mouse_position(), vec2(11))
local off = hex_to_offset(hex)
coords.text = string.format("%d,%d", off.x, off.y)
end))
end
function explosion(position, size, color, color_var, sound) end
-- 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()
repeat
local happy = true
for i,h in pairs(home) do
local elevation = hash_retrieve(map, h)
if not elevation then -- hex not in map
@ -31,12 +62,12 @@ function find_home()
happy = false
elseif not happy then
home = spiral_map(h, 2)
home = spiral_map(vec2(23, 4), preferred_radius or 2)
home_node = am.group()
else
local center = hex_to_pixel(h, vec2(11))
local color = vec4(0.5)
local color = vec4(1, 0, 0.5, 1)
local node = am.circle(center, 4, color, 4)
home_node:append(node)
end
@ -46,6 +77,7 @@ function find_home()
end
-- map elevation to appropriate tile color.
function color_at(elevation)
if elevation < -0.5 then -- Lowest Elevation : Impassable
return vec4(0.10, 0.30, 0.40, (elevation + 1.4) / 2 + 0.2)
@ -58,41 +90,53 @@ function color_at(elevation)
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.5, 0.5, 0.5, 1)
end
end
function draw_(map)
function cartograph()
map = rectangular_map(46, 33); math.randomseed(map.seed)
world = am.group()
for hex,elevation in pairs(map) do
-- subtle shading for map edges. unnecessary, really.
local off = hex_to_offset(hex)
local mask = vec4(0, 0, 0, math.max(((off.x - 23.5) / 46) ^ 2,
((-off.y - 16.5) / 32) ^ 2))
local color = color_at(elevation) - mask
local node = am.circle(hex_to_pixel(hex, vec2(11)), 11, vec4(0), 6)
:action(am.tween(5, {color = color}, am.ease.out(am.ease.hyperbola)))
world:append(node:tag(tostring(hex)))
:action(am.tween(5, {color=color}, am.ease.out(am.ease.hyperbola)))
world:append(node)
end
world:append(find_home())
return am.translate(-278, -318) ^ world:tag"world"
if bias == "right" then
win.scene:prepend(am.translate(-278, -318) ^ world)
win.scene:action(am.tween(win.scene"curtain", 1, {x2 = -268}, am.ease.bounce))
elseif bias == "left" then
win.scene:prepend(am.translate(-480, -318) ^ world)
win.scene:action(am.tween(win.scene"curtain", 1, {x1 = 268}, am.ease.bounce))
else
error("invalid bias")
end
world:action(spawner)
end
-- determines when, where, and how often to spawn mobs.
function spawner(world)
if math.random(10) == 1 then -- chance to spawn
if math.random(25) == 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)
if math.random() < 0.5 then
x = math.random(0, 1) * 47
x = math.random(0, 1) * 46
else
y = math.random(0, 1) * 33
end
@ -102,37 +146,69 @@ function spawner(world)
local e = hash_retrieve(map, spawn_position)
until e and e < 0.5 and e > -0.5
local mob = am.circle(hex_to_pixel(spawn_position, vec2(11)), 4, vec4(1), 6)
:action(coroutine.create(function(mob)
local dead = false
repeat
local neighbours = hex_neighbours(pixel_to_hex(mob.center, vec2(11)))
local candidates = {}
for _,h in pairs(neighbours) do
local e = hash_retrieve(map, h)
if e and e < 0.5 and e > -0.5 then
table.insert(candidates, h)
end
end
local move = candidates[math.random(#candidates)]
am.wait(am.tween(mob, 1, {center=hex_to_pixel(move, vec2(11))}))
until dead
end))
world:append(mob)
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
world:append(mob"circle":action(coroutine.create(live)))
end
end
function game_init(seed)
local bg = am.rect(-480, 300, -268, -300, vec4(0.12, 0.3, 0.3, 1))
map = rectangular_map(46, 33)
-- This function is the coroutine that represents the life-cycle of a mob.
function live(mob)
local dead = false
math.randomseed(map.seed)
win.scene = am.group(draw_(map):action(spawner), bg)
end
local visited = {}; visited[mob.center] = true
-- begin life
repeat
local neighbours = hex_neighbours(pixel_to_hex(mob.center, vec2(11)))
local candidates = {}
-- get list of candidates: hex positions to consider moving to.
for _,h in pairs(neighbours) do
local e = hash_retrieve(map, h)
if e and e < 0.5 and e > -0.5 then
if not hash_retrieve(visited, h) then
table.insert(candidates, h)
end
end
end
-- choose where to move. manhattan distance closest to goal is chosen.
local move = candidates[1]
for _,h in pairs(candidates) do
if math.distance(h, home.center) < math.distance(move, home.center) then
move = h
end
end
if not move then return true --error("can't find anywhere to move to")
end -- bug
local speed = (hash_retrieve(map, move)) ^ 2 + 0.5
am.wait(am.tween(mob, speed, {center=hex_to_pixel(move, vec2(11))}))
visited[move] = true
if move == home.center then dead = true end
until dead
explosion(mob.center)
end
--
game_init()
function init()
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
win.scene = am.group(bg)
cartograph()
end
init()
Loading…
Cancel
Save