diff --git a/main.lua b/main.lua index 5bfb59a..a155802 100644 --- a/main.lua +++ b/main.lua @@ -27,10 +27,11 @@ WIN = am.window{ title = "hexyz", highdpi = true, letterbox = true, - --clear_color = color_at(0) + clear_color = COLORS.TRUE_BLACK } OFF_SCREEN = vec2(WIN.width * 2) -- arbitrary pixel position that is garunteed to be off screen +PERF_STATS = false -- result of am.perf_stats() -- should be called every frame WORLD = false -- root scene node of everything considered to be in the game world -- aka non gui stuff @@ -60,10 +61,8 @@ local TRDTS = { } local TRDT = TRDTS.SEED -local function select_tower(tower_type) - SELECTED_TOWER_TYPE = tower_type - WIN.scene"tower_tooltip".text = tower_type_tostring(tower_type) -end +-- a function - get sets later inside toolbelt +--local select_tower_type local function game_action(scene) if SCORE < 0 then game_end() end @@ -71,6 +70,7 @@ local function game_action(scene) TIME = TIME + am.delta_time SCORE = SCORE + am.delta_time MOUSE = WIN:mouse_position() + PERF_STATS = am.perf_stats() local hex = pixel_to_hex(MOUSE - WORLDSPACE_COORDINATE_OFFSET) local rounded_mouse = hex_to_pixel(hex) + WORLDSPACE_COORDINATE_OFFSET @@ -103,11 +103,8 @@ local function game_action(scene) elseif WIN:key_pressed"f1" then 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 - select_tower((SELECTED_TOWER_TYPE + 1) % #table.keys(TOWER_TYPE)) + select_tower_type((SELECTED_TOWER_TYPE) % #table.keys(TOWER_TYPE) + 1) end if tile and hot then @@ -134,7 +131,7 @@ local function game_action(scene) str = string.format("%s %s lang %s", am.platform, am.version, am.language()) elseif TRDT == TRDTS.PERF then - str = table.tostring(am.perf_stats()) + str = table.tostring(PERF_STATS) elseif TRDT == TRDTS.SEED then str = "SEED: " .. HEX_MAP.seed @@ -162,23 +159,61 @@ end local function toolbelt() local toolbelt_height = hex_height(HEX_SIZE) * 2 - local tower_tooltip = am.translate(WIN.left + 10, WIN.bottom + toolbelt_height + 10) + local tower_tooltip = am.translate(WIN.left + 10, WIN.bottom + toolbelt_height + 20) ^ am.text(tower_type_tostring(SELECTED_TOWER_TYPE), "left"):tag"tower_tooltip" + local toolbelt = am.group{ tower_tooltip, am.rect(WIN.left, WIN.bottom, WIN.right, WIN.bottom + toolbelt_height, COLORS.TRANSPARENT) - } + }:tag"toolbelt" - --[[ - local padding = 22 + local padding = 15 local size = toolbelt_height - padding - for i = 0, 0 do - toolbelt:append( - am.translate(vec2(size + padding, 0) * i + vec2(WIN.left + padding/3, WIN.bottom + padding/3)) - ^ am.rect(0, 0, size, size, COLORS.BLACK) - ) + local offset = vec2(WIN.left + padding/3, WIN.bottom + padding/3) + + local keys = { + '1', '2', '3', '4', '5', '6', '7', '9', '0', '-', '=' + } + + local tower_select_square = ( + am.translate(vec2(size + padding, size/2) + offset) + ^ am.rect(-size/2-3, -size/2-3, size/2+3, size/2+3, COLORS.SUNRAY) + ):tag"tower_select_square" + + toolbelt:append(tower_select_square) + local tower_type_values = table.values(TOWER_TYPE) + + for i = 1, #keys do + if tower_type_values[i] then + toolbelt:append( + am.translate(vec2(size + padding, 0) * i + offset) + ^ am.group{ + am.translate(0, size/2) + ^ pack_texture_into_sprite(TEX_BUTTON1, size, size), + + am.translate(0, size/2) + ^ pack_texture_into_sprite(get_tower_texture(tower_type_values[i]), size, size), + + am.translate(vec2(size/2)) + ^ am.group{ + pack_texture_into_sprite(TEX_BUTTON1, size/2, size/2), + am.scale(2) + ^ am.text(keys[i], COLORS.BLACK) + } + } + ) + end + end + + select_tower_type = function(tower_type) + SELECTED_TOWER_TYPE = tower_type + WIN.scene"tower_tooltip".text = tower_type_tostring(tower_type) + + local new_position = vec2((size + padding) * tower_type, size/2) + offset + WIN.scene"tower_select_square":action(am.tween(0.1, { position2d = new_position })) + + WIN.scene:action(am.play(am.sfxr_synth(SOUNDS.SELECT1), false, 1, SFX_VOLUME)) end - ]] return toolbelt end diff --git a/res/button1.png b/res/button1.png new file mode 100644 index 0000000..24b52f8 Binary files /dev/null and b/res/button1.png differ diff --git a/sound.lua b/sound.lua index 5f2d3f1..3bacc2c 100644 --- a/sound.lua +++ b/sound.lua @@ -8,6 +8,8 @@ SOUNDS = { LASER1 = 79859301, LASER2 = 86914201, PUSH1 = 30455908, + SELECT1 = 76036806, + PUSH2 = 57563308, BIRD1 = 50838307, RANDOM1 = 85363309, RANDOM2 = 15482409, @@ -24,3 +26,7 @@ function vplay_sound(seed) return am.play(am.sfxr_synth(seed), false, (math.random() + 0.5)/2) end +function play_sound(seed) + return am.play(am.sfxr_synth(seed), false) +end + diff --git a/src/grid.lua b/src/grid.lua index 8469914..81a4828 100644 --- a/src/grid.lua +++ b/src/grid.lua @@ -25,14 +25,17 @@ do local hhs = hex_horizontal_spacing(HEX_SIZE) local hvs = hex_vertical_spacing(HEX_SIZE) + HEX_GRID_PIXEL_WIDTH = (HEX_GRID_WIDTH - 1) * hhs + HEX_GRID_PIXEL_HEIGHT = (HEX_GRID_HEIGHT - 1) * hvs + -- number of 'spacings' on the grid == number of cells - 1 - GRID_PIXEL_DIMENSIONS = vec2((HEX_GRID_WIDTH - 1) * hhs - , (HEX_GRID_HEIGHT - 1) * hvs) + HEX_GRID_PIXEL_DIMENSIONS = vec2(HEX_GRID_PIXEL_WIDTH + , HEX_GRID_PIXEL_HEIGHT) end -- amulet puts 0,0 in the middle of the screen -- transform coordinates by this to pretend 0,0 is elsewhere -WORLDSPACE_COORDINATE_OFFSET = -GRID_PIXEL_DIMENSIONS/2 +WORLDSPACE_COORDINATE_OFFSET = -HEX_GRID_PIXEL_DIMENSIONS/2 -- the outer edges of the map are not interactable, most action occurs in the center HEX_GRID_INTERACTABLE_REGION_PADDING = 4 @@ -51,10 +54,10 @@ function color_at(elevation) return COLORS.WATER{ a = (elevation + 1.4) / 2 + 0.2 } elseif elevation < 0 then -- med-low elevation - return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.8) / 2 + 0.2 } + return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.8) / 2 + 0.3 } elseif elevation < 0.5 then -- med-high elevation - return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.6) / 2 + 0.2 } + return math.lerp(COLORS.DIRT, COLORS.GRASS, elevation + 0.5){ a = (elevation + 1.6) / 2 + 0.3 } elseif elevation < 1 then -- high elevation return COLORS.MOUNTAIN{ ra = elevation } @@ -67,24 +70,18 @@ end function grid_cost(map, from, to) local t1, t2 = map.get(from.x, from.y), map.get(to.x, to.y) - - -- moving from a non-water, non-mountain tile to a water or mountain tile is very expensive - if math.abs(t1.elevation) < 0.5 and math.abs(t2.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) + return math.abs(10 * math.abs(t1.elevation)^0.5 - 10 * math.abs(t2.elevation)^0.5) end function random_map(seed) local map = rectangular_map(HEX_GRID_DIMENSIONS.x, HEX_GRID_DIMENSIONS.y, seed) math.randomseed(map.seed) - local world = am.group() + -- the world's appearance relies largely on a backdrop which can be scaled in + -- tone to give the appearance of light or darkness + local neg_mask = am.rect(0, 0, HEX_GRID_PIXEL_WIDTH, HEX_GRID_PIXEL_HEIGHT, COLORS.TRUE_BLACK):tag"negative_mask" + + local world = am.group(neg_mask):tag"world" for i,_ in pairs(map) do for j,noise in pairs(map[i]) do local evenq = hex_to_evenq(vec2(i, j)) @@ -119,34 +116,8 @@ function random_map(seed) 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)) - return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) - ^ world:tag"world" + return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) ^ world 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 - - diff --git a/src/hexyz.lua b/src/hexyz.lua index a960a35..1bc1c3d 100644 --- a/src/hexyz.lua +++ b/src/hexyz.lua @@ -551,6 +551,9 @@ function Astar(map, start, goal, heuristic, cost_f) end end end + if not made_it then + log('aaaa') + end return path, made_it end diff --git a/src/mob.lua b/src/mob.lua index 794e1d9..e63d4c3 100644 --- a/src/mob.lua +++ b/src/mob.lua @@ -30,13 +30,10 @@ function mob_on_hex(hex) end) end +-- check if a the tile at |hex| is passable by |mob| function mob_can_pass_through(mob, hex) local tile = HEX_MAP.get(hex.x, hex.y) - if tile and tile.elevation < -0.5 or tile.elevation >= 0.5 then - return false - else - return true - end + return tile and tile.elevation < 0.5 and tile.elevation > -0.5 end function mob_die(mob, mob_index) @@ -60,11 +57,6 @@ function check_for_broken_mob_pathing(hex) end end --- check if a the tile at |hex| is passable by |mob| -local function mob_can_pass_through(mob, hex) - local tile = HEX_MAP.get(hex.x, hex.y) - return tile and tile.elevation < 0.5 and tile.elevation > -0.5 -end -- @TODO performance. -- try reducing map size by identifying key nodes (inflection points) @@ -106,44 +98,14 @@ local function mob_update(mob, mob_index) return true end - local frame_target = nil - if mob.path then - -- we have an explicitly stored hex that this mob wants to move towards. - frame_target = mob.path[mob.hex.x] and mob.path[mob.hex.x][mob.hex.y] + local frame_target = mob.path[mob.hex.x] and mob.path[mob.hex.x][mob.hex.y] - else - -- make a dumb guess where we should go. - 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 - 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 - frame_target = best_hex - end - end - - if frame_target == last_frame_hex or not mob_can_pass_through(mob, frame_target) then - -- we are trying to go somewhere dumb. make a better path. - mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) - return -- don't move this frame. too much time thinking - end - - if frame_target then - mob.position = mob.position + math.normalize(hex_to_pixel(frame_target) - mob.position) * mob.speed + if frame_target --[[and mob_can_pass_through(mob, frame_target.hex)]] then + local factor = 1 + mob.speed * (1/frame_target.priority) / PERF_STATS.avg_fps + mob.position = mob.position + math.normalize(hex_to_pixel(frame_target.hex) - mob.position) * factor mob.node.position2d = mob.position else - log("no frame target") + mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER) end --[[ passive animation @@ -162,9 +124,9 @@ local function make_and_register_mob() mob_update ) - mob.path = false --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 = 1 + mob.speed = 100 mob.bounty = 5 mob.hurtbox_radius = MOB_SIZE diff --git a/src/tower.lua b/src/tower.lua index 7dda72f..7eea041 100644 --- a/src/tower.lua +++ b/src/tower.lua @@ -1,11 +1,18 @@ TOWER_TYPE = { - REDEYE = 0, - WALL = 1, - MOAT = 2, + REDEYE = 1, + WALL = 2, + MOAT = 3, } +function get_tower_texture(tower_type) + if tower_type == TOWER_TYPE.REDEYE then return TEX_TOWER2 + elseif tower_type == TOWER_TYPE.WALL then return TEX_WALL_CLOSED + elseif tower_type == TOWER_TYPE.MOAT then return TEX_MOAT1 + end +end + 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" @@ -13,6 +20,28 @@ function tower_type_tostring(tower_type) end end +local function get_tower_update_function(tower_type) + if tower_type == TOWER_TYPE.REDEYE then + return update_tower_redeye + end +end + +local function make_tower_sprite(tower_type) + local texture = get_tower_texture(tower_type) + if tower_type == TOWER_TYPE.REDEYE then + return pack_texture_into_sprite(texture, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) + + elseif tower_type == TOWER_TYPE.WALL then + --return pack_texture_into_sprite(TEX_WALL_CLOSED, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) + return am.circle(vec2(0), HEX_SIZE, COLORS.VERY_DARK_GRAY, 6) + + elseif tower_type == TOWER_TYPE.MOAT then + --return pack_texture_into_sprite(TEX_MOAT1, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) + return am.circle(vec2(0), HEX_SIZE, COLORS.YALE_BLUE, 6) + end +end + + --[[ tower(entity) structure: @@ -24,8 +53,8 @@ tower(entity) structure: } --]] function is_buildable(hex, tile, tower) - local blocked = mob_on_hex(hex) - return not blocked and is_passable(tile) + local blocked = #mobs_on_hex(hex) ~= 0 + return not blocked and tile.elevation <= 0.5 and tile.elevation > -0.5 end function update_tower_redeye(tower, tower_index) @@ -60,30 +89,6 @@ function update_tower_redeye(tower, tower_index) end end -local function make_tower_sprite(tower_type) - if tower_type == TOWER_TYPE.REDEYE then - return pack_texture_into_sprite(TEX_TOWER2, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) - - elseif tower_type == TOWER_TYPE.WALL then - --return pack_texture_into_sprite(TEX_WALL_CLOSED, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) - return am.circle(vec2(0), HEX_SIZE, COLORS.VERY_DARK_GRAY, 6) - - elseif tower_type == TOWER_TYPE.MOAT then - --return pack_texture_into_sprite(TEX_MOAT1, HEX_PIXEL_SIZE.x, HEX_PIXEL_SIZE.y) - return am.circle(vec2(0), HEX_SIZE, COLORS.YALE_BLUE, 6) - end -end - -local function modify_terrain_by_tower_type(tower_type, hex) - -end - -local function get_tower_update_function(tower_type) - if tower_type == TOWER_TYPE.REDEYE then - return update_tower_redeye - end -end - function make_and_register_tower(hex, tower_type) local tower = make_basic_entity( hex, diff --git a/texture.lua b/texture.lua index d43429b..468c6cd 100644 --- a/texture.lua +++ b/texture.lua @@ -3,6 +3,8 @@ function load_textures() TEX_MARQUIS = am.texture2d("res/marquis.png") + TEX_BUTTON1 = am.texture2d("res/button1.png") + TEX_ARROW = am.texture2d("res/arrow.png") TEX_WALL_CLOSED = am.texture2d("res/wall_closed.png")