Files
Continentis/Assets/Scripts/MainGame/Character/CharacterView/FrameAnimator.cs
SoulliesOfficial ac98ec3aef 更新
2026-04-17 12:01:50 -04:00

109 lines
3.9 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 System;
using System.Collections;
using System.Collections.Generic;
using AnimatorPlus;
using SLSUtilities.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;
}
}
}
}