diff --git a/src/hexyz.lua b/src/hexyz.lua index 20c2eda..e366ac0 100644 --- a/src/hexyz.lua +++ b/src/hexyz.lua @@ -64,7 +64,7 @@ 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) +function hex_to_pixel(hex, size, orientation_M, offset) local M = orientation_M or FLAT.M local x = (M[1][1] * hex[1] + M[1][2] * hex[2]) * size[1] @@ -149,17 +149,17 @@ function spiral_map(center, radius) 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 == h then - return n +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) @@ -250,6 +250,7 @@ function rectangular_map(width, height, seed) local map = {} for i = 0, width do + map[i] = {} for j = 0, height do -- Begin to Calculate Noise @@ -263,7 +264,10 @@ function rectangular_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 - math.floor(i/2))] = noise + j = j - math.floor(i/2) -- this is what makes it rectangular + + -- store two dimensions as a single number + map[i][j] = noise end end setmetatable(map, {__index={width=width, height=height, seed=seed}}) diff --git a/src/main.lua b/src/main.lua index 68b0cc1..860b860 100644 --- a/src/main.lua +++ b/src/main.lua @@ -3,16 +3,18 @@ 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, -- 960px - height = 800 * 3/4, -- 600px - resizable = false, - clear_color = vec4(0.08, 0.08, 0.11, 1) +{ -- Base Resolution = 3/4 * WXGA standard 16:10 + width = 1280 * 3/4, height = 800 * 3/4, -- 960px -- 600px +} + +bias = "right" +state = { + score = 0, } -local bias = "right" local map local world @@ -20,32 +22,6 @@ local home local home_node -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) @@ -55,14 +31,14 @@ function find_home(preferred_radius) local happy = true for i,h in pairs(home) do - local elevation = hash_retrieve(map, h) + 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(vec2(23, 4), preferred_radius or 2) + home = spiral_map(h, preferred_radius or 1) home_node = am.group() else @@ -91,40 +67,33 @@ 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) + return vec4(0.6) end end 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) - end - world:append(find_home()) + world = am.translate(vec2(-278, -318)) ^ am.group():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)) + for i,_ in pairs(map) do + for j,elevation in pairs(map[i]) do - 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)) + -- subtly shade map edges + local off = hex_to_offset(vec2(i, j)) + 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 - else - error("invalid bias") + 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))) + world:append(node) + end end + world:append(find_home()) world:action(spawner) + + return world end @@ -143,7 +112,7 @@ function spawner(world) spawn_position = offset_to_hex(vec2(x, y)) -- ensure that we spawn somewhere that is passable: mid-elevation - local e = hash_retrieve(map, spawn_position) + local e = map[spawn_position.x][spawn_position.y] until e and e < 0.5 and e > -0.5 local mob @@ -158,7 +127,7 @@ function spawner(world) end --- This function is the coroutine that represents the life-cycle of a mob. +-- this function is the coroutine that represents the life-cycle of a mob. function live(mob) local dead = false @@ -172,7 +141,11 @@ function live(mob) -- get list of candidates: hex positions to consider moving to. for _,h in pairs(neighbours) do - local e = hash_retrieve(map, h) + 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 not hash_retrieve(visited, h) then table.insert(candidates, h) @@ -188,10 +161,10 @@ function live(mob) end end - if not move then return true --error("can't find anywhere to move to") + if not move then print("can't find anywhere to move to"); return end -- bug - local speed = (hash_retrieve(map, move)) ^ 2 + 0.5 + 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 if move == home.center then dead = true end @@ -199,15 +172,54 @@ function live(mob) explosion(mob.center) end + -- function init() - local bg = am.rect(win.left, win.top, win.right, win.bottom, vec4(0.12, 0.3, 0.3, 1)) - :tag"curtain" - + 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 - win.scene = am.group(bg) - cartograph() + 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) + -- get info about mouse position + local hex = pixel_to_hex(win:mouse_position() - vec2(-278, -318), vec2(11)) + 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 = "" + + else + -- check if mouse clicked + if win:mouse_down"left" then + 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)) + 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) + end + scene"score".text = string.format("SCORE: %.2f", am.current_time() + state.score) + end + main_scene:action(am.series + { + am.tween(bg, 1, {x2 = -268}, am.ease.bounce), + main_action + }) + win.scene = main_scene end init()