diff --git a/main.lua b/main.lua index 81eb49f..00f2ab7 100644 --- a/main.lua +++ b/main.lua @@ -72,7 +72,7 @@ local function can_do_build(hex, tile, tower_type) end local function game_action(scene) - if SCORE < 0 then game_end() end + --if SCORE < 0 then game_end() end TIME = TIME + am.delta_time SCORE = SCORE + am.delta_time @@ -111,7 +111,12 @@ local function game_action(scene) TRDT = (TRDT + 1) % #table.keys(TRDTS) elseif WIN:key_pressed"tab" then - select_tower_type((SELECTED_TOWER_TYPE) % #table.keys(TOWER_TYPE) + 1) + local num_of_types = #table.keys(TOWER_TYPE) + if WIN:key_down"lshift" then + select_tower_type((SELECTED_TOWER_TYPE + num_of_types - 2) % num_of_types + 1) + else + select_tower_type((SELECTED_TOWER_TYPE) % num_of_types + 1) + end elseif WIN:key_pressed"1" then select_tower_type(TOWER_TYPE.REDEYE) elseif WIN:key_pressed"2" then select_tower_type(2) @@ -214,7 +219,7 @@ local function toolbelt() toolbelt:append(tower_select_square) local tower_type_values = table.values(TOWER_TYPE) - local keys = { '1', '2', '3', '4', '5', '6', '7', '9', '0', '-', '=' } + local keys = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=' } for i = 1, #keys do if tower_type_values[i] then toolbelt:append( diff --git a/res/satelite.png b/res/satelite.png new file mode 100644 index 0000000..e8e27a1 Binary files /dev/null and b/res/satelite.png differ diff --git a/sound.lua b/sound.lua index 4fe595e..1c0819a 100644 --- a/sound.lua +++ b/sound.lua @@ -6,7 +6,7 @@ SOUNDS = { EXPLOSION3 = 69338002, EXPLOSION4 = 92224102, COIN1 = 10262800, - HIT2 = 25811004, + HIT1 = 39920504, LASER1 = 79859301, LASER2 = 86914201, PUSH1 = 30455908, @@ -24,8 +24,8 @@ SOUNDS = { } -- play a sound with variable pitch -function vplay_sound(seed) - return am.play(am.sfxr_synth(seed), false, (math.random() + 0.5)/2) +function vplay_sound(seed, range) + return am.play(am.sfxr_synth(seed), false, (math.random() + 0.5)/(range and 1/range or 2)) end function play_sound(seed) diff --git a/src/grid.lua b/src/grid.lua index fec3656..d77a342 100644 --- a/src/grid.lua +++ b/src/grid.lua @@ -78,8 +78,48 @@ end function grid_cost(map, from, to) local t1, t2 = map.get(from.x, from.y), map.get(to.x, to.y) - --local base_cost = math.abs(t1.elevation) * 10 - return math.abs(10 * math.abs(t1.elevation)^0.5 - 10 * math.abs(t2.elevation)^0.5) + return 1 + 10 * math.abs(math.abs(t1.elevation)^0.5 + - math.abs(t2.elevation)^0.5) +end + +function generate_and_apply_flow_field(map, start, world) + local flow_field = dijkstra(map, start, nil, grid_cost) + local overlay_group = am.group():tag"flow_field" + for i,_ in pairs(flow_field) do + for j,f in pairs(flow_field[i]) do + if f then + map[i][j].priority = f.priority + + overlay_group:append(am.translate(hex_to_pixel(vec2(i, j))) + ^ am.text(string.format("%.1f", f.priority * 10))) + else + -- should fire exactly once per goal hex + log('no priority') + end + end + end + + -- dijkstra doesn't set the priority of the center, do it ourselves + map[HEX_GRID_CENTER.x][HEX_GRID_CENTER.y].priority = -1 + overlay_group:append(am.translate(hex_to_pixel(vec2(HEX_GRID_CENTER.x, HEX_GRID_CENTER.y))) + ^ am.text(string.format("%.1f", -10))) + + if world then world:append(overlay_group) end +end + +function redraw_flow_field_overlay(flow_field) + local overlay_group = am.group():tag"flow_field" + for i,_ in pairs(flow_field) do + for j,f in pairs(flow_field[i]) do + if f then + overlay_group:append(am.translate(hex_to_pixel(vec2(i, j))) + ^ am.text(string.format("%.1f", f.priority * 10))) + else + -- should fire exactly once per goal hex + --log('no priority') + end + end + end end function random_map(seed) @@ -127,19 +167,21 @@ function random_map(seed) node = node }) - getmetatable(map).__index.neighbours = function(hex) - return table.filter(hex_neighbours(hex), function(_hex) - local tile = map.get(_hex.x, _hex.y) - return tile and tile.elevation > -0.5 and tile.elevation <= 0.5 - end) - end - world:append(node) end end - world:append(am.translate(hex_to_pixel(HEX_GRID_CENTER)) - ^ pack_texture_into_sprite(TEX_RADAR1, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y)) + getmetatable(map).__index.neighbours = function(hex) + return table.filter(hex_neighbours(hex), function(_hex) + local tile = map.get(_hex.x, _hex.y) + return tile and tile.elevation > -0.5 and tile.elevation <= 0.5 + end) + end + + generate_and_apply_flow_field(map, HEX_GRID_CENTER) + + --world:append(am.translate(hex_to_pixel(HEX_GRID_CENTER)) + -- ^ pack_texture_into_sprite(TEX_SATELLITE, HEX_PIXEL_SIZE.x*2, HEX_PIXEL_SIZE.y*2)) return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) ^ world end diff --git a/src/mob.lua b/src/mob.lua index 1c0935a..c00bdde 100644 --- a/src/mob.lua +++ b/src/mob.lua @@ -84,27 +84,64 @@ local function mob_update(mob, mob_index) mob.hex = pixel_to_hex(mob.position) if mob.hex == HEX_GRID_CENTER then + log('die') 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] - -- frame_target will be false when we are one hex away from the center, - -- or nil if something went wrong - if not frame_target then - frame_target = { hex = HEX_GRID_CENTER, priority = 0 } + -- figure out movement + local frame_target, tile = nil, nil + if mob.path then + log('A*') + + -- we have an explicitly stored target + local path_entry = mob.path[mob.hex.x] and mob.path[mob.hex.x][mob.hex.y] + frame_target = path_entry.hex + + -- check if our target is valid, and if it's not we aren't going to move this frame. + -- recalculate our path. + if last_frame_hex ~= mob.hex and not mob_can_pass_through(mob, frame_target) then + log('recalc') + mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) + frame_target = nil + end + else + -- use the map's flow field - gotta find the the best neighbour + local neighbours = HEX_MAP.neighbours(mob.hex) + + if #neighbours > 0 then + local first_neighbour = neighbours[1] + tile = HEX_MAP.get(first_neighbour.x, first_neighbour.y) + local lowest_cost_hex = first_neighbour + local lowest_cost = tile.priority or 0 + + for _,n in pairs(neighbours) do + tile = HEX_MAP.get(n.x, n.y) + local current_cost = tile.priority + + if current_cost and current_cost < lowest_cost then + lowest_cost_hex = n + lowest_cost = current_cost + end + end + + frame_target = lowest_cost_hex + else + log('no neighbours') + log(table.tostring(neighbours) .. mob.hex .. mob.position) + end end - if mob_can_pass_through(mob, frame_target.hex) then + -- do movement + if frame_target then -- this is supposed to achieve frame rate independence, but i have no idea if it actually does - local rate = 1 + mob.speed * (1/frame_target.priority) / PERF_STATS.avg_fps + local rate = 1 + mob.speed / PERF_STATS.avg_fps - mob.position = mob.position + math.normalize(hex_to_pixel(frame_target.hex) - mob.position) * rate + mob.position = mob.position + math.normalize(hex_to_pixel(frame_target) - mob.position) * rate mob.node.position2d = mob.position - else - mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) + log('no target') end --[[ passive animation @@ -123,7 +160,7 @@ local function make_and_register_mob() mob_update ) - mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) + --mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) mob.health = 10 mob.speed = 100 mob.bounty = 5 diff --git a/src/projectile.lua b/src/projectile.lua index 895b688..bba2c12 100644 --- a/src/projectile.lua +++ b/src/projectile.lua @@ -63,14 +63,13 @@ function projectile_update(projectile, projectile_index) -- hit the mob, delete ourselves, affect the world do_hit_mob(closest_mob, projectile.damage, closest_mob_index) delete_entity(PROJECTILES, projectile_index) - WORLD:action(vplay_sound(SOUNDS.HIT1)) + WORLD:action(vplay_sound(SOUNDS.HIT1, 0.5)) end function make_and_register_projectile(hex, vector, velocity, damage, hitbox_radius) local projectile = make_basic_entity(hex , am.line(vector, vector*hitbox_radius, 3, COLORS.CLARET) , projectile_update) - projectile.vector = vector projectile.velocity = velocity projectile.damage = damage diff --git a/src/tower.lua b/src/tower.lua index 4df3acf..5ec31fc 100644 --- a/src/tower.lua +++ b/src/tower.lua @@ -11,8 +11,8 @@ tower(entity) structure: TOWER_TYPE = { REDEYE = 1, - WALL = 2, - MOAT = 3, + WALL = 11, + MOAT = 12, } function get_tower_texture(tower_type) @@ -117,6 +117,7 @@ function make_and_register_tower(hex, tower_type) -- make this cell impassable HEX_MAP[hex.x][hex.y].elevation = 2 + generate_and_apply_flow_field(HEX_MAP, HEX_GRID_CENTER) register_entity(TOWERS, tower) end diff --git a/texture.lua b/texture.lua index 34b051d..0c74223 100644 --- a/texture.lua +++ b/texture.lua @@ -10,6 +10,7 @@ function load_textures() TEX_ARROW = am.texture2d("res/arrow.png") TEX_RADAR1 = am.texture2d("res/radar.png") + TEX_SATELLITE = am.texture2d("res/satelite.png") TEX_WALL_CLOSED = am.texture2d("res/wall_closed.png") TEX_MOAT1 = am.texture2d("res/moat1.png") TEX_TOWER1 = am.texture2d("res/tower1.png")