109 lines
3.9 KiB
C#
109 lines
3.9 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using AnimatorPlus;
|
||
using SLSFramework.General;
|
||
using UnityEngine;
|
||
|
||
namespace Continentis.MainGame.Character
|
||
{
|
||
/// <summary>
|
||
/// Tier 2 动画驱动器:帧动画方案,基于 AnimatorPlus2D + AnimationClip。
|
||
/// 通过 CharacterData.animations 映射表驱动 Sprite Sheet 帧动画。
|
||
/// 适合有完整帧动画序列的像素风角色(如 PixelFantasy 系列)。
|
||
/// </summary>
|
||
public class FrameAnimator : MonoBehaviour, ICharacterAnimator
|
||
{
|
||
private AnimatorPlus2D _animatorPlus;
|
||
private SerializableDictionary<string, AnimationClip> _animations;
|
||
private Coroutine _completionCoroutine;
|
||
|
||
// ── ICharacterAnimator ──────────────────────────────────────────────
|
||
|
||
/// <summary>
|
||
/// 初始化:从 CombatCharacterViewBase 获取 AnimatorPlus2D 引用和动画映射表。
|
||
/// </summary>
|
||
public void InitializeAnimator(CombatCharacterViewBase view)
|
||
{
|
||
_animatorPlus = view.animatorPlus2D;
|
||
|
||
// 从 CharacterData 拷贝动画映射
|
||
_animations = new SerializableDictionary<string, AnimationClip>();
|
||
foreach (KeyValuePair<string, AnimationClip> pair in view.character.data.animations)
|
||
{
|
||
_animations.Add(pair.Key, pair.Value);
|
||
}
|
||
|
||
// 设置 Idle 并初始化 Playable Graph
|
||
if (_animations.TryGetValue("Idle", out AnimationClip idle))
|
||
{
|
||
_animatorPlus.defaultIdleClip = idle;
|
||
_animatorPlus.Initialize();
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError($"[FrameAnimator] 角色 '{view.character.data.displayName}' 缺少 Idle 动画,无法初始化。");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放指定动作的 AnimationClip,播完自动回 Idle 并触发回调。
|
||
/// </summary>
|
||
public void PlayAction(string actionName, float speed = 1f, Action onComplete = null)
|
||
{
|
||
StopCompletionCoroutine();
|
||
|
||
if (!_animations.TryGetValue(actionName, out AnimationClip clip))
|
||
{
|
||
Debug.LogWarning($"[FrameAnimator] 找不到动画 '{actionName}',跳过播放。");
|
||
onComplete?.Invoke();
|
||
return;
|
||
}
|
||
|
||
_animatorPlus.Play(clip, speed);
|
||
|
||
// 动画播完后触发回调(AnimatorPlus2D 自动回 Idle,此处仅等待时长)
|
||
if (onComplete != null)
|
||
{
|
||
float duration = clip.length / Mathf.Max(speed, 0.01f);
|
||
_completionCoroutine = StartCoroutine(WaitForCompletion(duration, onComplete));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 立即停止当前动作,切回 Idle。
|
||
/// </summary>
|
||
public void ReturnToIdle()
|
||
{
|
||
StopCompletionCoroutine();
|
||
_animatorPlus.Stop();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暂停或恢复 PlayableGraph。
|
||
/// </summary>
|
||
public void SetPause(bool isPaused)
|
||
{
|
||
_animatorPlus.SetPause(isPaused);
|
||
}
|
||
|
||
// ── 内部逻辑 ────────────────────────────────────────────────────────
|
||
|
||
private IEnumerator WaitForCompletion(float duration, Action onComplete)
|
||
{
|
||
yield return new WaitForSeconds(duration);
|
||
onComplete?.Invoke();
|
||
_completionCoroutine = null;
|
||
}
|
||
|
||
private void StopCompletionCoroutine()
|
||
{
|
||
if (_completionCoroutine != null)
|
||
{
|
||
StopCoroutine(_completionCoroutine);
|
||
_completionCoroutine = null;
|
||
}
|
||
}
|
||
}
|
||
}
|