Files
AIGame/AIClient/Assets/AOT/Scripts/Review/CharacterReviewAnimCycle.cs
T

140 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using System.Linq;
/// <summary>
/// 角色验收场景:对带 Animator 且含 int 参数 Motion 的单位轮播 Idle/Walk/Attack。
/// Edit Mode(Scene 视图)与 Play Mode 均可预览。
/// </summary>
[DisallowMultipleComponent]
[ExecuteAlways]
public sealed class CharacterReviewAnimCycle : MonoBehaviour
{
[SerializeField] float secondsPerMotion = 2.8f;
[SerializeField] string motionParam = "Motion";
[SerializeField] string[] motionNames = { "Idle", "Walk", "Attack" };
[SerializeField] int fixedMotion = -1;
Animator _animator;
TextMesh _label;
string _baseLabel;
int _motionIndex;
float _elapsed;
double _lastEditorTime = -1;
void OnEnable()
{
CacheRefs();
_elapsed = 0f;
_motionIndex = 0;
ApplyMotion(fixedMotion >= 0 ? fixedMotion : 0);
#if UNITY_EDITOR
if (!Application.isPlaying)
{
_lastEditorTime = UnityEditor.EditorApplication.timeSinceStartup;
UnityEditor.EditorApplication.update -= EditorTick;
UnityEditor.EditorApplication.update += EditorTick;
}
#endif
}
void OnDisable()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.update -= EditorTick;
#endif
}
void Update()
{
if (!Application.isPlaying) return;
Tick(Time.deltaTime);
UpdateStateLabel();
}
#if UNITY_EDITOR
void EditorTick()
{
if (this == null || Application.isPlaying || !isActiveAndEnabled) return;
double now = UnityEditor.EditorApplication.timeSinceStartup;
float dt = _lastEditorTime < 0 ? 0.016f : (float)(now - _lastEditorTime);
_lastEditorTime = now;
if (dt <= 0f) return;
if (dt > 0.1f) dt = 0.033f;
Tick(dt);
if (_animator != null && _animator.isActiveAndEnabled)
_animator.Update(dt);
UpdateStateLabel();
UnityEditor.SceneView.RepaintAll();
}
#endif
void CacheRefs()
{
if (_animator == null)
_animator = GetComponentInChildren<Animator>(true);
if (_label == null)
{
var labelTf = transform.Find("NameLabel");
if (labelTf != null) _label = labelTf.GetComponent<TextMesh>();
}
if (_label != null && string.IsNullOrEmpty(_baseLabel))
{
var t = _label.text ?? "";
var cut = t.IndexOf(" [", System.StringComparison.Ordinal);
_baseLabel = cut >= 0 ? t.Substring(0, cut) : t;
}
}
void Tick(float dt)
{
CacheRefs();
if (_animator == null || _animator.runtimeAnimatorController == null) return;
if (!HasMotionParam()) return;
_elapsed += dt;
if (_elapsed < Mathf.Max(0.5f, secondsPerMotion)) return;
_elapsed = 0f;
int count = motionNames != null && motionNames.Length > 0 ? motionNames.Length : 3;
_motionIndex = fixedMotion >= 0 ? fixedMotion : (_motionIndex + 1) % count;
ApplyMotion(_motionIndex);
}
bool HasMotionParam()
{
if (_animator == null) return false;
foreach (var p in _animator.parameters)
if (p.name == motionParam && p.type == AnimatorControllerParameterType.Int)
return true;
return false;
}
void ApplyMotion(int index)
{
if (_animator == null) return;
string selected = motionNames != null && index >= 0 && index < motionNames.Length
? motionNames[index] : index.ToString();
bool attackTrigger = _animator.parameters.Any(p=>p.name=="Attack" && p.type==AnimatorControllerParameterType.Trigger);
int value = selected == "Walk" ? 1 : selected == "Attack" && !attackTrigger ? 2 : 0;
if (HasMotionParam())
_animator.SetInteger(motionParam, value);
if(selected=="Attack" && attackTrigger) _animator.SetTrigger("Attack");
if (_label != null)
{
string name = motionNames != null && index >= 0 && index < motionNames.Length
? motionNames[index]
: index.ToString();
_label.text = string.IsNullOrEmpty(_baseLabel)
? name
: _baseLabel + " [" + name + "]";
}
}
void UpdateStateLabel()
{
if(_animator==null || _label==null || _animator.runtimeAnimatorController==null) return;
var state=_animator.GetCurrentAnimatorStateInfo(0);
string name=state.IsName("Attack") ? "Attack" : state.IsName("Walk") ? "Walk" : "Idle";
_label.text=_baseLabel+" ["+name+"]";
}
}