using System; using System.Collections; using Sirenix.OdinInspector; using Spine; using Spine.Unity; using UnityEngine; using AnimationState = Spine.AnimationState; namespace BlueWater.Players { public class SpineController : MonoBehaviour { // Variables #region Variables // Components [SerializeField] private SkeletonAnimation _skeletonAnimation; private AnimationState _animationState; // Variables [SerializeField] private string _initialSkinName = "default"; #endregion // Unity events #region Unity events private void Awake() { InitializeComponents(); } #endregion // Initialize methods #region Initialize methods [Button("셋팅 초기화")] public virtual void InitializeComponents() { _skeletonAnimation = transform.GetComponentInChildren(); _animationState = _skeletonAnimation.AnimationState; SetSkin(_initialSkinName); } #endregion // Methods #region Methods /// 스파인 애니메이션 이름 /// 반복 여부 /// 애니메이션 속도 양수값 /// true인 경우 자동으로 speed에 음수값을 넣음 /// public TrackEntry PlayAnimation(string animationName, bool isLoopActive, float speed = 1f, bool isReverse = false) { if (!_skeletonAnimation || _animationState == null) return null; if (string.IsNullOrEmpty(animationName)) { Debug.LogError($"{animationName}의 애니메이션은 존재하지 않습니다."); return null; } _animationState.TimeScale = isReverse ? -Mathf.Abs(speed) : Mathf.Abs(speed); var trackEntry = _animationState.SetAnimation(0, animationName, isLoopActive); if (isReverse) { trackEntry.TrackTime = trackEntry.AnimationEnd; } return trackEntry; } public void SetSkin(string skinName) { if (_skeletonAnimation == null && _animationState == null) return; if (string.IsNullOrEmpty(skinName)) { Debug.LogError($"{skinName}의 스킨 이름은 존재하지 않습니다."); return; } _skeletonAnimation.Skeleton.SetSkin(skinName); _skeletonAnimation.Skeleton.SetSlotsToSetupPose(); _animationState.Apply(_skeletonAnimation.Skeleton); } public async Awaitable WaitForAnimationCompletion(TrackEntry trackEntry, bool isReverse = false) { if (isReverse) { await AwaitUntil(() => trackEntry.TrackTime <= 0); } else { await AwaitUntil(() => trackEntry.IsComplete); } } public async Awaitable AwaitUntil(Func condition) { while (!condition()) { await Awaitable.NextFrameAsync(); } } #endregion } }