To throw some ideas out there, here's what I'm currently doing:
* Levels are scripted using Lua.
* Use coroutines so logic can wait and resume.
* Can have many coroutines running at once.
Example level:
function background0(script, args)
setBackground("image.png")
setBackgroundSpeed(100)
wait(1000)
setBackgroundSpeed(200)
end
function spawnWave(script, args)
for i=1,10 do
spawn("enemy1", position={args.x, 100}, path="path_name")
wait("milli", 200)
end
end
function spawnBoss(scripts, args)
spawn("boss")
wait("second", 10)
spawn("boss2")
end
function run(script, args)
script(background0)
script(spawnWave, {x = 0})
script(spawnWave, {x = 100})
wait("all enemies dead")
script(spawnBoss)
wait("all enemies dead")
nextStage("stage2")
end
return run
The above script will spawn two waves of enemies at the same time. Each wave will spawn a single enemy every 200 milliseconds, and finish when 10 enemies have been spawned. When all those enemies die, a boss will be spawned. After 10 a second boss enemy is spawned. When they're dead the level is complete.
* The script() call starts a new coroutine.
* The wait() call yields the coroutine.
* The game will resume a coroutine when its wait condition is met.
* You can have many scripts running "concurrently". By concurrently here I mean each time the game's logic is updated, each coroutine will be run sequentially until it waits or finishes.
* Can add in whatever different wait conditions you like.
* Whatever the script returns is the first coroutine that gets run.
This allows scripting levels temporally but does not tie things to real time. Wait conditions such as "wait for all enemies to die" is useful in many situations. It's easy enough to skip parts of levels by commenting stuff out (this will depend on how well you organise the scripts). Since it's in lua, pretty much everything is done already, except the logic to run and check coroutine wait conditions.