133 lines
2.8 KiB
C#
Raw Permalink Normal View History

2025-09-24 11:24:38 +05:00
namespace Fusion.Addons.AnimationController
{
using System;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
[Serializable]
public sealed class BlendTreeSet
{
// PUBLIC MEMBERS
public BlendTreeNode[] Nodes => _nodes;
public AnimationMixerPlayable Mixer => _mixer;
public AnimationBlendTree BlendTree => _blendTree;
// PRIVATE MEMBERS
[SerializeField]
private float _speed;
[SerializeField]
private BlendTreeNode[] _nodes;
private AnimationMixerPlayable _mixer;
private AnimationBlendTree _blendTree;
private bool _isCacheValid;
private float _cachedTargetLength;
private Vector2 _cachedPosition;
// PUBLIC METHODS
public void CreatePlayable(AnimationController controller)
{
int nodeCount = _nodes.Length;
_mixer = AnimationMixerPlayable.Create(controller.Graph, _nodes.Length);
Vector2[] blendTreePositions = new Vector2[nodeCount];
for (int i = 0; i < nodeCount; ++i)
{
BlendTreeNode node = _nodes[i];
node.CreatePlayable(controller.Graph);
blendTreePositions[i] = node.Position;
_mixer.ConnectInput(i, node.PlayableClip, 0);
}
_blendTree = new AnimationBlendTree(blendTreePositions);
}
public void DestroyPlayable()
{
if (_mixer.IsValid() == true)
{
_mixer.Destroy();
}
for (int i = 0, count = _nodes.Length; i < count; ++i)
{
_nodes[i].DestroyPlayable();
}
}
public void SetSpeed(float speed)
{
_blendTree.SetScale(speed);
_isCacheValid = false;
}
public void ResetSpeed()
{
SetSpeed(_speed);
}
public float SetPosition(Vector2 position)
{
float targetLength = 0.0f;
if (_isCacheValid == true && AlmostEquals(position, _cachedPosition, 0.01f) == true)
{
targetLength = _cachedTargetLength;
}
else
{
_blendTree.CalculateWeights(position);
float[] weights = _blendTree.Weights;
for (int i = 0, count = _nodes.Length; i < count; ++i)
{
float weight = weights[i];
if (weight > 0.0f)
{
targetLength += _nodes[i].Length / _nodes[i].Speed * weight;
}
_mixer.SetInputWeight(i, weight);
}
_isCacheValid = true;
_cachedPosition = position;
_cachedTargetLength = targetLength;
}
return targetLength;
}
public void SetTime(float animationTime)
{
for (int i = 0, count = _nodes.Length; i < count; ++i)
{
if (_blendTree.Weights[i] > 0.0f)
{
BlendTreeNode node = _nodes[i];
node.PlayableClip.SetTime(animationTime * node.Length);
}
}
}
// PRIVATE METHODS
private static bool AlmostEquals(Vector2 vectorA, Vector2 vectorB, float tolerance = 0.01f)
{
Vector2 difference = vectorA - vectorB;
return difference.x < tolerance && difference.x > -tolerance && difference.y < tolerance && difference.y > -tolerance;
}
}
}