Attaching Scripts
Once you have scripts discovered and loaded, you'll want to run them.
At the moment BMS supports two methods of making scripts runnable:
- Attaching them to entities via
ScriptComponent
's - Adding static scripts
And then sending script event's which trigger callbacks on the scripts.
Attaching scripts to entities
In order to attach a script and make it runnable simply add a ScriptComponent
to an entity
commands.entity(my_entity).insert(ScriptComponent::new(vec!["my_script.lua", "my_other_script.lua"]));
When this script is run the entity
global will represent the entity the script is attached to. This allows you to interact with the entity in your script easilly.
Making static scripts runnable
Some scripts do not require attaching to an entity. You can run these scripts by loading them first as you would with any other script, then either adding them at app level via add_static_script
or by issuing a AddStaticScript
command like so:
commands.queue(AddStaticScript::new("my_static_script.lua"));
The script will then be run as any other script but without being attached to any entity. and as such the entity
global will always represent an invalid entity.
Note: Internally these scripts are attached to a dummy entity and as such you can think of them as being attached to an entity with an id of 0
.
Running Scripts
Scripts can run logic either when loaded or when triggered by an event. For example the script:
print("hello from load time")
function on_event(arg1)
print("hello from event time")
print(arg1)
end
Will print "hello from load time" when the script is loaded, and "hello from event time" when the script receives an event targeting the on_event
callback with a receiver list including this script or entity.
In order to trigger on_event
you need to first define a label, then send an event containing the label:
#[derive(Reflect)]
pub struct MyReflectType;
// define the label, you can define as many as you like here
callback_labels!(OnEvent => "on_event");
// trigger the event
fn send_event(mut writer: EventWriter<ScriptCallbackEvent>, mut allocator: ResMut<AppReflectAllocator>) {
let allocator = allocator.write();
let my_reflect_payload = ReflectReference::new_allocated(MyReflectType, &mut allocator);
writer.send(ScriptCallbackEvent::new_for_all(
OnEvent,
vec![my_reflect_payload.into()],
));
}
Note the second argument is the payload we are sending with the event, in this case we are sending an arbitrary reflect type MyReflectType
. This can be any type you like, as long as it implements Reflect
.
Other variants of the ScriptValue
enum are available for sending different types of data, such as ScriptValue::Integer
for primtive, types.
Event Handlers
In order for the events you send to actually be picked up, you need to inject special systems into your application. These systems will listen for the events and trigger the appropriate callbacks on the scripts:
app.add_systems(Update, event_handler::<OnEvent, LuaScriptingPlugin>);
Note the system is parameterized by the label we defined earlier, and the scripting plugin we are using. You can add as many of these systems as you like.
The event handler will catch all events with the label OnEvent
and trigger the on_event
callback on all targeted scripts which have that callback defined.
In order to handle events in the same frame and not accidentally have events "spill over" into the next frame, you should make sure to order any systems which produce these events before the event handler systems.