You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
9.4 KiB
302 lines
9.4 KiB
|
|
|
|
math.randomseed(os.time())
|
|
math.random()
|
|
math.random()
|
|
math.random()
|
|
|
|
-- assets/non-or-trivial code
|
|
require "color"
|
|
require "sound"
|
|
require "texture"
|
|
|
|
require "src/entity"
|
|
require "src/extra"
|
|
require "src/geometry"
|
|
require "src/hexyz"
|
|
require "src/grid"
|
|
require "src/mob"
|
|
require "src/projectile"
|
|
require "src/tower"
|
|
|
|
|
|
-- Globals
|
|
WIN = am.window{
|
|
width = 1920,
|
|
height = 1080,
|
|
title = "hexyz",
|
|
highdpi = true,
|
|
letterbox = true,
|
|
clear_color = color_at(0)
|
|
}
|
|
|
|
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
|
|
|
|
TIME = 0 -- runtime of the current game in seconds (not whole program runtime)
|
|
SCORE = 0 -- score of the player
|
|
MONEY = 0 -- available resources
|
|
MOUSE = false -- position of the mouse at the start of every frame, if an action is tracking it
|
|
|
|
-- global audio settings
|
|
MUSIC_VOLUME = 0.1
|
|
SFX_VOLUME = 0.1
|
|
|
|
-- game stuff
|
|
SELECTED_TOWER_TYPE = TOWER_TYPE.REDEYE
|
|
|
|
-- top right display types
|
|
local TRDTS = {
|
|
NOTHING = -1,
|
|
CENTERED_EVENQ = 0,
|
|
EVENQ = 1,
|
|
HEX = 2,
|
|
PLATFORM = 3,
|
|
PERF = 4,
|
|
SEED = 5,
|
|
TILE = 6
|
|
}
|
|
local TRDT = TRDTS.SEED
|
|
|
|
local function select_hex(hex)
|
|
local tower = tower_on_hex(hex)
|
|
local tile = HEX_MAP.get(hex.x, hex.y)
|
|
log(tile)
|
|
end
|
|
|
|
local function can_do_build(hex, tile, tower_type)
|
|
return tower_is_buildable_on(hex, tile, SELECTED_TOWER_TYPE)
|
|
end
|
|
|
|
local function game_action(scene)
|
|
if SCORE < 0 then game_end() end
|
|
|
|
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
|
|
local evenq = hex_to_evenq(hex)
|
|
local centered_evenq = evenq{ y = -evenq.y } - vec2(math.floor(HEX_GRID_WIDTH/2)
|
|
, math.floor(HEX_GRID_HEIGHT/2))
|
|
local tile = HEX_MAP.get(hex.x, hex.y)
|
|
local hot = evenq_is_interactable(evenq{ y = -evenq.y })
|
|
|
|
do_entity_updates()
|
|
do_mob_spawning()
|
|
|
|
if WIN:mouse_pressed"left" then
|
|
if hot and can_do_build(hex, tile, SELECTED_TOWER_TYPE) then
|
|
build_tower(hex, SELECTED_TOWER_TYPE)
|
|
end
|
|
end
|
|
|
|
if WIN:mouse_pressed"middle" then
|
|
WIN.scene"scale".scale2d = vec2(1)
|
|
else
|
|
local mwd = vec2(WIN:mouse_wheel_delta().y / 1000)
|
|
WIN.scene"scale".scale2d = WIN.scene"scale".scale2d + mwd
|
|
WIN.scene"scale".scale2d = WIN.scene"scale".scale2d + mwd
|
|
end
|
|
|
|
if WIN:key_pressed"escape" then
|
|
game_end()
|
|
|
|
elseif WIN:key_pressed"f1" then
|
|
TRDT = (TRDT + 1) % #table.keys(TRDTS)
|
|
|
|
elseif WIN:key_pressed"tab" then
|
|
select_tower_type((SELECTED_TOWER_TYPE) % #table.keys(TOWER_TYPE) + 1)
|
|
|
|
elseif WIN:key_pressed"1" then select_tower_type(TOWER_TYPE.REDEYE)
|
|
elseif WIN:key_pressed"2" then select_tower_type(2)
|
|
elseif WIN:key_pressed"3" then select_tower_type(3)
|
|
elseif WIN:key_pressed"4" then --select_tower_type(4)
|
|
elseif WIN:key_pressed"5" then --select_tower_type(5)
|
|
elseif WIN:key_pressed"6" then --select_tower_type(6)
|
|
elseif WIN:key_pressed"7" then --select_tower_type(7)
|
|
elseif WIN:key_pressed"8" then --select_tower_type(8)
|
|
elseif WIN:key_pressed"9" then --select_tower_type(9)
|
|
elseif WIN:key_pressed"0" then --select_tower_type(10)
|
|
elseif WIN:key_pressed"-" then --select_tower_type(1)
|
|
elseif WIN:key_pressed"=" then --select_tower_type(1)
|
|
end
|
|
|
|
if tile and hot then
|
|
WIN.scene"hex_cursor".center = rounded_mouse
|
|
else
|
|
WIN.scene"hex_cursor".center = OFF_SCREEN
|
|
end
|
|
|
|
WIN.scene"score".text = string.format("SCORE: %.2f", SCORE)
|
|
WIN.scene"money".text = string.format("MONEY: %d", MONEY)
|
|
|
|
do
|
|
local str = ""
|
|
if TRDT == TRDTS.CENTERED_EVENQ then
|
|
str = centered_evenq.x .. "," .. centered_evenq.y .. " (cevenq)"
|
|
|
|
elseif TRDT == TRDTS.EVENQ then
|
|
str = evenq.x .. "," .. evenq.y .. " (evenq)"
|
|
|
|
elseif TRDT == TRDTS.HEX then
|
|
str = hex.x .. "," .. hex.y .. " (hex)"
|
|
|
|
elseif TRDT == TRDTS.PLATFORM then
|
|
str = string.format("%s %s lang %s", am.platform, am.version, am.language())
|
|
|
|
elseif TRDT == TRDTS.PERF then
|
|
str = table.tostring(PERF_STATS)
|
|
|
|
elseif TRDT == TRDTS.SEED then
|
|
str = "SEED: " .. HEX_MAP.seed
|
|
|
|
elseif TRDT == TRDTS.TILE then
|
|
str = table.tostring(HEX_MAP.get(hex.x, hex.y))
|
|
end
|
|
WIN.scene"coords".text = str
|
|
end
|
|
|
|
--do_day_night_cycle()
|
|
end
|
|
|
|
function do_day_night_cycle()
|
|
local tstep = (math.sin(TIME) / PERF_STATS.avg_fps + 1)/8
|
|
WORLD"negative_mask".color = vec4(tstep)
|
|
end
|
|
|
|
function game_end()
|
|
|
|
-- de-initialize stuff
|
|
delete_all_entities()
|
|
TIME = 0
|
|
SCORE = 0
|
|
MONEY = 0
|
|
WORLD = false
|
|
|
|
WIN.scene = am.scale(1) ^ game_scene()
|
|
end
|
|
|
|
function update_score(diff)
|
|
SCORE = SCORE + diff
|
|
end
|
|
|
|
local function toolbelt()
|
|
local toolbelt_height = hex_height(HEX_SIZE) * 2
|
|
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 = 15
|
|
local size = toolbelt_height - padding
|
|
local half_size = size/2
|
|
local offset = vec2(WIN.left + padding*3, WIN.bottom + padding/3)
|
|
|
|
local tab_button = am.translate(vec2(0, half_size) + offset)
|
|
^ am.group{
|
|
pack_texture_into_sprite(TEX_WIDER_BUTTON1, 54, 32),
|
|
pack_texture_into_sprite(TEX_TAB_ICON, 25, 25)
|
|
}
|
|
toolbelt:append(tab_button)
|
|
|
|
local tower_select_square = (
|
|
am.translate(vec2(size + padding, half_size) + 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)
|
|
local keys = { '1', '2', '3', '4', '5', '6', '7', '9', '0', '-', '=' }
|
|
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, half_size)
|
|
^ pack_texture_into_sprite(TEX_BUTTON1, size, size),
|
|
|
|
am.translate(0, half_size)
|
|
^ pack_texture_into_sprite(get_tower_texture(tower_type_values[i]), size, size),
|
|
|
|
am.translate(vec2(half_size))
|
|
^ am.group{
|
|
pack_texture_into_sprite(TEX_BUTTON1, half_size, half_size),
|
|
am.scale(2)
|
|
^ am.text(keys[i], COLORS.BLACK)
|
|
}
|
|
}
|
|
)
|
|
else
|
|
toolbelt:append(
|
|
am.translate(vec2(size + padding, 0) * i + offset)
|
|
^ am.group{
|
|
am.translate(0, half_size)
|
|
^ pack_texture_into_sprite(TEX_BUTTON1, size, size),
|
|
|
|
am.translate(vec2(half_size))
|
|
^ am.group{
|
|
pack_texture_into_sprite(TEX_BUTTON1, half_size, half_size),
|
|
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
|
|
|
|
-- @NOTE must be global to allow the game_action to reference it
|
|
function game_scene()
|
|
local score = am.translate(WIN.left + 10, WIN.top - 20) ^ am.text("", "left"):tag"score"
|
|
local money = am.translate(WIN.left + 10, WIN.top - 40) ^ am.text("", "left"):tag"money"
|
|
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 curtain = am.rect(WIN.left, WIN.bottom, WIN.right, WIN.top, COLORS.TRUE_BLACK)
|
|
curtain:action(coroutine.create(function()
|
|
am.wait(am.tween(curtain, 3, { color = vec4(0) }, am.ease.out(am.ease.hyperbola)))
|
|
WIN.scene:remove(curtain)
|
|
end))
|
|
|
|
HEX_MAP, WORLD = random_map()
|
|
|
|
local scene = am.group{
|
|
WORLD,
|
|
curtain,
|
|
hex_cursor,
|
|
toolbelt(),
|
|
score,
|
|
money,
|
|
coords,
|
|
}
|
|
|
|
scene:action(game_action)
|
|
--scene:action(am.play(SOUNDS.TRACK1))
|
|
|
|
return scene
|
|
end
|
|
|
|
load_textures()
|
|
WIN.scene = am.scale(vec2(1)) ^ game_scene()
|
|
noglobals()
|
|
|