226 lines
6.5 KiB
C#
226 lines
6.5 KiB
C#
using System.Collections.Generic;
|
|
using Superlazy;
|
|
using UnityEngine;
|
|
|
|
public interface IUnitAnimatorBinder
|
|
{
|
|
void AddUpdate(IUnitViewUpdator updator);
|
|
|
|
void RemoveUpdate(IUnitViewUpdator updator);
|
|
|
|
bool UseAnimation { get; }
|
|
bool RequireReset { get; }
|
|
string Animation { get; }
|
|
int CurrentFrame { get; }
|
|
bool UseActionAnimationBegin { get; }
|
|
float ActionAnimationBegin { get; }
|
|
bool UseCrossFade { get; } // actionStop == false
|
|
float CrossFade { get; }
|
|
bool ActionStop { get; }
|
|
bool Loop { get; }
|
|
}
|
|
|
|
public interface IUnitViewUpdator
|
|
{
|
|
void OnUpdate();
|
|
}
|
|
|
|
public class UnitAnimatorController : MonoBehaviour, IUnitViewUpdator
|
|
{
|
|
private static readonly float frameTime = 1.0f / 60.0f;
|
|
private static readonly int[] animHashes = new int[] { Animator.StringToHash("Anim1"), Animator.StringToHash("Anim2") }; // Anim1, Anim2의 애니메이터 해시
|
|
|
|
private IUnitAnimatorBinder unitView;
|
|
|
|
private Animator animator;
|
|
private AnimatorOverrideController overrideController;
|
|
|
|
private int animatorFrame;
|
|
private float animatorTime;
|
|
private string currentAnim;
|
|
|
|
private AnimationClip[] clips;
|
|
|
|
private int animIndex = 0;
|
|
private bool requireReset = false;
|
|
|
|
private List<(Transform t, Vector3 p, Quaternion r, Vector3 s)> bindPoses;
|
|
|
|
private void Awake() // TODO: 빌드시점으로 옮길수 있으면 좋음
|
|
{
|
|
animator = GetComponentInChildren<Animator>();
|
|
animatorFrame = 0;
|
|
currentAnim = null;
|
|
animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; // cullingMode가 걸려있는경우 꺼졌다가 켜진 상태에서 모든 동작이 X
|
|
if (animator.runtimeAnimatorController == null)
|
|
{
|
|
overrideController = new AnimatorOverrideController(SLResources.GetAnimatorController("BaseController"));
|
|
animator.runtimeAnimatorController = overrideController;
|
|
|
|
clips = overrideController.animationClips;
|
|
}
|
|
|
|
if (bindPoses == null)
|
|
{
|
|
var allChildren = animator.GetComponentsInChildren<Transform>();
|
|
bindPoses = new List<(Transform t, Vector3 p, Quaternion r, Vector3 s)>();
|
|
foreach (var child in allChildren)
|
|
{
|
|
bindPoses.Add((child, child.localPosition, child.localRotation, child.localScale));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
unitView = GetComponentInParent<IUnitAnimatorBinder>();
|
|
if (unitView == null) // Tool 등에서 유닛이 없는 경우 사용하지 않도록 설정
|
|
{
|
|
return;
|
|
}
|
|
|
|
unitView.AddUpdate(this);
|
|
}
|
|
|
|
private void ResetPose()
|
|
{
|
|
if (bindPoses == null) return;
|
|
foreach (var (t, p, r, s) in bindPoses)
|
|
{
|
|
t.localPosition = p;
|
|
t.localRotation = r;
|
|
t.localScale = s;
|
|
}
|
|
}
|
|
|
|
private bool UpdateCurrAnimation()
|
|
{
|
|
if (unitView.CurrentFrame - 1 - animatorFrame >= 0 && unitView.Animation == currentAnim) return false;
|
|
|
|
ChangeController(unitView.Animation);
|
|
currentAnim = unitView.Animation;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void ChangeController(string clipName)
|
|
{
|
|
var clip = SLResources.Load<AnimationClip>(clipName);
|
|
if (clip == null)
|
|
{
|
|
SLLog.Error($"Can't Find: {clipName}.anim", this);
|
|
return;
|
|
}
|
|
|
|
if (requireReset)
|
|
{
|
|
ResetPose();
|
|
}
|
|
|
|
requireReset = unitView.RequireReset;
|
|
|
|
animIndex = (animIndex + 1) % 2;
|
|
|
|
overrideController[clips[animIndex]] = clip;
|
|
|
|
var startTime = 0.0f;
|
|
if (unitView.UseActionAnimationBegin)
|
|
{
|
|
startTime = (unitView.ActionAnimationBegin - 1) / 60.0f;
|
|
}
|
|
|
|
var currentFrame = unitView.CurrentFrame - 1;
|
|
startTime += currentFrame / 60.0f;
|
|
|
|
if (currentAnim != null && unitView.UseCrossFade && unitView.ActionStop == false)
|
|
{
|
|
animator.CrossFadeInFixedTime(animHashes[animIndex], unitView.CrossFade, 0, startTime);
|
|
}
|
|
else
|
|
{
|
|
animator.PlayInFixedTime(animHashes[animIndex], 0, startTime);
|
|
}
|
|
|
|
animator.speed = 1;
|
|
animator.Update(0.0f); // 업데이트를 돌때 속도가 0이면 시작 시간이 동작하지 않는다
|
|
animator.speed = 0f;
|
|
|
|
animatorFrame = currentFrame;
|
|
animatorTime = currentFrame * frameTime;
|
|
}
|
|
|
|
private void UpdateAnimator()
|
|
{
|
|
var currentFrame = unitView.CurrentFrame - 1;
|
|
var deltaFrame = currentFrame - animatorFrame;
|
|
|
|
var deltaTime = Time.deltaTime;
|
|
if (deltaFrame > 0 && Time.timeScale <= 0.01f)
|
|
{
|
|
animator.updateMode = AnimatorUpdateMode.UnscaledTime;
|
|
deltaTime = Time.unscaledDeltaTime;
|
|
}
|
|
else
|
|
{
|
|
animator.updateMode = AnimatorUpdateMode.Normal;
|
|
}
|
|
|
|
if (deltaTime > 0.0000001f)
|
|
{
|
|
if (deltaFrame < 1)
|
|
{
|
|
if ((Time.timeScale < 1 || currentFrame == -1) && unitView.ActionStop == false) // 프레임이 없거나 슬로우 상태
|
|
{
|
|
animatorTime += deltaTime;
|
|
animator.speed = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
animator.speed = 0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (currentFrame * frameTime - animatorTime >= 0)
|
|
{
|
|
animator.speed = (currentFrame * frameTime - animatorTime) / deltaTime;
|
|
animatorFrame = currentFrame;
|
|
animatorTime = currentFrame * frameTime;
|
|
}
|
|
else
|
|
{
|
|
animator.speed = 0;
|
|
animatorFrame = currentFrame;
|
|
}
|
|
}
|
|
|
|
if (unitView.Loop)
|
|
{
|
|
var time = animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
|
|
if (time > 1.0f && animator.IsInTransition(0) == false)
|
|
{
|
|
animator.Play(animHashes[animIndex], 0, time - Mathf.Floor(time));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void OnUpdate()
|
|
{
|
|
if (unitView.UseAnimation == false) return;
|
|
|
|
//UpdateCurrAnimation();
|
|
if (UpdateCurrAnimation() == false)
|
|
{
|
|
UpdateAnimator();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
unitView.RemoveUpdate(this);
|
|
unitView = null;
|
|
currentAnim = null;
|
|
ResetPose();
|
|
}
|
|
} |