Nicholas Hayashi
4 years ago
6 changed files with 471 additions and 436 deletions
-
15src/colors.lua
-
78src/grid.lua
-
9src/gui.lua
-
89src/hexyz.lua
-
267src/main.lua
-
77src/mob.lua
@ -0,0 +1,15 @@ |
|||||
|
|
||||
|
COLORS = { |
||||
|
TRANSPARENT = vec4(0.4), |
||||
|
--TRANSPARENT = vec4(0.6), |
||||
|
|
||||
|
WHITE = vec4(0.8, 0.8, 0.7, 1), |
||||
|
BLACK = vec4(0, 0, 0, 1), |
||||
|
|
||||
|
-- hues |
||||
|
BLUE_STONE = vec4(0.12, 0.3, 0.3, 1), |
||||
|
MYRTLE = vec4(0.10, 0.25, 0.10, 1), |
||||
|
BROWN_POD = vec4(0.25, 0.20, 0.10, 1), |
||||
|
BOTTLE_GREEN = vec4(0.15, 0.30, 0.20, 1) |
||||
|
} |
||||
|
|
@ -0,0 +1,78 @@ |
|||||
|
|
||||
|
require "colors" |
||||
|
|
||||
|
local WORLD_GRID_DIMENSIONS = vec2(46, 32) |
||||
|
local world_grid_map |
||||
|
|
||||
|
-- ensure home-base is somewhat of an open area. |
||||
|
function find_home(preferred_radius) |
||||
|
home = spiral_map(vec2(23, 4), preferred_radius or 2) |
||||
|
local home_node = am.group() |
||||
|
|
||||
|
repeat |
||||
|
local happy = true |
||||
|
|
||||
|
for i,h in pairs(home) do |
||||
|
local elevation = map[h.x][h.y] |
||||
|
|
||||
|
if not elevation then -- hex not in map |
||||
|
elseif elevation > 0.5 or elevation < -0.5 then |
||||
|
happy = false |
||||
|
|
||||
|
elseif not happy then |
||||
|
home = spiral_map(h, preferred_radius or 1) |
||||
|
home_node = am.group() |
||||
|
|
||||
|
else |
||||
|
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) |
||||
|
end |
||||
|
end |
||||
|
until happy |
||||
|
return home_node |
||||
|
end |
||||
|
|
||||
|
-- map elevation to appropriate tile color. |
||||
|
function color_at(elevation) |
||||
|
if elevation < -0.5 then -- lowest elevation : impassable |
||||
|
return COLORS.BLUE_STONE{ a = (elevation + 1.4) / 2 + 0.2 } |
||||
|
|
||||
|
elseif elevation < 0 then -- med-low elevation : passable |
||||
|
return COLORS.MYRTLE{ a = (elevation + 1.8) / 2 + 0.2 } |
||||
|
|
||||
|
elseif elevation < 0.5 then -- med-high elevation : passable |
||||
|
return COLORS.BROWN_POD{ a = (elevation + 1.6) / 2 + 0.2 } |
||||
|
|
||||
|
elseif elevation < 1 then -- highest elevation : impassable |
||||
|
return COLORS.BOTTLE_GREEN{ a = (elevation + 1.0) / 2 + 0.2 } |
||||
|
end |
||||
|
end |
||||
|
|
||||
|
function random_map(seed) |
||||
|
world_grid_map = rectangular_map(WORLD_GRID_DIMENSIONS.x, WORLD_GRID_DIMENSIONS.y, seed); |
||||
|
math.randomseed(world_grid_map.seed) |
||||
|
local world = am.translate(vec2(win.left + 200, win.bottom -60)) ^ am.group():tag"world" |
||||
|
|
||||
|
for i,_ in pairs(world_grid_map) do |
||||
|
for j,elevation in pairs(world_grid_map[i]) do |
||||
|
|
||||
|
-- subtly shade map edges |
||||
|
local off = hex_to_offset(vec2(i, j)) |
||||
|
local mask = vec4(0, 0, 0, math.max(((off.x - WORLD_GRID_DIMENSIONS.x/2) / WORLD_GRID_DIMENSIONS.x) ^ 2, |
||||
|
((-off.y - WORLD_GRID_DIMENSIONS.y/2) / WORLD_GRID_DIMENSIONS.y) ^ 2)) |
||||
|
local color = color_at(elevation) - mask |
||||
|
|
||||
|
local node = am.circle(hex_to_pixel(vec2(i, j)), get_default_hex_size(), vec4(0), 6) |
||||
|
:action(am.tween(2, { color=color }, am.ease.out(am.ease.hyperbola))) |
||||
|
|
||||
|
world:append(node) |
||||
|
end |
||||
|
end |
||||
|
--world:append(find_home(2)) |
||||
|
--world:action(spawner) |
||||
|
return world:tag"world" |
||||
|
end |
||||
|
|
||||
|
|
@ -0,0 +1,9 @@ |
|||||
|
|
||||
|
local hot |
||||
|
local active |
||||
|
|
||||
|
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 |
||||
|
|
@ -0,0 +1,77 @@ |
|||||
|
|
||||
|
|
||||
|
|
||||
|
-- determines when, where, and how often to spawn mobs. |
||||
|
function spawner(world) |
||||
|
local SPAWN_CHANCE = 25 |
||||
|
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) |
||||
|
if math.random() < 0.5 then |
||||
|
x = math.random(0, 1) * 46 |
||||
|
else |
||||
|
y = math.random(0, 1) * 33 |
||||
|
end |
||||
|
spawn_position = offset_to_hex(vec2(x, y)) |
||||
|
|
||||
|
-- ensure that we spawn somewhere that is passable: mid-elevation |
||||
|
local e = map[spawn_position.x][spawn_position.y] |
||||
|
until e and e < 0.5 and e > -0.5 |
||||
|
|
||||
|
local mob = am.translate(-278, -318) ^ am.circle(hex_to_pixel(spawn_position), 4) |
||||
|
world:append(mob"circle":action(coroutine.create(live))) |
||||
|
end |
||||
|
end |
||||
|
|
||||
|
-- this function is the coroutine that represents the life-cycle of a mob. |
||||
|
function live(mob) |
||||
|
local dead = false |
||||
|
|
||||
|
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)) |
||||
|
local candidates = {} |
||||
|
|
||||
|
-- get list of candidates: hex positions to consider moving to. |
||||
|
for _,h in pairs(neighbours) do |
||||
|
|
||||
|
local e |
||||
|
if map[h.x] then |
||||
|
e = map[h.x][h.y] |
||||
|
end |
||||
|
|
||||
|
if e and e < 0.5 and e > -0.5 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 |
||||
|
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 print("can't find anywhere to move to"); return |
||||
|
end -- bug |
||||
|
|
||||
|
local speed = map[move.x][move.y] ^ 2 + 0.5 |
||||
|
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 |
||||
|
win.scene:remove(mob) |
||||
|
end |
||||
|
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue