Broadcasting - Grisgram/gml-raptor GitHub Wiki
The Broadcasting
subsystem in raptor consists of three main components:
Class | Description |
---|---|
Sender |
This is your main object. The Sender is kind of a radio-station, sending out broadcasts to all listening receivers. Just create a new Sender() and add receivers to it.NOTE: gml-raptor creates one Sender in the GAMECONTROLLER object. It can be accessed through the BROADCASTER macro. This macro will always point to a valid Sender . |
Receiver |
When using the add_receiver function of your sender , a receiver is built with the given name, message_filter and callback.The callback will receive one parameter, a Broadcast instance.It offers these three values: from - The sender of the broadcasttitle - The message title/namedata - (optional) additional data structUse remove_receiver with its name to stop receiving messages in its callback. |
Broadcast |
Use the send function on a sender to send out a broadcast message.It contains three members: from - the sender of the broadcasttitle - the name of the broadcast (this one must pass the message_filter of a receiver)data - optional struct that holds any additional data for this broadcast. |
How to use the subsystem:
If you want to send something, just callBROADCASTER.send(your_sender|self, "your_message", [your_data_struct])
.
Here is a small example:
var snd = new Sender();
snd.add_receiver(self, "achievement_counter", "*_died", my_achievement_counter_function);
... when a monster dies you could invoke
snd.send(self, "dragon_died");
It is very important to know, that the name
s of your receivers must be system-wide unique!
If you add a receiver with an already existing name, it will replace the former one.
Important
Keep in mind: Adding a receiver with the same name as an existing one, will replace the existing. So take care, how you name your receivers, as this can be a useful feature, or a trap, depending on how you use it.
As an example, naming a receiver "active_weapon"
might be a good idea, as any weapon that gets activated could just add itself as a receiver under the same name and replacing the so-far active weapon with itself in one go.
On the other hand, naming a receiver in a monster "active_weapon"
is a bad idea, when there are many monsters on the screen, they would permanently replace each other for the broadcast. To have a unique name for each instance, consider using the macro MY_NAME
as part of the receiver name, like MY_NAME + "active_weapon"
, as this resolves to the object name plus the instance id and it always delivers a unique string for one object instance.
raptor
also uses the broadcasting system internally, all its messages are prefixed with __raptor_<message_name>
to avoid collisions with your own custom messages.
However, it might be handy to listen to some of the raptor
-internal messages, as some of them can be of interest for your running game.
You can find the full list of internal messages at Raptor-internal broadcasts.
In larger games, there are many messages sent through the senders and a receiver normally does not need to catch all of them.
As an example, the achievement receiver in the code shown above shall only count, when a monster dies, so it receives only messages that end with _died
.
The title of a message is a string defined by you. So you should set up a naming system for your messages to make them filterable.
The message_filter
uses the string_match
function from the string utilities script, which is also part of raptor
. This function supports four types of wildcards:
Wildcard | Syntax | Description |
---|---|---|
*anything |
* at the beginning |
Matches all string that end with "anything" |
anything* |
* at the end |
Matches all string that start with "anything" |
*anything* |
* at the beginning and the end |
Matches all string that contain "anything" |
anything |
No * at all |
Exact match |
var snd = new Sender();
The Sender
has no constructor parameters. You can create as many as you like.
Important
Keep in mind, one sender is created for you by raptor. You can reach it through the BROADCASTER
macro.
In most games, this one global broadcaster will be sufficient.
Tip
If your callback function returns true
, this receiver will be removed after processing the message. This is a comfortable shortcut to remove a receiver, after its work is done.
As an example, if the achievement "Kill 100 Monsters" is reached, this receiver no longer must count dying monsters, so it can be removed.
Instead of keeping the receiver in an instance variable and then referencing it from within the callback, simply return true
, when the work is done.
If the callback function doesn't return anything, the receiver stays in the queue (which is the default).
BROADCASTER.add_receiver(self, "kill_monsters_achievement_counter", "*_died",
function(broadcast) {
// Here you can access all data in the broadcast like this:
// broadcast.from --> contains the sender of the message
// broadcast.title --> the title of the message (like "dragon_died")
// broadcast.data --> an optional data struct containing additional info or <undefined>
}
The add_receiver
method returns self
for call chaining, so you can add multiple receivers in one go, like you do with the StateMachine.
The Broadcast
is the object sent to your callback method, when you Send
a broadcast.
It contains these members:
Member | Datatype | Contains |
---|---|---|
uniqueid |
integer | Every broadcast has a uniqueid. It's a numeric value, unique for each send call, counting up |
handled |
bool | Initialized with false . Set it to true, to mark this broadcast as being done .The send loop will abort then and stop sending this broadcast to the remaining recipients |
from |
object instance | The sender of this broadcast |
title |
string | The string you set as title argument to the send method |
data |
struct | Any custom data struct you supplied to the send method |
When you send
this broadcast...:
BROADCASTER.send(self, "monster_died", { monster_id: 42 }));
...this will be received by all registered receivers, whose filter matches:
{
sender = (whoever has been `self` in the send-call above)
title = "monster_died" (as string)
handled = false
uniqueid = integer number
data = {
monster_id: 42
}
}