Browse Source

better debug stuff

master
Nicholas Hayashi 4 years ago
parent
commit
dc0eae52c2
  1. 1
      NOTES.md
  2. 28
      main.lua
  3. BIN
      res/boi.aseprite
  4. 10
      src/entity.lua
  5. 42
      src/grid.lua
  6. 17
      src/hexyz.lua
  7. 82
      src/mob.lua
  8. 11
      src/tower.lua

1
NOTES.md

@ -1,4 +1,5 @@
SEEED 1835 has bad start
todoooos & notes todoooos & notes

28
main.lua

@ -26,12 +26,15 @@ WIN = am.window{
height = 1080, height = 1080,
title = "hexyz", title = "hexyz",
highdpi = true, highdpi = true,
letterbox = true
letterbox = true,
clear_color = color_at(0)
} }
OFF_SCREEN = vec2(WIN.width * 2) -- arbitrary pixel position that is garunteed to be off screen OFF_SCREEN = vec2(WIN.width * 2) -- arbitrary pixel position that is garunteed to be off screen
WORLD = false -- root scene node of everything considered to be in the game world WORLD = false -- root scene node of everything considered to be in the game world
-- aka non gui stuff
TIME = 0 -- runtime of the current game in seconds (not whole program runtime) TIME = 0 -- runtime of the current game in seconds (not whole program runtime)
SCORE = 0 -- score of the player SCORE = 0 -- score of the player
MONEY = 0 -- available resources MONEY = 0 -- available resources
@ -52,7 +55,8 @@ local TRDTS = {
HEX = 2, HEX = 2,
PLATFORM = 3, PLATFORM = 3,
PERF = 4, PERF = 4,
SEED = 5
SEED = 5,
TILE = 6
} }
local TRDT = TRDTS.SEED local TRDT = TRDTS.SEED
@ -64,9 +68,10 @@ end
local function game_action(scene) local function game_action(scene)
if SCORE < 0 then game_end() end if SCORE < 0 then game_end() end
TIME = TIME + am.delta_time
TIME = TIME + am.delta_time
SCORE = SCORE + am.delta_time SCORE = SCORE + am.delta_time
MOUSE = WIN:mouse_position() MOUSE = WIN:mouse_position()
local mwd = WIN:mouse_wheel_delta()
local hex = pixel_to_hex(MOUSE - WORLDSPACE_COORDINATE_OFFSET) local hex = pixel_to_hex(MOUSE - WORLDSPACE_COORDINATE_OFFSET)
local rounded_mouse = hex_to_pixel(hex) + WORLDSPACE_COORDINATE_OFFSET local rounded_mouse = hex_to_pixel(hex) + WORLDSPACE_COORDINATE_OFFSET
@ -85,12 +90,23 @@ local function game_action(scene)
end end
end end
if WIN:mouse_pressed"middle" then
WIN.scene"scale".scale2d = vec2(1)
else
local small_mwd = vec2(mwd.y / 1000)
WIN.scene"scale".scale = WIN.scene"scale".scale + small_mwd
WIN.scene"scale".scale = WIN.scene"scale".scale + small_mwd
end
if WIN:key_pressed"escape" then if WIN:key_pressed"escape" then
game_end() game_end()
elseif WIN:key_pressed"f1" then elseif WIN:key_pressed"f1" then
TRDT = (TRDT + 1) % #table.keys(TRDTS) TRDT = (TRDT + 1) % #table.keys(TRDTS)
elseif WIN:key_pressed"f2" then
WORLD"priority_overlay".hidden = not WORLD"priority_overlay".hidden
elseif WIN:key_pressed"tab" then elseif WIN:key_pressed"tab" then
select_tower((SELECTED_TOWER_TYPE + 1) % #table.keys(TOWER_TYPE)) select_tower((SELECTED_TOWER_TYPE + 1) % #table.keys(TOWER_TYPE))
end end
@ -123,6 +139,9 @@ local function game_action(scene)
elseif TRDT == TRDTS.SEED then elseif TRDT == TRDTS.SEED then
str = "SEED: " .. HEX_MAP.seed str = "SEED: " .. HEX_MAP.seed
elseif TRDT == TRDTS.TILE then
str = table.tostring(HEX_MAP.get(hex.x, hex.y))
end end
WIN.scene"coords".text = str WIN.scene"coords".text = str
end end
@ -172,7 +191,6 @@ function game_scene()
local coords = am.translate(WIN.right - 10, WIN.top - 20) ^ am.text("", "right", "top"):tag"coords" local coords = am.translate(WIN.right - 10, WIN.top - 20) ^ am.text("", "right", "top"):tag"coords"
local hex_cursor = am.circle(OFF_SCREEN, HEX_SIZE, COLORS.TRANSPARENT, 6):tag"hex_cursor" local hex_cursor = am.circle(OFF_SCREEN, HEX_SIZE, COLORS.TRANSPARENT, 6):tag"hex_cursor"
local curtain = am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRUE_BLACK) local curtain = am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRUE_BLACK)
curtain:action(coroutine.create(function() curtain:action(coroutine.create(function()
am.wait(am.tween(curtain, 3, { color = vec4(0) }, am.ease.out(am.ease.hyperbola))) am.wait(am.tween(curtain, 3, { color = vec4(0) }, am.ease.out(am.ease.hyperbola)))
@ -198,6 +216,6 @@ function game_scene()
end end
load_textures() load_textures()
WIN.scene = game_scene()
WIN.scene = am.scale(vec2(1)) ^ game_scene()
noglobals() noglobals()

BIN
res/boi.aseprite

10
src/entity.lua

@ -17,7 +17,7 @@ entity structure:
function make_basic_entity(hex, node, update, position) function make_basic_entity(hex, node, update, position)
local entity = {} local entity = {}
entity.TOB = TIME
entity.TOB = TIME
-- usually you'll provide a hex and not a position, and the entity will spawn in the center -- usually you'll provide a hex and not a position, and the entity will spawn in the center
-- of the hex. if you want an entity to exist not at the center of a hex, you can provide a -- of the hex. if you want an entity to exist not at the center of a hex, you can provide a
@ -51,17 +51,18 @@ end
function delete_all_entities() function delete_all_entities()
for mob_index,mob in pairs(MOBS) do for mob_index,mob in pairs(MOBS) do
delete_entity(MOBS, mob_index)
if mob then delete_entity(MOBS, mob_index) end
end end
for tower_index,tower in pairs(TOWERS) do for tower_index,tower in pairs(TOWERS) do
delete_entity(TOWERS, tower_index)
if tower then delete_entity(TOWERS, tower_index) end
end end
for projectile_index,projectile in pairs(PROJECTILES) do for projectile_index,projectile in pairs(PROJECTILES) do
delete_entity(PROJECTILES, projectile_index)
if projectile then delete_entity(PROJECTILES, projectile_index) end
end end
end end
function do_entity_updates() function do_entity_updates()
--if WIN:key_down"space" then
for mob_index,mob in pairs(MOBS) do for mob_index,mob in pairs(MOBS) do
if mob and mob.update then if mob and mob.update then
mob.update(mob, mob_index) mob.update(mob, mob_index)
@ -77,5 +78,6 @@ function do_entity_updates()
projectile.update(projectile, projectile_index) projectile.update(projectile, projectile_index)
end end
end end
--end
end end

42
src/grid.lua

@ -65,14 +65,19 @@ function color_at(elevation)
end end
end end
function grid_heuristic(source, target)
local function grid_heuristic(source, target)
return math.distance(source, target) return math.distance(source, target)
end end
function grid_cost(from, to)
local t1, t2 = HEX_MAP.get(from.x, from.y), HEX_MAP.get(to.x, to.y)
--local baseline = math.log(math.abs(1 - t1.elevation) + math.abs(1 - t2.elevation))
return math.abs(t1.elevation - t2.elevation) --+ baseline
local function grid_cost(map, from, to)
local t1, t2 = map.get(from.x, from.y), map.get(to.x, to.y)
if t2.elevation < -0.5 or t2.elevation >= 0.5
or t1.elevation < -0.5 or t1.elevation >= 0.5 then return 999 end
return math.abs(math.abs(t1.elevation)^0.5 - math.abs(t2.elevation)^0.5)
end
local function generate_flow_field(map, start)
return dijkstra(map, start, nil, grid_cost)
end end
function random_map(seed) function random_map(seed)
@ -97,7 +102,7 @@ function random_map(seed)
noise = noise * d^0.125 -- arbitrary, seems to work good noise = noise * d^0.125 -- arbitrary, seems to work good
end end
-- light shading on edge cells
-- light shading on edge cells @TODO replace this with a skylight, that can move
local mask = vec4(0, 0, 0, math.max(((evenq.x - HEX_GRID_WIDTH/2) / HEX_GRID_WIDTH) ^ 2 local mask = vec4(0, 0, 0, math.max(((evenq.x - HEX_GRID_WIDTH/2) / HEX_GRID_WIDTH) ^ 2
, ((-evenq.y - HEX_GRID_HEIGHT/2) / HEX_GRID_HEIGHT) ^ 2)) , ((-evenq.y - HEX_GRID_HEIGHT/2) / HEX_GRID_HEIGHT) ^ 2))
local color = color_at(noise) - mask local color = color_at(noise) - mask
@ -114,9 +119,34 @@ function random_map(seed)
end end
end end
local flow_field = generate_flow_field(map, HEX_GRID_CENTER)
for i,_ in pairs(flow_field) do
for j,priority in pairs(flow_field[i]) do
if priority then
map[i][j].priority = priority.priority
end
end
end
world:append(draw_priority_overlay(map))
world:append(am.circle(hex_to_pixel(HEX_GRID_CENTER), HEX_SIZE/2, COLORS.MAGENTA, 4)) world:append(am.circle(hex_to_pixel(HEX_GRID_CENTER), HEX_SIZE/2, COLORS.MAGENTA, 4))
return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) return map, am.translate(WORLDSPACE_COORDINATE_OFFSET)
^ world:tag"world" ^ world:tag"world"
end end
function draw_priority_overlay(map)
local priority_overlay = am.group():tag"priority_overlay"
for i,_ in pairs(map) do
for j,tile in pairs(map[i]) do
if tile then
priority_overlay:append(am.translate(hex_to_pixel(vec2(i, j)))
^ am.text(string.format("%.1f", tile.priority or 0)))
end
end
end
return priority_overlay
end

17
src/hexyz.lua

@ -448,7 +448,7 @@ end
function breadth_first(map, start) function breadth_first(map, start)
local frontier = {} local frontier = {}
frontier[1] = { start }
frontier[1] = start
local distance = {} local distance = {}
distance[start.x] = {} distance[start.x] = {}
@ -461,7 +461,8 @@ function breadth_first(map, start)
local d = map_get(distance, neighbour.x, neighbour.y) local d = map_get(distance, neighbour.x, neighbour.y)
if not d then if not d then
table.insert(frontier, neighbour) table.insert(frontier, neighbour)
map_set(distance, neighbour.x, neighbour.y, d + 1)
local current_distance = map_get(distance, current.x, current.y)
map_set(distance, neighbour.x, neighbour.y, current_distance + 1)
end end
end end
end end
@ -471,7 +472,7 @@ end
function dijkstra(map, start, goal, cost_f) function dijkstra(map, start, goal, cost_f)
local frontier = {} local frontier = {}
frontier = { hex = start, priority = 0 }
frontier[1] = { hex = start, priority = 0 }
local came_from = {} local came_from = {}
came_from[start.x] = {} came_from[start.x] = {}
@ -484,17 +485,17 @@ function dijkstra(map, start, goal, cost_f)
while not (#frontier == 0) do while not (#frontier == 0) do
local current = table.remove(frontier, 1) local current = table.remove(frontier, 1)
if current.hex == goal then
if goal and current.hex == goal then
break break
end end
for _,neighbour in pairs(map.neighbours(current.hex)) do for _,neighbour in pairs(map.neighbours(current.hex)) do
local new_cost = map_get(cost_so_far, current.hex.x, current.hex.y) + cost_f(current.hex, neighbour)
local new_cost = map_get(cost_so_far, current.hex.x, current.hex.y) + cost_f(map, current.hex, neighbour)
local neighbour_cost = map_get(cost_so_far, neighbour.x, neighbour.y) local neighbour_cost = map_get(cost_so_far, neighbour.x, neighbour.y)
if not neighbour_cost or new_cost < neighbour_cost then
if not neighbour_cost or (new_cost < neighbour_cost) then
map_set(cost_so_far, neighbour.x, neighbour.y, new_cost) map_set(cost_so_far, neighbour.x, neighbour.y, new_cost)
local priority = new_cost
local priority = new_cost + math.distance(start, neighbour)
table.insert(frontier, { hex = neighbour, priority = priority }) table.insert(frontier, { hex = neighbour, priority = priority })
map_set(came_from, neighbour.x, neighbour.y, current) map_set(came_from, neighbour.x, neighbour.y, current)
end end
@ -539,7 +540,7 @@ function Astar(map, start, goal, heuristic, cost_f)
end end
for _,next_ in pairs(map.neighbours(current.hex)) do for _,next_ in pairs(map.neighbours(current.hex)) do
local new_cost = map_get(path_so_far, current.hex.x, current.hex.y) + cost_f(current.hex, next_)
local new_cost = map_get(path_so_far, current.hex.x, current.hex.y) + cost_f(map, current.hex, next_)
local next_cost = map_get(path_so_far, next_.x, next_.y) local next_cost = map_get(path_so_far, next_.x, next_.y)
if not next_cost or new_cost < next_cost then if not next_cost or new_cost < next_cost then

82
src/mob.lua

@ -10,12 +10,11 @@ mob(entity) structure:
} }
--]] --]]
-- distance from hex centerpoint to nearest edge
MOB_SIZE = hex_height(HEX_SIZE, ORIENTATION.FLAT) / 2
MAX_MOB_SIZE = hex_height(HEX_SIZE, ORIENTATION.FLAT) / 2
MOB_SIZE = MAX_MOB_SIZE/2
function mobs_on_hex(hex) function mobs_on_hex(hex)
local t = {} local t = {}
for mob_index,mob in pairs(MOBS) do for mob_index,mob in pairs(MOBS) do
if mob and mob.hex == hex then if mob and mob.hex == hex then
table.insert(t, mob_index, mob) table.insert(t, mob_index, mob)
@ -33,39 +32,11 @@ end
function mob_die(mob, mob_index) function mob_die(mob, mob_index)
WORLD:action(vplay_sound(SOUNDS.EXPLOSION1)) WORLD:action(vplay_sound(SOUNDS.EXPLOSION1))
--WORLD:append(mob_death_explosion(mob))
delete_entity(MOBS, mob_index) delete_entity(MOBS, mob_index)
end end
function mob_death_explosion(mob)
local t = 0.5
return am.particles2d{
source_pos = mob.position,
source_pos_var = vec2(mob.hurtbox_radius),
max_particles = 25,
start_size = mob.hurtbox_radius/10,
start_size_var = mob.hurtbox_radius/15,
end_size = 0,
angle = 0,
angle_var = math.pi,
speed = 105,
speed_var = 55,
life = t * 0.8,
life_var = t * 0.2,
start_color = COLORS.CLARET,
start_color_var = COLORS.DIRT,
end_color = COLORS.DIRT,
end_color_var = COLORS.CLARET,
damping = 0.3
}:action(coroutine.create(function(self)
am.wait(am.delay(t))
WORLD:remove(self)
end))
end
function do_hit_mob(mob, damage, mob_index) function do_hit_mob(mob, damage, mob_index)
mob.health = mob.health - damage mob.health = mob.health - damage
if mob.health <= 0 then if mob.health <= 0 then
update_score(mob.bounty) update_score(mob.bounty)
mob_die(mob, mob_index) mob_die(mob, mob_index)
@ -74,9 +45,9 @@ end
function check_for_broken_mob_pathing(hex) function check_for_broken_mob_pathing(hex)
for _,mob in pairs(MOBS) do for _,mob in pairs(MOBS) do
if mob and mob.path[hex.x] and mob.path[hex.x][hex.y] then
mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER)
end
--if mob and mob.path[hex.x] and mob.path[hex.x][hex.y] then
--mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER)
--end
end end
end end
@ -90,7 +61,7 @@ end
-- try reducing map size by identifying key nodes (inflection points) -- try reducing map size by identifying key nodes (inflection points)
-- there are performance hits everytime we spawn a mob and it's Astar's fault -- there are performance hits everytime we spawn a mob and it's Astar's fault
function get_mob_path(mob, map, start, goal) function get_mob_path(mob, map, start, goal)
return Astar(map, goal, start, grid_heuristic, grid_cost)
--return Astar(map, goal, start, grid_heuristic, grid_cost)
end end
-- @FIXME there's a bug here where the position of the spawn hex is sometimes 1 closer to the center than we want -- @FIXME there's a bug here where the position of the spawn hex is sometimes 1 closer to the center than we want
@ -124,20 +95,43 @@ local function get_spawn_hex()
end end
local function mob_update(mob, mob_index) local function mob_update(mob, mob_index)
local last_frame_hex = mob.hex
mob.hex = pixel_to_hex(mob.position) mob.hex = pixel_to_hex(mob.position)
local frame_target = mob.path[mob.hex.x] and mob.path[mob.hex.x][mob.hex.y]
if mob.hex == HEX_GRID_CENTER then
update_score(-mob.health)
mob_die(mob, mob_index)
return true
end
--local frame_target = mob.path[mob.hex.x] and mob.path[mob.hex.x][mob.hex.y]
local frame_target = nil
local neighbours = HEX_MAP.neighbours(mob.hex)
if #neighbours ~= 0 then
local first_entry = HEX_MAP.get(neighbours[1].x, neighbours[1].y)
local best_hex = neighbours[1]
local best_cost = first_entry and first_entry.priority or HEX_MAP.get(last_frame_hex.x, last_frame_hex.y).priority
for _,h in pairs(neighbours) do
--if h ~= last_frame_hex then
local map_entry = HEX_MAP.get(h.x, h.y)
local cost = map_entry.priority
if cost and cost < best_cost then
best_cost = cost
best_hex = h
end
--end
end
frame_target = best_hex
end
if frame_target then if frame_target then
mob.position = mob.position + math.normalize(hex_to_pixel(frame_target.hex) - mob.position) * mob.speed
mob.position = mob.position + math.normalize(hex_to_pixel(frame_target) - mob.position) * mob.speed
mob.node.position2d = mob.position mob.node.position2d = mob.position
else else
if mob.hex == HEX_GRID_CENTER then
update_score(-mob.health)
mob_die(mob, mob_index)
else
log("stuck")
end
log("no frame target")
end end
--[[ passive animation --[[ passive animation
@ -165,7 +159,7 @@ local function make_and_register_mob()
register_entity(MOBS, mob) register_entity(MOBS, mob)
end end
local SPAWN_CHANCE = 100
local SPAWN_CHANCE = 25
function do_mob_spawning() function do_mob_spawning()
--if WIN:key_pressed"space" then --if WIN:key_pressed"space" then
if math.random(SPAWN_CHANCE) == 1 then if math.random(SPAWN_CHANCE) == 1 then

11
src/tower.lua

@ -6,13 +6,10 @@ TOWER_TYPE = {
MOAT = 2, MOAT = 2,
} }
function tower_type_tostring(type_)
if type_ == TOWER_TYPE.REDEYE then
return "Redeye Tower"
elseif type_ == TOWER_TYPE.WALL then
return "Wall"
elseif type_ == TOWER_TYPE.MOAT then
return "Moat"
function tower_type_tostring(tower_type)
if tower_type == TOWER_TYPE.REDEYE then return "Redeye Tower"
elseif tower_type == TOWER_TYPE.WALL then return "Wall"
elseif tower_type == TOWER_TYPE.MOAT then return "Moat"
end end
end end

Loading…
Cancel
Save