Files
Cielonos/Assets/Scripts/MainGame/Characters/Base/Subcontrollers/Animation/AnimatorClipMap.cs

139 lines
5.1 KiB
C#
Raw Normal View History

2026-01-03 18:19:39 -05:00
using UnityEngine;
using System.Collections.Generic;
2026-06-27 12:52:03 -04:00
using Sirenix.OdinInspector;
2026-01-03 18:19:39 -05:00
#if UNITY_EDITOR
2026-06-27 12:52:03 -04:00
using UnityEditor.Animations;
2026-01-03 18:19:39 -05:00
#endif
2026-06-27 12:52:03 -04:00
2026-01-03 18:19:39 -05:00
namespace Cielonos.MainGame.Characters
{
2026-06-27 12:52:03 -04:00
// ============================================================================
// AnimatorStateMapper (nested in AnimationSubcontrollerBase via partial)
// ============================================================================
public partial class AnimationSubcontrollerBase
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
/// <summary>
/// 将 Animator 状态机中的 State 名称映射到对应 AnimationClip 的查询器。
/// 通过 Bake 按钮在编辑器中预先建立映射表,运行时以 O(1) 速度查询。
/// </summary>
2026-01-03 18:19:39 -05:00
[System.Serializable]
2026-06-27 12:52:03 -04:00
public class AnimatorStateMapper
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
[Title("Bake Settings")]
[SerializeField, LabelText("Target Animator")]
private Animator _targetAnimatorForBake;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
[TableList(ShowIndexLabels = true), Searchable]
[SerializeField]
private List<StateClipPair> _mappings = new List<StateClipPair>();
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
private Dictionary<string, AnimationClip> _clipDict;
private bool _isInitialized = false;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
[System.Serializable]
public struct StateClipPair
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
[ReadOnly] public string stateName;
public AnimationClip clip;
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
public AnimatorStateMapper()
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
_mappings = new List<StateClipPair>();
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
// ── Runtime API ───────────────────────────────────────────────────
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
/// <summary>必须在宿主的 Awake / Initialize 中调用,构建运行时索引。</summary>
public void Initialize()
{
if (_isInitialized) return;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
_clipDict = new Dictionary<string, AnimationClip>(_mappings.Count);
foreach (var pair in _mappings)
{
if (!string.IsNullOrEmpty(pair.stateName) && pair.clip != null)
_clipDict[pair.stateName] = pair.clip;
}
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
_isInitialized = true;
}
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
public AnimationClip GetClip(string stateName)
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
if (!_isInitialized) Initialize();
if (_clipDict.TryGetValue(stateName, out var clip)) return clip;
Debug.LogWarning($"[AnimatorStateMapper] 未找到 State: '{stateName}' 对应的 Clip。请检查是否已 Bake 或 State 名字是否正确。");
return null;
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
public float GetClipLength(string stateName)
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
var clip = GetClip(stateName);
return clip != null ? clip.length : 0f;
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
// ── Editor Baking ─────────────────────────────────────────────────
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
#if UNITY_EDITOR
public void Bake(Animator animator)
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
_targetAnimatorForBake = animator;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
var controller = _targetAnimatorForBake.runtimeAnimatorController as AnimatorController;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
if (controller == null &&
_targetAnimatorForBake.runtimeAnimatorController is AnimatorOverrideController oc)
controller = oc.runtimeAnimatorController as AnimatorController;
2026-01-03 18:19:39 -05:00
2026-06-27 12:52:03 -04:00
if (controller == null)
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
Debug.LogError("Animator 上未找到有效的 AnimatorController 资源!");
return;
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
_mappings.Clear();
int count = 0;
foreach (var layer in controller.layers)
count += RecursiveProcessStateMachine(layer.stateMachine);
Debug.Log($"<color=green>Bake 完成!共提取了 {count} 个 State-Clip 映射。</color>");
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
private int RecursiveProcessStateMachine(AnimatorStateMachine sm)
2026-01-03 18:19:39 -05:00
{
2026-06-27 12:52:03 -04:00
int count = 0;
foreach (var cs in sm.states)
{
if (cs.state.motion is AnimationClip clip)
{
_mappings.Add(new StateClipPair { stateName = cs.state.name, clip = clip });
count++;
}
}
foreach (var childSm in sm.stateMachines)
count += RecursiveProcessStateMachine(childSm.stateMachine);
return count;
2026-01-03 18:19:39 -05:00
}
#endif
2026-06-27 12:52:03 -04:00
}
2026-01-03 18:19:39 -05:00
}
2026-06-27 12:52:03 -04:00
// ── Editor Buttons ─────────────────────────────────────────────────────────
2026-01-03 18:19:39 -05:00
#if UNITY_EDITOR
public partial class AnimationSubcontrollerBase
{
[Button]
private void MapperBake()
{
mapper ??= new AnimatorStateMapper();
mapper.Bake(animator);
}
}
#endif
}