Sep 16, 2020.Knowledge
When animating a property in Sequencer, it’s sometimes desirable to have extra behavior surrounding the change instead of just setting the value. This can be useful if you want the object to react to changes made to the property, or you want to define different behaviors for how a property is handled. For example, if you wanted to have a transform that was applied in different coordinate spaces like world, and local.
By default, animating a property in Sequencer only sets the property’s value directly; however, additional behavior can be defined in a function that Sequencer will call instead. If Sequencer finds a UFunction named Set[PropertyName], that function will be called instead of setting the value directly. Sequencer should also recognize if a property has a setter defined with the BlueprintSetter property specifier.
This is better than having the actor poll the value of the property while ticking for example, as the function is only called when the property changes. It has its drawbacks, though, since Sequencer searches for these functions by name, this can lead to a function being unintentionally called.
We are in the works of developing a new method of evaluation that allows for a more robust way to define how property changes are applied. Until then, setter functions are the best supported way to accomplish this.
For reference, the setter function is searched for in FTrackInstancePropertyBindings::CacheBinding. This looks for a function on the bound object that matches the name FunctionName. The FunctionName is set in the FTrackInstancePropertyBindings constructor. If a name is passed in, it uses that name, otherwise it looks for one named Set[PropertyName]. Here’s the relevant code from the constructor:
static const FString Set(TEXT(“Set”));
const FString FunctionString = Set + PropertyName.ToString();
FunctionName = FName(*FunctionString);
You can define the function in either C++ or Blueprints. We have existing documentation that references these functions (it refers to them as Proxy Functions) in the context of blending character animation and a level sequence, but this article will outline more generic and direct steps. For the steps outlined in the linked doc, start in section 2 step 6. Please note that the documentation misses some important steps for previewing in editor.
Create your property, either as a UProperty in C++ or as a Blueprint variable. This will need to be exposed to cinematics, either through the flag “Expose to Cinematics” in Blueprints, or with the interp property specifier in C++.
The docs page wants you to make it editable by marking it as “Instance Editable” in Blueprint. For C++ you can add the EditAnywhere property specifier.
Create the UFunction setter. Make sure it’s named Set[PropertyName]. For example, if the UProperty from step 1 was named FloatToAnimate, then the UFunction should be named SetFloatToAnimate. This needs to take an input of the same type as the property you are animating. For Blueprints this function needs to have Call in Editor checked on it for it to work when previewing the sequence in editor. In C++ you can do the same with the CallInEditor function specifier.
Set the value of the property you are changing. The linked doc skips this step, and since it doesn’t need to preview in the editor, it isn’t an issue, but the Sequencer UI uses this value to display in the timeline. Without this step when the sequence is playing or being scrubbed in the editor, the value shown in the UI will never change.