Love2D and its 3D/VR companion LOVR are great. I won't blab about how awesome they are - though having an entirely open framework means certain things must be built from scratch. One such thing is an event handling system.
Engines like Unity use a class inheritance to handle this. Every object in a scene is a GameObject, which has an inherited update method to process itself every frame.
It's possible to do this without much trouble by architecting all of your game entities in a similarly OOP way, but this isn't always intuitive, and can cause unnecessary headache and overhead if your game isn't overly complex, or you want more manual control over your event stacks.
Here's a super simple event stack example using anonymous functions and an event stack table (named 'queue'):
table.insert(queue, function() <code> end)
The most frequent use would likely be to add a global wait in between code blocks:
table.insert(queue, function() wait = 1 end)
This also makes calling functions with parameters and so forth very simple:
table.insert(queue, function()
sfx:play()
ComplexFunction(a, 'b', { c = 0 })
end)
Then in update:
love.update(TimeDelta)
if wait > 0 then
wait = wait - TimeDelta
love.draw() -- Continue to draw, but don't process stack
return
end
if #queue > 0 then
if type(queue[1])=='function' then
local f = queue[1]
table.remove(queue, 1)
f()
end
end
end
This code is the basis for most of the animation in my game, or when there needs to be a timed wait e.g. to suspend input tracked by variable named inputEnabled for one second:
function q(o) table.insert(queue, o) end
function setinput(tf) inputEnabled = tf end
q(function() setinput(false) end)
q(function() wait = 1 end)
q(function() setinput(true) end)
Lua allows lots of room for freedom in styling your code however you wish.