Animancer Parameters are strongly typed, named values stored in a central dictionary for scripts to get, set, and watch for changes.
- Mixer States and Controller States can link their internal parameters to Animancer Parameters so that:
- Other scripts can control their values without needing direct access to the states.
- Multiple states can be linked to the same parameter.
- The Linear Mixer sample demonstrates this feature in action.
- The dictionary uses String References as its keys.
- A parameter of any type can be created, but it can then only contain values of that type.
Cached Example
The most efficient way to access frequently used parameters is to store them in a Parameter<T>
field, where T
is the Generic Argument specifying the type of value it will contain.
public class CachedParameterExample : MonoBehaviour
{
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private StringAsset _ParameterName;
private Parameter<float> _Parameter;
On startup, you access the AnimancerComponent.Parameters
dictionary to GetOrCreate
the parameter you want, meaning that whatever system access a parameter with a particular name first will create it then any other system to use the same name will be given the same parameter.
protected virtual void Awake()
{
_Parameter = _Animancer.Parameters.GetOrCreate<float>(_ParameterName);
Then you can listen for any changes to the parameter using its OnValueChanged
event.
_Parameter.OnValueChanged += OnParameterChanged;
}
private void OnParameterChanged(float value)
{
Debug.Log(value);
}
Or get and set its Value
whenever you want.
protected virtual void Update()
{
_Parameter.Value = Time.timeSinceLevelLoad;
}
}
Lazy Example
You can also interact with parameters in the dictionary instead of caching them in a field. This can simplify the code, but is less efficient if it needs to look up the parameter every time.
If the above example wasn't setting the Value
and only needed to listen for OnValueChanged
, it could use AddOnValueChanged
without losing any efficiency.
public class LazyParameterExample : MonoBehaviour
{
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private StringAsset _ParameterName;
protected virtual void Awake()
{
_Animancer.Parameters.AddOnValueChanged<float>(_ParameterName, OnParameterChanged);
}
private void OnParameterChanged(float value)
{
Debug.Log(value);
}
It could also use SetValue
, but doing that every frame in Update
would be inefficient because it needs to internally find the parameter from the name every time. Dictionaries allow for fast lookups, but they're still slower than keeping a direct reference.
protected virtual void Update()
{
_Animancer.Parameters.SetValue(_ParameterName, Time.timeSinceLevelLoad);
}
}
Smoothing
Changing a parameter value takes effect immediately, so if you want it to change gradually over time you can use a SmoothedFloatParameter
or SmoothedVector2Parameter
as demonstrated in the Directional Mixer and Brains samples.
public class ParameterSmoothingExample : MonoBehaviour
{
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private StringAsset _Parameter;
[SerializeField] private float _ParameterSmoothTime = 0.15f;
Initializing a SmoothedFloatParameter
takes the AnimancerComponent
containing the parameter, a String Reference or Asset to specify its name, and the approximate amount of time you want it to take to reach the target value using the internan Mathf.SmoothTime
.
private SmoothedFloatParameter _SmoothedParameter;
protected virtual void Awake()
{
_SmoothedParameter = new SmoothedFloatParameter(
_Animancer,
_Parameter,
_ParameterSmoothTime);
}
You can then set the TargetValue
on the smoother or simply set the parameter value normally to have it smoothly move towards that value.
protected virtual void Update()
{
_SmoothedParameter.TargetValue = 0;
_Animancer.Parameters.SetValue(_Parameter, 0);
Or you can set the CurrentValue
to move it immediately and cancel any active smoothing.
_SmoothedParameter.CurrentValue = 0;
}
}
Using SmoothedVector2Parameter
is the same as all that, except it takes two parameter names in the constructor and the value is a Vector2
.
Debugging
Since this system is designed to be accessed from anywhere, it's unfortunately easy to end up in situations where parameters are given unexpected values. That's why there's an inbuilt logging system which can be turned on for a particular parameter to log any time something gets or sets its value as well as any OnValueChanged
listeners that are added or removed.
How to enable parameter logging
Logging can be enabled via the Inspector or via code.
In the Live Inspector you can Right Click on a parameter and select the Log Interactions
function from the Context Menu.
In code, you can set the parameter's LogContext
like this:
public class DebuggingParameterExample : MonoBehaviour
{
[SerializeField] private AnimancerComponent _Animancer;
[SerializeField] private StringAsset _ParameterName;
private Parameter<float> _Parameter;
protected virtual void Awake()
{
_Parameter = _Animancer.Parameters.GetOrCreate<float>(_ParameterName);
_Parameter.LogContext = this;
}
}
You can assign any type of object as the context such as a component or string
and it will be used as a prefix for that parameter's log messages in case you need to debug multiple parameters at the same time.
When is this logging available
By default, this logging is available in the Unity Editor and in Development Builds, but not regular Release Builds.
If you need to use it in a Release Build you can define ANIMANCER_DEBUG_PARAMETERS
as a Custom Scripting Symbol in your project. Unfortunately, this requires Animancer Pro as the scripts need to be recompiled with that symbol active which can't happen with the pre-compiled DLLs in Animancer Lite.
Inspector Control Only
It can also sometimes be useful to prevent all scripts from setting a parameter so that you can control it manually in the Inspector and observe the effects.
This can be done by enabling Inspector Control Only
via the same context menu as explained above or in code by setting the _Parameter.InspectorControlOnly = true;
.