Record Animation: Trigger Setup
Following the previous tutorial, you should have a working animation. Now, say you wanted to be able to have effects be activated as your coaster train moves along the track. How would you do so?
Triggers!
What are triggers?
Triggers are markers in an animation that, when passed, will fire a Signal that can be used to activate effects. They are similar to KeyframeMarkers in Roblox Animations.
Recording Triggers
Triggers are recorded on an animation by adding them to a TriggerRecorder
. This is then attached to an animation when you export.
You can look at the API for TriggerRecorder
here: TriggerRecorder docs
Triggers are manually added to a TriggerRecorder via the :add()
method. You may have already seen this used within the template to "simulate" the station hold:
-- add a wait in the station for 20 seconds
triggerRecorder:add("StationHeld", keyframeRecorder:getLength())
keyframeRecorder:append(KeyframeRecorder.fromTimeAmount(startKeyframe, 20, RECORD_INTERVAL))
triggerRecorder:add("StationReleased", keyframeRecorder:getLength())
add()
takes two arguments. The first is the name
of the trigger.
The second is the time position
value within the animation. You can see the station triggers use the current length of the KeyframeRecorder before and after adding keyframes to it.
Contrary to what you might think, this second argument is NOT the track position. This makes it difficult to add triggers as their time positions will change when you modify the ride's physics. Additionally, it would be difficult to get the exact time a train crosses a position as much of this is hidden in the simulation.
Instead, we use the GetPassedTriggersBuilder
class, which does this for us.
Recording Using GetPassedTriggersBuilder
The GetPassedTriggersBuilder
allows you to record triggers at track positions instead of time positions by getting when a train reaches that position in a KeyframeRecorder
.
The docs can be found here: GetPassedTriggersBuilder Docs
It has already been implemented in the template. You can see it by going to this section of the template:
-- record passed triggers
local passedTriggerRecorder = GetPassedTriggersBuilder.new()
:withKeyframeRecorder(keyframeRecorder)
:withCFrameTrack(TRACK)
--:withTrigger("Trigger1", 100)
--:withTrigger("Trigger2", 200)
:build()
:unwrap()
triggerRecorder:combine(passedTriggerRecorder)
The first thing you will notice is that it uses the Builder
pattern for better chaining. To set it up, we need to pass in two objects: our KeyframeRecorder
, which will search through when it passes our position and our Track
, which will restrict which track to look at to isolate positions. We pass it in through withKeyframeRecorder
and withCFrameTrack
respectively.
To add triggers, we call the withTrigger
method on our Builder which should be commented out. withTrigger
takes two arguments similar to TriggerRecorder
's add
method. However, compared to TriggerRecorder
the second is the track position.
We will uncomment one of the withTrigger
lines and modify it with the following:
:withTrigger("MY_TRIGGER", 400)
Once you have added your triggers, re-run the program in the plugin and your triggers should be there.
Connecting To Triggers
After you have recorded your triggers, now you can connect to them in your RidePlayer scripts to activate your effects. To do so, we call the :getTrigger()
method of ModelAnimationPlayer
. This is similar to AnimationTrack:GetMarkerReachedSignal().
Here's an example of a trigger being used:
local animPlayer = rideManager:getAnimationPlayer("Train1")
animPlayer:getTrigger("MY_TRIGGER"):Connect(function()
-- do something here!
end)
In this example, we get our ModelAnimationPlayer
from our RideManager
(this works on both server and client). Then we get our trigger by calling getTrigger
and passing in the name of it MY_TRIGGER
. This returns a Signal
that we will :Connect()
to with the code we want to call each time this trigger fires.