102 lines
3.8 KiB
Text
102 lines
3.8 KiB
Text
-- Forge (FORGE.md): compiles all four sample descriptions and plays the platformer.
|
|
--
|
|
-- The descriptions share nothing -- physics with a character, disc frames and time windows, a
|
|
-- shoot-em-up of spawned kinds, a gun over video -- so compiling all of them here is the test
|
|
-- that the core has no genre baked into it.
|
|
-- Nothing in this scene knows what a platformer is; it drives keys and looks at the result.
|
|
dofile("Forge/AuthorCompile.singe")
|
|
|
|
local font = fontLoad("Singe/FreeSansBold.ttf", 18)
|
|
local built = {}
|
|
local out = singeGetDataPath()
|
|
|
|
fontSelect(font)
|
|
fontQuality(FONT_QUALITY_BLENDED)
|
|
overlaySetResolution(720, 480)
|
|
|
|
for _, name in ipairs({ "platformer", "qte", "shmup", "gunvideo" }) do
|
|
local game = authorLoad("testScripts/author/" .. name .. ".game")
|
|
local problems = authorCheck(game)
|
|
|
|
built[name] = authorBuild("testScripts/author/" .. name .. ".game", out .. name .. ".singe")
|
|
debugPrint("AUTHOR built " .. built[name] .. " with " .. #problems .. " problems")
|
|
for _, problem in ipairs(problems) do
|
|
debugPrint("AUTHOR FAIL " .. name .. ": " .. problem)
|
|
end
|
|
end
|
|
|
|
-- Both must at least load as Lua; a compiler that emits something unparseable is the failure this
|
|
-- catches earliest, and it costs nothing to check both even though only one is played.
|
|
for name, path in pairs(built) do
|
|
local chunk, problem = loadfile(path)
|
|
|
|
if chunk == nil then
|
|
debugPrint("AUTHOR FAIL " .. name .. " does not parse: " .. tostring(problem))
|
|
else
|
|
debugPrint("AUTHOR parsed " .. name)
|
|
end
|
|
end
|
|
|
|
-- Now run the platformer, as the engine would if it had been launched directly.
|
|
dofile(built.platformer)
|
|
|
|
local gameUpdate = onOverlayUpdate
|
|
local frames = 0
|
|
|
|
-- Driving by what the game is doing, not by a clock or a frame count.
|
|
--
|
|
-- Both of those were tried and both are wrong. A frame count is wrong because the authored game
|
|
-- moves in seconds. A clock is wrong because physics steps at most MAX_STEPS_PER_FRAME (4, so
|
|
-- 66 ms) per frame and deliberately falls behind wall clock on a machine that cannot keep up --
|
|
-- which the sanitizer build, with a disc to decode, does. A test that watches the hero instead
|
|
-- gives the same answer at any frame rate, and exercises onGround from this side as well.
|
|
local JUMP_AT = 340 -- Where the hero leaves the ground to reach the ledge.
|
|
local GIVE_UP = 20.0 -- Seconds. Generous: this is a stuck detector, not a schedule.
|
|
|
|
local held = false
|
|
local jumped = false
|
|
local won = 0
|
|
local shots = 0
|
|
|
|
|
|
function onOverlayUpdate()
|
|
local t = authorTime()
|
|
local hero = authorEntity("hero")
|
|
local hx, hy = authorPosition(hero)
|
|
|
|
frames = frames + 1
|
|
if not held then
|
|
authorKeyDown(0, SCANCODE.RIGHT.value)
|
|
held = true
|
|
end
|
|
|
|
-- Jump once, when the hero is under way and has ground beneath it.
|
|
if (not jumped) and (hx >= JUMP_AT) and playerIsOnGround(hero.node) then
|
|
authorKeyDown(0, SCANCODE.SPACE.value)
|
|
jumped = true
|
|
elseif jumped then
|
|
authorKeyUp(0, SCANCODE.SPACE.value)
|
|
end
|
|
|
|
local r = gameUpdate()
|
|
|
|
-- The engine's own text over the authored game, so a screenshot says what it is looking at.
|
|
colorForeground(255, 255, 255, 255)
|
|
fontPrint(12, 450, string.format("authored platformer, %.1fs, score %d", t, AUTHOR_VARS.score))
|
|
|
|
-- Four shots at the moments that matter, found by watching rather than by timing: the start,
|
|
-- the run, the jump, and the frame after the prize was taken.
|
|
if (shots == 0) or (shots == 1 and hx > 250) or (shots == 2 and jumped and not playerIsOnGround(hero.node)) or (shots == 3 and won > 0 and t > won + 0.3) then
|
|
shots = shots + 1
|
|
singeScreenshot()
|
|
end
|
|
if AUTHOR_VARS.won and won == 0 then
|
|
won = t
|
|
end
|
|
if (won > 0 and t > won + 0.6) or (t > GIVE_UP) then
|
|
debugPrint("AUTHOR RESULT score=" .. AUTHOR_VARS.score .. " flagWon=" .. tostring(AUTHOR_VARS.won) .. " after=" .. string.format("%.1fs", t))
|
|
singeQuit()
|
|
end
|
|
|
|
return r
|
|
end
|