2024-06-21 22:11:53 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections;
|
2024-06-07 17:31:08 +00:00
|
|
|
using Sirenix.OdinInspector;
|
2024-06-06 11:07:07 +00:00
|
|
|
using Spine.Unity;
|
|
|
|
using UnityEngine;
|
|
|
|
using AnimationState = Spine.AnimationState;
|
|
|
|
|
|
|
|
namespace BlueWater.Players
|
|
|
|
{
|
2024-06-07 17:31:08 +00:00
|
|
|
public class SpineController : MonoBehaviour
|
2024-06-06 11:07:07 +00:00
|
|
|
{
|
|
|
|
// Variables
|
|
|
|
#region Variables
|
|
|
|
// Components
|
2024-06-07 17:31:08 +00:00
|
|
|
[SerializeField]
|
|
|
|
private SkeletonAnimation _skeletonAnimation;
|
|
|
|
private AnimationState _animationState;
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
[SerializeField]
|
2024-06-21 22:11:53 +00:00
|
|
|
private string _initialSkinName = "default";
|
2024-06-06 11:07:07 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
// Unity events
|
|
|
|
#region Unity events
|
|
|
|
|
2024-06-07 17:31:08 +00:00
|
|
|
private void Awake()
|
2024-06-06 11:07:07 +00:00
|
|
|
{
|
2024-06-07 17:31:08 +00:00
|
|
|
InitializeComponents();
|
2024-06-06 11:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
// Initialize methods
|
|
|
|
#region Initialize methods
|
|
|
|
|
2024-06-07 17:31:08 +00:00
|
|
|
[Button("셋팅 초기화")]
|
|
|
|
public virtual void InitializeComponents()
|
2024-06-06 11:07:07 +00:00
|
|
|
{
|
2024-06-07 17:31:08 +00:00
|
|
|
_skeletonAnimation = transform.GetComponentInChildren<SkeletonAnimation>();
|
|
|
|
_animationState = _skeletonAnimation.AnimationState;
|
|
|
|
SetSkin(_initialSkinName);
|
2024-06-06 11:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
// Methods
|
|
|
|
#region Methods
|
|
|
|
|
|
|
|
public void PlayAnimation(string animationName, bool isLoopActive, float speed = 1f)
|
|
|
|
{
|
2024-06-07 17:31:08 +00:00
|
|
|
if (!_skeletonAnimation && _animationState == null) return;
|
2024-06-06 11:07:07 +00:00
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(animationName))
|
|
|
|
{
|
|
|
|
Debug.LogError($"{animationName}의 애니메이션은 존재하지 않습니다.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-07 17:31:08 +00:00
|
|
|
_animationState.TimeScale = speed;
|
|
|
|
_animationState.SetAnimation(0, animationName, isLoopActive);
|
2024-06-06 11:07:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SetSkin(string skinName)
|
|
|
|
{
|
2024-06-07 17:31:08 +00:00
|
|
|
if (_skeletonAnimation == null && _animationState == null) return;
|
2024-06-06 11:07:07 +00:00
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(skinName))
|
|
|
|
{
|
|
|
|
Debug.LogError($"{skinName}의 스킨 이름은 존재하지 않습니다.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-07 17:31:08 +00:00
|
|
|
_skeletonAnimation.Skeleton.SetSkin(skinName);
|
|
|
|
_skeletonAnimation.Skeleton.SetSlotsToSetupPose();
|
|
|
|
_animationState.Apply(_skeletonAnimation.Skeleton);
|
2024-06-06 11:07:07 +00:00
|
|
|
}
|
|
|
|
|
2024-06-21 22:11:53 +00:00
|
|
|
public bool IsComparingCurrentAnimation(string animationName, int trackIndex = 0)
|
|
|
|
{
|
|
|
|
if (!_skeletonAnimation || _animationState == null) return false;
|
|
|
|
|
|
|
|
var currentAnimation = _animationState.GetCurrent(trackIndex)?.Animation;
|
|
|
|
return currentAnimation != null && currentAnimation.Name == animationName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public IEnumerator WaitForAnimationToRun(string animationName, Action<bool> onSuccess, float timeout = 2f)
|
|
|
|
{
|
|
|
|
var elapsedTime = 0f;
|
|
|
|
while (!IsComparingCurrentAnimation(animationName))
|
|
|
|
{
|
|
|
|
elapsedTime += Time.deltaTime;
|
|
|
|
yield return null;
|
|
|
|
if (elapsedTime > timeout)
|
|
|
|
{
|
|
|
|
Debug.Log("Timeout waiting for animation state: " + animationName);
|
|
|
|
onSuccess?.Invoke(false);
|
|
|
|
yield break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onSuccess?.Invoke(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SetCurrentAnimationSpeed(float targetDuration, int trackIndex = 0)
|
|
|
|
{
|
|
|
|
if (!_skeletonAnimation || _animationState == null) return;
|
|
|
|
|
|
|
|
var currentAnimation = _animationState.GetCurrent(trackIndex)?.Animation;
|
|
|
|
if (currentAnimation != null)
|
|
|
|
{
|
|
|
|
var animationLength = currentAnimation.Duration;
|
|
|
|
_animationState.TimeScale = animationLength / targetDuration;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public float GetCurrentAnimationNormalizedTime(int trackIndex = 0)
|
|
|
|
{
|
|
|
|
if (!_skeletonAnimation || _animationState == null) return 0f;
|
|
|
|
|
|
|
|
var currentTrackEntry = _animationState.GetCurrent(trackIndex);
|
|
|
|
if (currentTrackEntry != null)
|
|
|
|
{
|
|
|
|
return currentTrackEntry.TrackTime / currentTrackEntry.Animation.Duration;
|
|
|
|
}
|
|
|
|
return 0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float GetCurrentAnimationLength(int trackIndex = 0)
|
|
|
|
{
|
|
|
|
if (!_skeletonAnimation || _animationState == null) return 0f;
|
|
|
|
|
|
|
|
var currentAnimation = _animationState.GetCurrent(trackIndex)?.Animation;
|
|
|
|
return currentAnimation != null ? currentAnimation.Duration : 0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ResetAnimationSpeed()
|
|
|
|
{
|
|
|
|
if (!_skeletonAnimation || _animationState == null) return;
|
|
|
|
|
|
|
|
_animationState.TimeScale = 1f;
|
|
|
|
}
|
|
|
|
|
2024-06-06 11:07:07 +00:00
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|