10 changed files with 335 additions and 253 deletions
			
			
		- 
					2README.md
- 
					BINres/wall_closed.png
- 
					BINres/wall_open.png
- 
					6src/colors.lua
- 
					99src/grid.lua
- 
					54src/gui.lua
- 
					51src/hexyz.lua
- 
					155src/main.lua
- 
					131src/mob.lua
- 
					14src/util.lua
| After Width: 138 | Height: 138 | Size: 2.0 KiB | 
| After Width: 137 | Height: 137 | Size: 1.8 KiB | 
| @ -1,15 +1,17 @@ | |||
| 
 | |||
| COLORS = { | |||
|     TRANSPARENT = vec4(0.4), | |||
|     --TRANSPARENT = vec4(0.6), | |||
| 
 | |||
|     -- tones | |||
|     WHITE = vec4(0.8, 0.8, 0.7, 1), | |||
|     BLACK = vec4(0, 0, 0, 1), | |||
|     TRUEBLACK = 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) | |||
|     BOTTLE_GREEN = vec4(0.15, 0.30, 0.20, 1), | |||
|     MAGENTA = vec4(1, 0, 1, 1) | |||
| } | |||
| 
 | |||
| @ -1,9 +1,53 @@ | |||
| 
 | |||
| local hot | |||
| local active | |||
| local hot, active = false, false | |||
| local widgets = {} | |||
| 
 | |||
| 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) | |||
| function get_widgets() return widgets end | |||
| 
 | |||
| function register_widget(id, poll) | |||
|     widgets[id] = { id = id, poll = poll } | |||
| end | |||
| 
 | |||
| function point_in_rect(point, rect) | |||
|     return point.x > rect.x1 and point.x < rect.x2 and point.y > rect.y1 and point.y < rect.y2 | |||
| end | |||
| 
 | |||
| function set_hot(id) | |||
|     if not active then hot = { id = id } end | |||
| end | |||
| 
 | |||
| function register_button_widget(id, rect) | |||
|     register_widget(id, function() | |||
|         local click = false | |||
| 
 | |||
|         if active and active.id == id then | |||
|             if win:mouse_released"left" then | |||
|                 if hot and hot.id == id then click = true end | |||
|                 active = false | |||
|             end | |||
|         elseif hot and hot.id == id then | |||
|             if win:mouse_pressed"left" then active = { id = id } end | |||
|         end | |||
| 
 | |||
|         if point_in_rect(win:mouse_position(), rect) then set_hot(id) end | |||
| 
 | |||
|         return click | |||
|     end) | |||
| end | |||
| 
 | |||
| function make_button_widget(id, position, dimensions, text) | |||
|     local rect = am.rect( | |||
|         -dimensions.x/2, | |||
|         dimensions.y/2, | |||
|         dimensions.x/2, | |||
|         -dimensions.y/2, | |||
|         vec4(1, 0, 0, 1) | |||
|     ) | |||
| 
 | |||
|     register_button_widget(id, rect) | |||
|     return am.group{ | |||
|         rect, | |||
|         am.text(text) | |||
|     }:tag(id) | |||
| end | |||
| 
 | |||
| @ -1,79 +1,108 @@ | |||
| 
 | |||
| MOBS = {} | |||
| 
 | |||
| MOB_HURTBOX_RADIUS = 4 | |||
| -- check if a |tile| is passable by |mob| | |||
| function can_pass_through(mob, tile) | |||
|     return tile and tile.elevation and tile.elevation < 0.5 and tile.elevation > -0.5 | |||
| end | |||
| 
 | |||
| function get_path(mob, starting_hex, goal_hex) | |||
|     local moves = {} | |||
| 
 | |||
|     local visited = {} | |||
|     visited[starting_hex.x] = {} | |||
|     visited[starting_hex.x][starting_hex.y] = true | |||
| 
 | |||
| -- 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 | |||
|         local neighbours = hex_neighbours(pixel_to_hex(mob.position)) | |||
|         local candidates = {} | |||
| 
 | |||
|         -- get list of candidates: hex positions to consider moving to. | |||
|         for _,neighbour in pairs(neighbours) do | |||
|             if can_pass_through(mob, get_tile(neighbour.x, neighbour.y)) then | |||
|                 if not (visited[neighbour.h] and visited[neighbour.x][neighbour.y]) then | |||
|                     table.insert(candidates, neighbour) | |||
|                 else | |||
|                 y = math.random(0, 1) * 33 | |||
|                     --table.insert(candidates, neighbour) | |||
|                 end | |||
|             end | |||
|         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), MOB_HURTBOX_RADIUS) | |||
|         world:append(mob"circle":action(coroutine.create(live))) | |||
|         -- choose where to move | |||
|         local move = candidates[1] | |||
|         for _,hex in pairs(candidates) do | |||
|             if math.distance(hex, goal_hex) < math.distance(move, goal_hex) then | |||
|                 move = hex | |||
|             end | |||
|         end | |||
| 
 | |||
| -- this function is the coroutine that represents the life-cycle of a mob. | |||
| function live(mob) | |||
|     local dead = false | |||
|         if move then | |||
|             table.insert(moves, move) | |||
|             visited[move.x] = {} | |||
|             visited[move.x][move.y] = true | |||
|         end | |||
| 
 | |||
|     local visited = {} | |||
|     visited[mob.center.x] = {}; visited[mob.center.x][mob.center.y] = true | |||
|         --if move == goal then log('made it!') return end | |||
|     until move == goal_hex | |||
| 
 | |||
|     return moves | |||
| end | |||
| 
 | |||
|     -- begin life | |||
| function get_spawn_hex(mob) | |||
|     local spawn_hex | |||
|     repeat | |||
|         local neighbours = hex_neighbours(pixel_to_hex(mob.center)) | |||
|         local candidates = {} | |||
|         -- ensure we spawn on an random tile along the map's edges | |||
|         local roll = math.random(HEX_GRID_WIDTH * 2 + HEX_GRID_HEIGHT * 2) - 1 | |||
|         local x, y | |||
| 
 | |||
|         -- get list of candidates: hex positions to consider moving to. | |||
|         for _,h in pairs(neighbours) do | |||
|         if roll < HEX_GRID_HEIGHT then | |||
|             x, y = 0, roll | |||
| 
 | |||
|             local e | |||
|             if map[h.x] then | |||
|                 e = map[h.x][h.y] | |||
|             end | |||
|         elseif roll < (HEX_GRID_WIDTH + HEX_GRID_HEIGHT) then | |||
|             x, y = roll - HEX_GRID_HEIGHT, HEX_GRID_HEIGHT - 1 | |||
| 
 | |||
|         elseif roll < (HEX_GRID_HEIGHT * 2 + HEX_GRID_WIDTH) then | |||
|             x, y = HEX_GRID_WIDTH - 1, roll - HEX_GRID_WIDTH - HEX_GRID_HEIGHT | |||
| 
 | |||
|             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) | |||
|             x, y = roll - (HEX_GRID_HEIGHT * 2) - HEX_GRID_WIDTH, 0 | |||
|         end | |||
| 
 | |||
|         -- @NOTE negate 'y' because hexyz algorithms assume south is positive, in amulet north is positive | |||
|         spawn_hex = evenq_to_hex(vec2(x, -y)) | |||
|         local tile = HEX_MAP[spawn_hex.x][spawn_hex.y] | |||
| 
 | |||
|     until can_pass_through(mob, tile) | |||
| 
 | |||
|     return spawn_hex | |||
| end | |||
| 
 | |||
| function make_mob() | |||
|     local mob = {} | |||
| 
 | |||
|     local spawn_hex = get_spawn_hex(mob) | |||
|     log(spawn_hex) | |||
|     local spawn_position = hex_to_pixel(spawn_hex) + WORLDSPACE_COORDINATE_OFFSET | |||
| 
 | |||
|     mob.position = spawn_position | |||
|     --mob.path = get_path(mob, spawn_hex, HEX_GRID_CENTER) | |||
|     mob.sprite = am.circle(spawn_position, 18, COLORS.WHITE, 4) | |||
|     win.scene:append(mob.sprite) | |||
| 
 | |||
|     return mob | |||
| 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 | |||
| local SPAWN_CHANCE = 25 | |||
| function do_mob_spawning() | |||
|     if win:key_pressed"space" then | |||
|     --if math.random(SPAWN_CHANCE) == 1 then | |||
|         table.insert(MOBS, make_mob()) | |||
|     end | |||
| end | |||
| 
 | |||
|         if not move then print("can't find anywhere to move to"); return | |||
|         end -- bug | |||
| function do_mob_updates() | |||
|     for _,mob in pairs(MOBS) do | |||
| 
 | |||
|         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 | |||
| end | |||
| 
 | |||
| @ -0,0 +1,14 @@ | |||
| 
 | |||
| function table.shift(t, count) | |||
|     local e = t[1] | |||
|     t[1] = nil | |||
| 
 | |||
|     for i,e in pairs(t) do | |||
|         if e then | |||
|             t[i - 1] = e | |||
|         end | |||
|     end | |||
| 
 | |||
|     return e | |||
| end | |||
| 
 | |||
						Write
						Preview
					
					
					Loading…
					
					Cancel
						Save
					
		Reference in new issue