(Note. if you are doing lots of that "if whatever.state then ..." you might want to give a look to "stateful.lua".http.//github.com/kikito/stateful.lua )
This library tries to solve the following problem. some actions need to be executed when some asynchronous condition is fulfilled. By "asyncronous" we mean that it something that typically doesn't depend on the code. Hence precalculating it beforehand is impractical.
The way these problems are typically handed is by continuously polling for the trigger condition. For example, on the pause menu, one would find this code on the enemy movement routines.
But the biggest problem with that code is lack of separation. The code dealign with your goblins should only deal with goblin stuff. It should not "know" about the menu system, or the keyboard actions, or the file loader. And the same goes with your bullet code, player code, etc. They don't need to know about exernal systems, such as the keyboard.
This library allows you to build "walls" between them. your keyboard code will just raise events, and your player code will observe those events. This allows for better encapsulation; if you later add multiplayer functionality, for example, the network module will just have to raise the same events just like the keyboard module did; your player logic will be unaffected.
A very common situation in programming is that you want to attach observations and events to a particular subject: for example, you want a button to observe a mouseclick, but only until that button is garbage-collected.
Having to store the @id@ of the observed button and using it to call @beholder.stopObserving(id)@ when the button is destroyed is tiresome and clunky:
<pre>
local button = buildAButton(callback)
local id = beholder.observe('mouseclick', function(x,y)
if isInside(button, x, y) then
callback()
end
end)
...
beholder.stopObserving(id)
button = nil
</pre>
It would be much better if beholder provided a way to "observe events while an object exists", and cancelling those observations automatically when the object stops existing.
This is possible through the @beholder.observeSubject@ method:
Events can be any type of Lua object. On the example, we used the "PAUSE" string. It could also be a number, a function or a table. The == operator is used in all cases.
Composed events are built from more than one lua object. You can do them by simply adding more parameters to the observe/trigger functions. For example, this trigger.
Notice that the two "non-observed integers" will be passed to the callback as additional parameters. That second action will be executed any time player1 is detected, no matter what coordinates.
If you want to detect all signals raised (i.e. for logging and debugging) you can do so by observing the "empty" event - simply pass a function to observe, without adding any more params.
Note that you can pass parameters to @triggerAll@. These will be passed to all callbacks (make sure that they are prepared for this, or you will get errors).
On this example I've assigned it to a local variable. If you are going to use beholder across multiple files, it's better to require the file just once and make the variable global.
This project uses "telescope".https.//github.com/norman/telescope for its specs. If you want to run the specs, you will have to install telescope first. Then just execute the following from the root inspect folder.