using System; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; namespace Animation { // 제네릭인 P 는 값 형식이면서 Enum을 상속한 타입이어야 한다. public class AnimatorManager
where P : struct, Enum { private readonly Animator animator; // 마지막 세팅 값을 저장해 불필요한 동작 방지용 private readonly Dictionary
cache = new(); // 키별 실제 타입을 매핑해두는 용도 private readonly Dictionary
types = new(); // 없는 키를 경고하기 위한 용도 (Enum에는 있는데 Animator에는 없는 경우) private readonly HashSet
missing = new();
// 없는 키를 경고하기 위한 용도 (Animator에는 있는데 Enum에는 없는 경우)
private readonly HashSet (param.name, out var key))
{
types[key] = param.type;
switch (param.type)
{
case AnimatorControllerParameterType.Bool:
cache[key] = animator.GetBool(param.name);
break;
case AnimatorControllerParameterType.Float:
cache[key] = animator.GetFloat(param.name);
break;
case AnimatorControllerParameterType.Int:
cache[key] = animator.GetInteger(param.name);
break;
}
}
else
{
extras.Add(param.name);
}
}
foreach (P enumKey in (P[])Enum.GetValues(typeof(P)))
{
if (!types.ContainsKey(enumKey))
missing.Add(enumKey);
}
}
public void SetValue(P key, object value)
{
if (animator == null) throw new InvalidOperationException("Animator is null");
// missing은 가능하나 extras는 불가능(변수가 P 로 들어오기에 Animator에는 있는데 Enum에 없는 경우는 불가능)
if (missing.Contains(key)) throw new KeyNotFoundException("key is missing in animator: " + key);
string name = key.ToString();
switch (types[key])
{
case AnimatorControllerParameterType.Bool:
{
var newVal = Convert.ToBoolean(value);
if (!cache.TryGetValue(key, out var oldVal) || !Equals(newVal, (bool)oldVal))
{
animator.SetBool(name, newVal);
cache[key] = newVal;
}
break;
}
case AnimatorControllerParameterType.Float:
{
var newVal = Convert.ToSingle(value);
if (!cache.TryGetValue(key, out var oldVal) || !Mathf.Approximately(newVal, (float)oldVal))
{
animator.SetFloat(name, newVal);
cache[key] = newVal;
}
break;
}
case AnimatorControllerParameterType.Int:
{
var newVal = Convert.ToInt32(value);
if (!cache.TryGetValue(key, out var oldVal) || !Equals(newVal, (int)oldVal))
{
animator.SetInteger(name, newVal);
cache[key] = newVal;
}
break;
}
case AnimatorControllerParameterType.Trigger:
{
var newVal = Convert.ToBoolean(value);
if (newVal) animator.SetTrigger(name);
else animator.ResetTrigger(name);
break;
}
}
}
public object GetValue(P key)
{
if (types[key] != AnimatorControllerParameterType.Trigger)
{
return cache[key];
}
else
{
throw new InvalidOperationException("Trigger type cannot be get");
}
}
}
}