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 stateHashes = new Dictionary(); private float lastLoggedProgress = -1f; private float lastWarningTime = 0f; private const float warningInterval = 1f; public event Action OnAnimationFinished; void Awake() { animator = GetComponent(); 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; } }