// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik // using System.Collections.Generic; using System.Text; using UnityEngine; namespace Animancer { /// [Pro-Only] /// An which blends an array of other states together /// based on a two dimensional parameter and thresholds. /// /// /// Documentation: /// /// Mixers /// /// https://kybernetik.com.au/animancer/api/Animancer/Vector2MixerState /// public abstract class Vector2MixerState : MixerState, ICopyable { /************************************************************************************************************************/ /// .x. public float ParameterX { get => Parameter.x; set => Parameter = new(value, Parameter.y); } /// .y. public float ParameterY { get => Parameter.y; set => Parameter = new(Parameter.x, value); } /************************************************************************************************************************/ #region Parameter Binding /************************************************************************************************************************/ private NodeParameter _ParameterBindingX; /// /// If set, this will be used as a key in the so any /// changes to that parameter will automatically set the . /// public StringReference ParameterNameX { get => _ParameterBindingX.Key; set { if (_ParameterBindingX.SetKeyCheckNeedsInitialize(value)) _ParameterBindingX.Initialize(this, parameter => ParameterX = parameter); } } /************************************************************************************************************************/ private NodeParameter _ParameterBindingY; /// /// If set, this will be used as a key in the so any /// changes to that parameter will automatically set the . /// public StringReference ParameterNameY { get => _ParameterBindingY.Key; set { if (_ParameterBindingY.SetKeyCheckNeedsInitialize(value)) _ParameterBindingY.Initialize(this, parameter => ParameterY = parameter); } } /************************************************************************************************************************/ /// public override void SetGraph(AnimancerGraph graph) { if (Graph == graph) return; _ParameterBindingX.UnBindIfInitialized(); _ParameterBindingY.UnBindIfInitialized(); base.SetGraph(graph); _ParameterBindingX.BindIfInitialized(); _ParameterBindingY.BindIfInitialized(); } /************************************************************************************************************************/ /// public override void Destroy() { base.Destroy(); _ParameterBindingX.UnBindIfInitialized(); _ParameterBindingY.UnBindIfInitialized(); } /************************************************************************************************************************/ /// public sealed override void CopyFrom(MixerState copyFrom, CloneContext context) => this.CopyFromBase(copyFrom, context); /// public virtual void CopyFrom(Vector2MixerState copyFrom, CloneContext context) { base.CopyFrom(copyFrom, context); ParameterNameX = copyFrom.ParameterNameX; ParameterNameY = copyFrom.ParameterNameY; } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ /// Gets the lowest and highest threshold values on each axis. public void GetThresholdBounds(out Vector2 min, out Vector2 max) { var i = ChildCount - 1; min = max = GetThreshold(i); i--; for (; i >= 0; i--) { var threshold = GetThreshold(i); if (min.x > threshold.x) min.x = threshold.x; if (min.y > threshold.y) min.y = threshold.y; if (max.x < threshold.x) max.x = threshold.x; if (max.y < threshold.y) max.y = threshold.y; } } /// public override Vector2 NormalizedParameter { get { GetThresholdBounds(out var min, out var max); var value = Parameter; return new( AnimancerUtilities.InverseLerpUnclamped(min.x, max.x, value.x), AnimancerUtilities.InverseLerpUnclamped(min.y, max.y, value.y)); } set { GetThresholdBounds(out var min, out var max); Parameter = new( Mathf.LerpUnclamped(min.x, max.x, value.x), Mathf.LerpUnclamped(min.y, max.y, value.y)); } } /************************************************************************************************************************/ /// public override string GetParameterError(Vector2 value) => value.IsFinite() ? null : $"value.x and value.y {Strings.MustBeFinite}"; /************************************************************************************************************************/ /// public override void AppendParameter(StringBuilder text, Vector2 parameter) { text.Append('(') .Append(parameter.x) .Append(", ") .Append(parameter.y) .Append(')'); } /************************************************************************************************************************/ #region Inspector /************************************************************************************************************************/ /// public override void GetParameters(List parameters) { parameters.Add(new( "Parameter X", ParameterNameX, AnimatorControllerParameterType.Float, ParameterX)); parameters.Add(new( "Parameter Y", ParameterNameY, AnimatorControllerParameterType.Float, ParameterY)); } /// public override void SetParameters(List parameters) { var parameter = parameters[0]; ParameterNameX = parameter.name; ParameterX = (float)parameter.value; parameter = parameters[1]; ParameterNameY = parameter.name; ParameterY = (float)parameter.value; } /************************************************************************************************************************/ #endregion /************************************************************************************************************************/ } }