AnimalSimulation/Assets/Scripts/ModelController.cs

274 lines
6.8 KiB
C#

using UnityEngine;
using System.Collections.Generic;
using DG.Tweening;
using System;
public class ModelController : MonoBehaviour
{
private Animator animator;
private string currentAnim = "";
private bool isPlaying = false;
private Vector3 originalPosition;
private Vector3 originalScale;
[SerializeField] private string defaultAnimName = "Take 001";
[SerializeField] private bool hasAnimation = true;
private Dictionary<string, int> stateHashes = new Dictionary<string, int>();
private float lastLoggedProgress = -1f;
private float lastWarningTime = 0f;
private const float warningInterval = 1f;
public event Action OnAnimationFinished;
void Awake()
{
animator = GetComponent<Animator>();
originalPosition = transform.localPosition;
originalScale = transform.localScale;
if (hasAnimation)
{
if (animator == null)
{
hasAnimation = false;
}
else
{
CacheAnimationStates();
}
}
else
{
if (animator != null)
{
animator.enabled = false;
}
}
}
private void CacheAnimationStates()
{
if (!hasAnimation) return;
stateHashes.Clear();
if (!string.IsNullOrEmpty(defaultAnimName))
{
stateHashes[defaultAnimName] = Animator.StringToHash(defaultAnimName);
}
if (animator.runtimeAnimatorController != null)
{
foreach (var clip in animator.runtimeAnimatorController.animationClips)
{
if (!stateHashes.ContainsKey(clip.name))
{
stateHashes[clip.name] = Animator.StringToHash(clip.name);
}
}
}
else
{
hasAnimation = false;
animator.enabled = false;
}
}
void Update()
{
if (!hasAnimation || !isPlaying || animator == null || string.IsNullOrEmpty(currentAnim)) return;
if (!animator.enabled)
{
animator.enabled = true;
}
transform.localScale = originalScale;
transform.localPosition = originalPosition;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName(currentAnim) && stateInfo.normalizedTime >= 1f && !animator.IsInTransition(0))
{
isPlaying = false;
animator.enabled = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
OnAnimationFinished?.Invoke();
}
}
public void PlayAnimation()
{
if (!hasAnimation)
{
return;
}
if (animator == null || string.IsNullOrEmpty(defaultAnimName) || !gameObject.activeSelf)
{
return;
}
if (!AnimatorHasState(defaultAnimName))
{
return;
}
currentAnim = defaultAnimName;
animator.enabled = true;
animator.Play(stateHashes[currentAnim], 0, 0f);
animator.Update(0f);
isPlaying = true;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
public void SetAnimationProgress(float normalizedTime)
{
if (!hasAnimation)
{
return;
}
if (animator == null || string.IsNullOrEmpty(defaultAnimName) || !gameObject.activeSelf)
{
return;
}
if (string.IsNullOrEmpty(currentAnim))
{
currentAnim = defaultAnimName;
}
if (!AnimatorHasState(currentAnim))
{
return;
}
isPlaying = false;
animator.enabled = true;
float clampedTime = Mathf.Clamp01(normalizedTime);
animator.Play(stateHashes[currentAnim], 0, clampedTime);
animator.Update(0f);
animator.enabled = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
public void ResetAnimation()
{
if (!hasAnimation)
{
return;
}
if (animator == null || !gameObject.activeSelf)
{
return;
}
string animToReset = !string.IsNullOrEmpty(defaultAnimName) ? defaultAnimName : "";
if (string.IsNullOrEmpty(animToReset))
{
return;
}
if (!AnimatorHasState(animToReset))
{
return;
}
currentAnim = animToReset;
animator.enabled = true;
animator.Play(stateHashes[currentAnim], 0, 0f);
animator.Update(0f);
animator.enabled = false;
isPlaying = false;
transform.localScale = originalScale;
transform.localPosition = originalPosition;
}
public void MoveModel(float xOffset)
{
if (!gameObject.activeSelf)
{
return;
}
Vector3 targetPosition = originalPosition + new Vector3(xOffset, 0f, 0f);
transform.DOLocalMoveX(targetPosition.x, 1f).SetEase(Ease.InOutSine).OnComplete(() =>
{
transform.localScale = originalScale;
});
}
public void ResetModelPosition()
{
if (!gameObject.activeSelf)
{
return;
}
transform.DOLocalMoveX(originalPosition.x, 1f).SetEase(Ease.InOutSine).OnComplete(() =>
{
transform.localScale = originalScale;
});
}
public float GetAnimationProgress()
{
if (!hasAnimation)
{
return 0f;
}
if (animator == null || !animator.enabled || string.IsNullOrEmpty(currentAnim) || !gameObject.activeSelf)
{
return 0f;
}
if (!AnimatorHasState(currentAnim))
{
return 0f;
}
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (stateInfo.IsName(currentAnim))
{
float progress = Mathf.Clamp01(stateInfo.normalizedTime % 1f);
return progress;
}
return 0f;
}
private bool AnimatorHasState(string stateName)
{
if (!hasAnimation)
{
return false;
}
if (string.IsNullOrEmpty(stateName) || !stateHashes.TryGetValue(stateName, out int hash))
{
return false;
}
for (int i = 0; i < animator.layerCount; i++)
{
if (animator.HasState(i, hash))
{
return true;
}
}
return false;
}
public bool IsPlayingAnimation()
{
if (!hasAnimation)
{
return false;
}
return isPlaying;
}
public bool GetHasAnimation()
{
return hasAnimation;
}
}