Browse Source

added toolbelt selector thingy

master
Nicholas Hayashi 4 years ago
parent
commit
ad68161b63
  1. 75
      main.lua
  2. BIN
      res/button1.png
  3. 6
      sound.lua
  4. 59
      src/grid.lua
  5. 3
      src/hexyz.lua
  6. 56
      src/mob.lua
  7. 63
      src/tower.lua
  8. 2
      texture.lua

75
main.lua

@ -27,10 +27,11 @@ WIN = am.window{
title = "hexyz", title = "hexyz",
highdpi = true, highdpi = true,
letterbox = 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 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 WORLD = false -- root scene node of everything considered to be in the game world
-- aka non gui stuff -- aka non gui stuff
@ -60,10 +61,8 @@ local TRDTS = {
} }
local TRDT = TRDTS.SEED 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) local function game_action(scene)
if SCORE < 0 then game_end() end if SCORE < 0 then game_end() end
@ -71,6 +70,7 @@ local function game_action(scene)
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()
PERF_STATS = am.perf_stats()
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
@ -103,11 +103,8 @@ local function game_action(scene)
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_type((SELECTED_TOWER_TYPE) % #table.keys(TOWER_TYPE) + 1)
end end
if tile and hot then 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()) str = string.format("%s %s lang %s", am.platform, am.version, am.language())
elseif TRDT == TRDTS.PERF then elseif TRDT == TRDTS.PERF then
str = table.tostring(am.perf_stats())
str = table.tostring(PERF_STATS)
elseif TRDT == TRDTS.SEED then elseif TRDT == TRDTS.SEED then
str = "SEED: " .. HEX_MAP.seed str = "SEED: " .. HEX_MAP.seed
@ -162,23 +159,61 @@ end
local function toolbelt() local function toolbelt()
local toolbelt_height = hex_height(HEX_SIZE) * 2 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" ^ am.text(tower_type_tostring(SELECTED_TOWER_TYPE), "left"):tag"tower_tooltip"
local toolbelt = am.group{ local toolbelt = am.group{
tower_tooltip, tower_tooltip,
am.rect(WIN.left, WIN.bottom, WIN.right, WIN.bottom + toolbelt_height, COLORS.TRANSPARENT) 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 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 end
]]
return toolbelt return toolbelt
end end

BIN
res/button1.png

After

Width: 128  |  Height: 128  |  Size: 454 B

6
sound.lua

@ -8,6 +8,8 @@ SOUNDS = {
LASER1 = 79859301, LASER1 = 79859301,
LASER2 = 86914201, LASER2 = 86914201,
PUSH1 = 30455908, PUSH1 = 30455908,
SELECT1 = 76036806,
PUSH2 = 57563308,
BIRD1 = 50838307, BIRD1 = 50838307,
RANDOM1 = 85363309, RANDOM1 = 85363309,
RANDOM2 = 15482409, RANDOM2 = 15482409,
@ -24,3 +26,7 @@ function vplay_sound(seed)
return am.play(am.sfxr_synth(seed), false, (math.random() + 0.5)/2) return am.play(am.sfxr_synth(seed), false, (math.random() + 0.5)/2)
end end
function play_sound(seed)
return am.play(am.sfxr_synth(seed), false)
end

59
src/grid.lua

@ -25,14 +25,17 @@ do
local hhs = hex_horizontal_spacing(HEX_SIZE) local hhs = hex_horizontal_spacing(HEX_SIZE)
local hvs = hex_vertical_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 -- 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 end
-- amulet puts 0,0 in the middle of the screen -- amulet puts 0,0 in the middle of the screen
-- transform coordinates by this to pretend 0,0 is elsewhere -- 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 -- the outer edges of the map are not interactable, most action occurs in the center
HEX_GRID_INTERACTABLE_REGION_PADDING = 4 HEX_GRID_INTERACTABLE_REGION_PADDING = 4
@ -51,10 +54,10 @@ function color_at(elevation)
return COLORS.WATER{ a = (elevation + 1.4) / 2 + 0.2 } return COLORS.WATER{ a = (elevation + 1.4) / 2 + 0.2 }
elseif elevation < 0 then -- med-low elevation 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 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 elseif elevation < 1 then -- high elevation
return COLORS.MOUNTAIN{ ra = elevation } return COLORS.MOUNTAIN{ ra = elevation }
@ -67,24 +70,18 @@ end
function grid_cost(map, from, to) function grid_cost(map, from, to)
local t1, t2 = map.get(from.x, from.y), map.get(to.x, to.y) 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 end
function random_map(seed) function random_map(seed)
local map = rectangular_map(HEX_GRID_DIMENSIONS.x, HEX_GRID_DIMENSIONS.y, seed) local map = rectangular_map(HEX_GRID_DIMENSIONS.x, HEX_GRID_DIMENSIONS.y, seed)
math.randomseed(map.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 i,_ in pairs(map) do
for j,noise in pairs(map[i]) do for j,noise in pairs(map[i]) do
local evenq = hex_to_evenq(vec2(i, j)) local evenq = hex_to_evenq(vec2(i, j))
@ -119,34 +116,8 @@ 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)
^ world:tag"world"
return map, am.translate(WORLDSPACE_COORDINATE_OFFSET) ^ 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

3
src/hexyz.lua

@ -551,6 +551,9 @@ function Astar(map, start, goal, heuristic, cost_f)
end end
end end
end end
if not made_it then
log('aaaa')
end
return path, made_it return path, made_it
end end

56
src/mob.lua

@ -30,13 +30,10 @@ function mob_on_hex(hex)
end) end)
end end
-- check if a the tile at |hex| is passable by |mob|
function mob_can_pass_through(mob, hex) function mob_can_pass_through(mob, hex)
local tile = HEX_MAP.get(hex.x, hex.y) 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 end
function mob_die(mob, mob_index) function mob_die(mob, mob_index)
@ -60,11 +57,6 @@ function check_for_broken_mob_pathing(hex)
end end
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. -- @TODO performance.
-- try reducing map size by identifying key nodes (inflection points) -- try reducing map size by identifying key nodes (inflection points)
@ -106,44 +98,14 @@ local function mob_update(mob, mob_index)
return true return true
end 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 mob.node.position2d = mob.position
else else
log("no frame target")
mob.path = get_mob_path(mob, HEX_MAP, mob.hex, HEX_GRID_CENTER)
end end
--[[ passive animation --[[ passive animation
@ -162,9 +124,9 @@ local function make_and_register_mob()
mob_update 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.health = 10
mob.speed = 1
mob.speed = 100
mob.bounty = 5 mob.bounty = 5
mob.hurtbox_radius = MOB_SIZE mob.hurtbox_radius = MOB_SIZE

63
src/tower.lua

@ -1,11 +1,18 @@
TOWER_TYPE = { 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) function tower_type_tostring(tower_type)
if tower_type == TOWER_TYPE.REDEYE then return "Redeye Tower" if tower_type == TOWER_TYPE.REDEYE then return "Redeye Tower"
elseif tower_type == TOWER_TYPE.WALL then return "Wall" elseif tower_type == TOWER_TYPE.WALL then return "Wall"
@ -13,6 +20,28 @@ function tower_type_tostring(tower_type)
end end
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: tower(entity) structure:
@ -24,8 +53,8 @@ tower(entity) structure:
} }
--]] --]]
function is_buildable(hex, tile, tower) 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 end
function update_tower_redeye(tower, tower_index) function update_tower_redeye(tower, tower_index)
@ -60,30 +89,6 @@ function update_tower_redeye(tower, tower_index)
end end
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) function make_and_register_tower(hex, tower_type)
local tower = make_basic_entity( local tower = make_basic_entity(
hex, hex,

2
texture.lua

@ -3,6 +3,8 @@
function load_textures() function load_textures()
TEX_MARQUIS = am.texture2d("res/marquis.png") TEX_MARQUIS = am.texture2d("res/marquis.png")
TEX_BUTTON1 = am.texture2d("res/button1.png")
TEX_ARROW = am.texture2d("res/arrow.png") TEX_ARROW = am.texture2d("res/arrow.png")
TEX_WALL_CLOSED = am.texture2d("res/wall_closed.png") TEX_WALL_CLOSED = am.texture2d("res/wall_closed.png")

Loading…
Cancel
Save