bytepath/main.lua

245 lines
7.1 KiB
Lua

-- debug --
if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
DEBUG = true
require("lldebugger").start()
else DEBUG = false end
print('debug:', DEBUG)
-- libraries --
---@type Object
Object = require 'lib/classic/classic'
---@type Baton
Baton = require 'lib/baton/baton'
---@type Timer
Timer = require 'lib/hump/timer'
HC = require 'lib/hc'
Camera = require 'lib/cameramod/camera'
require 'lib/cameramod/Shake'
-- generic objects --
Room = require 'obj/Room'
Area = require 'obj/Area'
GameObject = require 'obj/GameObject'
function love.load()
-- screen setup
love.graphics.setDefaultFilter("nearest")
love.graphics.setLineStyle("rough")
resize(2)
---@type Room|nil
current_room = nil
-- load game objects
local game_objects = {}
print('loading game objects:')
recursiveEnumerate('obj/game', game_objects)
for _,v in ipairs(game_objects) do print('',v) end
requireFiles(game_objects, true)
-- load rooms
local room_files = {}
print('loading rooms:')
recursiveEnumerate('rooms', room_files)
for _,v in ipairs(room_files) do print('',v) end
requireFiles(room_files, true)
-- load input
input = Baton.new {
controls = {
left = {'key:left', 'key:a'},
right = {'key:right', 'key:d'},
up = {'key:up', 'key:w'},
down = {'key:down', 'key:s'},
action = {'key:z', 'key:space'},
f1 = {'key:f1'}, f2 = {'key:f2'}, f3 = {'key:f3'},
f10 = {'key:f10'}, f11 = {'key:f11'}, f12 = {'key:f12'}
},
pairs = {
move = {'left', 'right', 'up', 'down'}
}
}
camera = Camera()
gotoRoom('Stage')
end
function love.update(dt)
if current_room then current_room:update(dt) end
input:update(dt)
if input:pressed('f1') then gotoRoom('CircleRoom') end
if input:pressed('f2') and DEBUG then
-- global debug breakpoint
print('break')
end
if input:pressed('f3') then camera:shake(4, 60, 1) end
if input:pressed('f10') then
if DEBUG then
print('setting DEBUG to false...')
DEBUG = false
else
print('setting DEBUG to true...')
DEBUG = true
end
end
if input:pressed('f12') then
print("-------------------------------------")
print("Before collection: " .. collectgarbage("count")/1024)
collectgarbage()
print("After collection: " .. collectgarbage("count")/1024)
print("Object count: ")
local counts = type_count()
for k, v in pairs(counts) do print(k, v) end
print("-------------------------------------")
end
camera:update(dt)
end
function love.draw()
if current_room then current_room:draw() end
end
---Enumerates files in a folder and inserts them to a provided table.
---@param folder string path to folder to scan
---@param file_list table table to be inserted to
function recursiveEnumerate(folder, file_list)
local items = love.filesystem.getDirectoryItems(folder)
for _, item in ipairs(items) do
local file = folder .. '/' .. item
local info = love.filesystem.getInfo(file)
if info then -- exists (covers both files and directories)
if info.type == "file" then
table.insert(file_list, file)
elseif info.type == "directory" then
recursiveEnumerate(file, file_list)
end
end
end
end
---Load files table as lua modules.
---@param files table table containing files to be loaded
---@param should_return boolean|nil whether required files return a table/object
function requireFiles(files, should_return)
local returns = should_return or false
for _, file in ipairs(files) do
local module = file:sub(1, -5)
if not returns then require(module) else
local filename = module:match("([^/]+)$")
_G[filename] = require(module)
end
end
end
---Go to a specific room.
---@param room_type string the name of the room as registered
---@param ... any arguments passed to the room constructor
function gotoRoom(room_type, ...)
local Class = _G[room_type]
if not Class then
error("room '"..room_type.."' not found in _G")
end
if type(Class) ~= "table" and type(Class) ~= "function" then
error("room '"..room_type.."' is not callable (got "..type(Class)..", does room return itself?)")
end
if current_room and current_room.destroy then current_room:destroy() end
current_room = _G[room_type](...)
end
---Generates and returns random UUID string
---@return string
function UUID()
local fn = function(x)
local r = math.random(16) - 1
r = (x == "x") and (r + 1) or (r % 4) + 9
return ("0123456789abcdef"):sub(r, r)
end
return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn))
end
---Resize window
---@param s number scale setting
function resize(s)
love.window.setMode(s*gw, s*gh)
sx, sy = s, s
end
---Pushes a transformation stack for rotating and/or scaling
---@param x number horizontal coordinate to translate
---@param y number vertical coordinate to translate
---@param r number|nil angle to rotate
---@param sx number|nil horizontal scale
---@param sy number|nil vertical scale
function pushRotateScale(x, y, r, sx, sy)
love.graphics.push()
love.graphics.translate(x, y)
if r then love.graphics.rotate(r) end
if sx then love.graphics.scale(sx, sy or sx or 1) end
love.graphics.translate(-x, -y)
end
---Returns random number
---@param min number minimum of range
---@param max number maximum of range
---@return number
function random(min, max)
local min, max = min or 0, max or 1
return (min > max and (love.math.random()*(min - max) + max)) or (love.math.random()*(max - min) + min)
end
------------------------
-- garbage collection --
------------------------
---Counts all globals and applies function
---@param f function
function count_all(f)
local seen = {}
local count_table
count_table = function(t)
if seen[t] then return end
f(t)
seen[t] = true
for k,v in pairs(t) do
if type(v) == "table" then
count_table(v)
elseif type(v) == "userdata" then
f(v)
end
end
end
count_table(_G)
end
---Count all types of globals
---@return table
function type_count()
local counts = {}
local enumerate = function (o)
local t = type_name(o)
counts[t] = (counts[t] or 0) + 1
end
count_all(enumerate)
return counts
end
global_type_table = nil
---Resolves an object's true class name via metatable lookup.
---Caches results in `global_type_table` for speed.
---Fallbacks: "table" (no metatable), "Unknown" (uncached).
---@param o any Any object (table, userdata, etc.)
---@return string Class name (e.g., "Player", "Camera", "ImageData")
function type_name(o)
if global_type_table == nil then
global_type_table = {}
for k,v in pairs(_G) do
global_type_table[v] = k
end
global_type_table[0] = "table"
end
return global_type_table[getmetatable(o) or 0] or "Unknown"
end