Module strands
A pure Lua library to manage co-operative multitasking in games.
Used to declare a lists of sequential things for the game to do (including waiting), that can be done in parallel in the background.
Designed for point & click adventure games, but can be used in any genre. Also includes facilities for event handling through signals.
See strands_sample.lua, strands_say.lua, strands_nested.lua, and strands_signal.lua for examples of usage.
See Strand environments for more details about how and whether to use strand environments.
Functions
| inside_strand() | Check if the function invoking this is running inside a strand. |
| get_default_environment() | Get the table corresponding to the default strand environment. |
Fields
| _NAME | Library name. |
| _VERSION | Library version. |
Class Strand
| Strand.new(f, env) | Create new strand. |
| Strand.start(f[, env]) | Create and automatically start new strand. |
| Strand:update(dt) | Update the strand. |
| Strand:stop() | Stop the strand. |
| Strand:resume() | Resume a paused strand. |
| Strand:active() | Check if a strand is active. |
Class StrandRegistry
| StrandRegistry.new() | Create new strand registry. |
| StrandRegistry:create(f) | Create a new strand and add it to the registry. |
| StrandRegistry:start(f) | Create and start a new strand and add it to the registry. |
| StrandRegistry:update(dt) | Update all registered strands. |
| StrandRegistry:clear() | De-register all active strands. |
| StrandRegistry:set_environment(env) | Set the registry environment. |
| StrandRegistry:get_environment() | Get the registry environment. |
| StrandRegistry:is_running() | Check if a strand from this registry is currently running. |
Wait functions
| wait(t) | Pause strand execution for a specified amount of time. |
| wait_frame() | Pause strand execution until the next update. |
| wait_strand(strand) | Pause strand execution until another strand has finished running (or was stopped). |
| wait_signal(object, identifier) | Pause strand execution until a signal is emitted. |
| accumulator(duration, num_steps, loop) | Produces an iterator that cycles through integers by waiting a specified time between steps. |
Signals
| signals.connect(object, name, f) | Register a function to be called when a signal is emitted. |
| signals.disconnect(object, name, f) | Disconnect a function from a signal. |
| signals.emit(object, name, ...) | Emit a signal. |
| signals.clear() | Clear all registered functions. |
Functions
- inside_strand()
- Check if the function invoking this is running inside a strand.
- get_default_environment()
- Get the table corresponding to the default strand environment. This contains the wait functions.
Fields
Class Strand
- Strand.new(f, env)
-
Create new strand.
It is recommended to create strands using StrandRegistry:create instead.
Parameters:
- f: (function) function containing the commands to execute in the strand. Should not have any arguments
- env:
(optional table)
environment to load global functions from, within
f. If not provided no changes are made to the function environment.
Raises:
fmust be a functionSee also:
- Strand.start(f[, env])
-
Create and automatically start new strand.
It is recommended to create and start strands using StrandRegistry:start instead.
Parameters:
- f: same as Strand.new
- env: same as Strand.new (optional)
See also:
- Strand:update(dt)
-
Update the strand.
Meant to be called when updating the game loop, should normally be done at every frame.
If the strand is updated and reaches the end of its execution the signal with the strand as object and
"finished"as the identifier is emitted.Note: don't update strands directly if they are already being updated through StrandRegistry:update.
Parameters:
- dt: (number) time elapsed since last update. Units can be chosen by the user, but have to be consistent with the ones used in wait
Raises:
If any error is raised inside the strand - Strand:stop()
- Stop the strand. After calling this method the strand can no longer be updated. Use one of the wait functions to temporarily pause the strand.
- Strand:resume()
-
Resume a paused strand.
Same as calling
Strand:updatewithdt=0. Convenience function for starting a thread created withStrand.new. - Strand:active()
-
Check if a strand is active.
Returns:
-
(bool)
trueif the strand has not reached the end of its associated function and has not been stopped with Strand:update
Class StrandRegistry
- StrandRegistry.new()
-
Create new strand registry.
The registry is assigned the default strand environment (the one returned by get_default_environment containing the wait functions.
The environment can be changed using StrandRegistry:set_environment.
Returns:
-
(StrandRegistry)
strand registry instance
- StrandRegistry:create(f)
-
Create a new strand and add it to the registry.
The strand is created by passing the current registry environment
to Strand.new.
Parameters:
- f: (function) function associated to the strand. Should not have any arguments
Returns:
-
(Strand)
strand instance
See also:
- StrandRegistry:start(f)
-
Create and start a new strand and add it to the registry.
The strand is created by passing the current registry environment
to Strand.new.
Parameters:
- f: (function) same as StrandRegistry.new
Returns:
-
(Strand)
same as StrandRegistry.new
See also:
- StrandRegistry:update(dt)
-
Update all registered strands.
Meant to be called when updating the game loop, should normally be done at every frame.
If a strand has reached the end or has been stopped with Strand:stop it
is removed from the registry.
Strands are updated in the order they were created.
If a strand is updated and reaches the end of its execution the signal with the strand as object and
"finished"as the identifier is emitted.Parameters:
- dt: (number) same as Strand:update
- StrandRegistry:clear()
- De-register all active strands. The strands can still be updated individually through the instances obtained when they were created.
- StrandRegistry:set_environment(env)
-
Set the registry environment.
Parameters:
- env: (table or nil) table to use for the registry environment. If the registry environment is set to nil, the registry will pass a nil environment to Strand.new when creating new strands.
See also:
- StrandRegistry:get_environment()
-
Get the registry environment.
Unless changed, the default environment is the one returned by get_default_environment
and containing the wait functions,
Returns:
-
(table or nil)
current environment (
nilif no environment is set) - StrandRegistry:is_running()
-
Check if a strand from this registry is currently running.
Returns:
-
(bool)
trueif a strand from this registry is running,falseotherwise
Wait functions
- wait(t)
-
Pause strand execution for a specified amount of time.
Parameters:
- t: (number) the amount of time to wait. The units can be chosen arbitrarily, but should be consistent with Strand:update and StrandRegistry:update
Returns:
-
(number)
how much actual time has elapsed
- wait_frame()
-
Pause strand execution until the next update.
Normally the strands should be updated every frame,
which results in a pause of a single frame. Useful to
release control from the strand in a loop that should
do something each frame.
Returns:
-
(number)
duration of the wait (effectively the
dtpassed when updating the strand) - wait_strand(strand)
-
Pause strand execution until another strand has finished running (or was stopped).
Parameters:
- strand: (Strand) to wait for
Returns:
-
(number)
how much actual time has elapsed
- wait_signal(object, identifier)
-
Pause strand execution until a signal is emitted.
Parameters:
- object: object of the signal
- identifier: (string) of the signal
Returns:
-
(number)
how much actual time has elapsed
See also:
- accumulator(duration, num_steps, loop)
-
Produces an iterator that cycles through integers by waiting a specified time between steps.
To be used in a generic for loop.
Starts iterating from 1. Useful to use strands to control animations.
Note: to ensure that exactly the right amount of time is spent in each step, the iterator can skip over some steps, effectively returning the index of the steps that you would get by waiting the current total elapsed time. If not looping, the last index (
num_steps) is always returned before ending the iterator.Parameters:
- duration: (number) duration of the step. The units should be chosen consistently with Strand:update
- num_steps: (number) total number of steps to iterato over. It can be set to math.huge to leave it uncapped
- loop:
(optional bool)
trueif the itarator should restart
Returns:
- (function) the iterator
- (table) table containing the state of the iterator
- (int) the number 0
Usage:
for i in accumulator(0.5, 10) do print(i) end
-- roughly equivalent to the much more cumbersome local step_duration, num_steps = 0.5, 10 local duration = num_steps*step_duration local t = 0 local accum = 0 while t < duration do local i = math.min(math.floor(t/step_duration) + 1, num_steps) print(i) while accum < step_duration do accum = accum + wait_frame() end t = t + accum accum = accum%step_duration end
Signals
- signals.connect(object, name, f)
-
Register a function to be called when a signal is emitted.
Parameters:
- object:
object the signal is associated to (e.g., the player). Can be of any type other than
nil - name: (string) identifier of the event to signal (e.g., "finished moving"). Different objects can have the same identifier without conflicts
- f: (function) function to register
- object:
object the signal is associated to (e.g., the player). Can be of any type other than
- signals.disconnect(object, name, f)
-
Disconnect a function from a signal.
Parameters:
- object: same as signals.connect
- name: (string) identifier same as signals.connect
- f: (function) identifier same as signals.connect
- signals.emit(object, name, ...)
-
Emit a signal. Calls all connected functions.
Note: no guarantees are made on the order in which the connected functions will be called.
Parameters:
- object:
object the signal is associated to (e.g., the player). Can be of any type other than
nil - name: (string) identifier of the event to signal (e.g., "finished moving"). Different objects can have the same identifier without conflicts
- ...: arguments to pass to the registered functions when calling them
- object:
object the signal is associated to (e.g., the player). Can be of any type other than
- signals.clear()
- Clear all registered functions.