12.10 进度 基本完成
This commit is contained in:
3
Assets/OtherPlugins/AnimatorPlus/AnimatorPlus.asmdef
Normal file
3
Assets/OtherPlugins/AnimatorPlus/AnimatorPlus.asmdef
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "AnimatorPlus"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4acc6fc9b40b3234ab7a3d47290f0be8
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -63,24 +63,35 @@ namespace AnimatorPlus
|
||||
private AnimationLayerMixerPlayable finalLayerMixerPlayable;
|
||||
private bool resetRootMotionDelta;
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if(Layers.Count==0)
|
||||
Layers.Add(new LayerInfo()) ;
|
||||
Layers[0].mask = null;
|
||||
Layers[0].isAdditive = false;
|
||||
Layers[0].maxWeight = 1;
|
||||
|
||||
InitializeGraph();
|
||||
if (!playableGraph.IsValid())
|
||||
{
|
||||
InitializeGraph();
|
||||
}
|
||||
}
|
||||
private void OnDestroy()
|
||||
{
|
||||
playableGraph.Destroy();
|
||||
}
|
||||
|
||||
private void InitializeGraph()
|
||||
public void InitializeGraph()
|
||||
{
|
||||
// 防止重复初始化
|
||||
if (playableGraph.IsValid()) return;
|
||||
|
||||
// 确保 Layer 0 存在且配置正确(原 Start 中的逻辑移到这里)
|
||||
if (Layers.Count == 0)
|
||||
Layers.Add(new LayerInfo());
|
||||
|
||||
// 确保 Base Layer 的基本数据被初始化
|
||||
if (Layers[0].currentAnimClipPlayInfo == null)
|
||||
Layers[0].currentAnimClipPlayInfo = new AnimClipPlayInfo();
|
||||
|
||||
Layers[0].mask = null;
|
||||
Layers[0].isAdditive = false;
|
||||
Layers[0].maxWeight = 1;
|
||||
|
||||
DeltaPosition = Vector3.zero;
|
||||
DeltaRotation = Quaternion.identity;
|
||||
|
||||
@@ -176,6 +187,10 @@ namespace AnimatorPlus
|
||||
#endregion
|
||||
|
||||
#region 处理动画
|
||||
|
||||
Debug.Log($"Current Layer Index: {currentLayer.index} , Play Clip: {clip.name}");
|
||||
Debug.Log($"PlayInfo before play: CurrentClipIndex:{currentLayer.currentAnimClipPlayInfo.index} ");
|
||||
|
||||
//暂停住目标layer的当前动画
|
||||
if(currentLayer.currentAnimClipPlayInfo.index!=0)
|
||||
{
|
||||
|
||||
198
Assets/OtherPlugins/AnimatorPlus/Core/AnimatorPlus2D.cs
Normal file
198
Assets/OtherPlugins/AnimatorPlus/Core/AnimatorPlus2D.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Animations;
|
||||
|
||||
namespace AnimatorPlus
|
||||
{
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Animations;
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimatorPlus2D : MonoBehaviour
|
||||
{
|
||||
[Header("Settings")] [Tooltip("默认的待机动画 (必填)")]
|
||||
public AnimationClip defaultIdleClip;
|
||||
|
||||
[Header("Debug Info")] [SerializeField]
|
||||
private string currentClipName;
|
||||
|
||||
[SerializeField] private double currentTime;
|
||||
[SerializeField] private double currentDuration;
|
||||
[SerializeField] private bool isLoopingCurrent;
|
||||
|
||||
private Animator animator;
|
||||
private PlayableGraph graph;
|
||||
private AnimationPlayableOutput output;
|
||||
private AnimationClipPlayable currentPlayable;
|
||||
|
||||
private bool isGraphInit = false;
|
||||
private bool skipNextCompletionCheck = false; // 第一帧保护位
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
animator = GetComponent<Animator>();
|
||||
// 1. 彻底禁用原生 Animator 的逻辑更新,防止它干扰 Playable
|
||||
animator.enabled = true;
|
||||
animator.runtimeAnimatorController = null;
|
||||
// 2. 2D 必备设置
|
||||
// 确保动画始终计算(防止屏幕外卡死)
|
||||
animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||||
// 关闭 RootMotion(防止动画导致坐标乱飘)
|
||||
animator.applyRootMotion = false;
|
||||
|
||||
InitializeGraph();
|
||||
|
||||
// 开局自动播放 Idle
|
||||
if (defaultIdleClip != null)
|
||||
{
|
||||
PlayInternal(defaultIdleClip, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[AnimatorPlus2D] 请在 Inspector 中赋值 Default Idle Clip!");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (graph.IsValid()) graph.Destroy();
|
||||
}
|
||||
|
||||
private void InitializeGraph()
|
||||
{
|
||||
if (isGraphInit) return;
|
||||
|
||||
graph = PlayableGraph.Create($"{gameObject.name}_PureGraph");
|
||||
// 使用 GameTime (受 TimeScale 影响)
|
||||
graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
||||
|
||||
// 创建 Output 绑定到 Animator
|
||||
output = AnimationPlayableOutput.Create(graph, "SpriteOutput", GetComponent<Animator>());
|
||||
|
||||
graph.Play();
|
||||
isGraphInit = true;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!isGraphInit) return;
|
||||
|
||||
// 1. 手动驱动 Graph 更新 (因为 animator.enabled = false)
|
||||
graph.Evaluate(Time.deltaTime);
|
||||
|
||||
// 2. 监控非循环动画的结束
|
||||
if (currentPlayable.IsValid() && !isLoopingCurrent)
|
||||
{
|
||||
// 更新 Debug 信息
|
||||
currentTime = currentPlayable.GetTime();
|
||||
|
||||
// 如果处于“跳过检查”状态(刚播放的那一帧),不要检查结束
|
||||
if (skipNextCompletionCheck)
|
||||
{
|
||||
skipNextCompletionCheck = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否播放完毕
|
||||
if (currentTime >= currentDuration)
|
||||
{
|
||||
Debug.Log($"[AnimatorPlus2D] 动画 {currentClipName} 播放完毕,切回 Idle");
|
||||
ReturnToIdle();
|
||||
}
|
||||
}
|
||||
|
||||
/*if (!animator.enabled)
|
||||
{
|
||||
Debug.LogWarning("警告:Animator 组件被意外禁用!请检查是否挂载了旧版脚本(如 SpriteAnimationDriver)。");
|
||||
animator.enabled = true; // 尝试强制开启
|
||||
}*/
|
||||
}
|
||||
|
||||
// ================= 公开 API =================
|
||||
|
||||
/// <summary>
|
||||
/// 播放单次动画(如攻击),播完自动回 Idle
|
||||
/// </summary>
|
||||
public void Play(AnimationClip clip, float speed = 1.0f)
|
||||
{
|
||||
if (clip == null) return;
|
||||
// 强制设为非循环,因为这是“动作”
|
||||
PlayInternal(clip, false, speed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制停止当前动作,直接回 Idle
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
ReturnToIdle();
|
||||
}
|
||||
|
||||
public void SetPause(bool isPaused)
|
||||
{
|
||||
if (isGraphInit)
|
||||
{
|
||||
if (isPaused) graph.Stop();
|
||||
else graph.Play();
|
||||
}
|
||||
}
|
||||
|
||||
// ================= 内部逻辑 =================
|
||||
|
||||
private void ReturnToIdle()
|
||||
{
|
||||
if (defaultIdleClip != null)
|
||||
{
|
||||
// 播放 Idle,并标记为循环
|
||||
PlayInternal(defaultIdleClip, true, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayInternal(AnimationClip clip, bool isLoop, float speed = 1.0f)
|
||||
{
|
||||
if (!isGraphInit) InitializeGraph();
|
||||
|
||||
// 1. 清理旧的 Playable
|
||||
if (currentPlayable.IsValid())
|
||||
{
|
||||
currentPlayable.Destroy();
|
||||
}
|
||||
|
||||
// 2. 创建新的 Playable
|
||||
currentPlayable = AnimationClipPlayable.Create(graph, clip);
|
||||
currentPlayable.SetSpeed(speed);
|
||||
currentPlayable.SetDuration(clip.length);
|
||||
|
||||
// 【关键】Playable 默认不循环,我们需要手动配置
|
||||
// 如果是 Idle,我们不依赖 Playable 的 Loop,而是依赖我们不调用 Stop
|
||||
// 但为了保险,让 Playable 自身也 Loop
|
||||
if (isLoop)
|
||||
{
|
||||
currentPlayable.SetDuration(double.MaxValue);
|
||||
}
|
||||
|
||||
// 3. 连接 Output
|
||||
output.SetSourcePlayable(currentPlayable);
|
||||
|
||||
// 4. 重置状态
|
||||
currentPlayable.SetTime(0);
|
||||
currentPlayable.SetDone(false);
|
||||
|
||||
// 5. 更新内部状态标记
|
||||
currentClipName = clip.name;
|
||||
currentDuration = clip.length;
|
||||
isLoopingCurrent = isLoop;
|
||||
|
||||
// 【关键修复】设置“第一帧保护”,防止 Update 在同一帧里立刻判定结束
|
||||
skipNextCompletionCheck = true;
|
||||
|
||||
// 6. 立即刷新一帧画面
|
||||
graph.Evaluate(0);
|
||||
|
||||
Debug.Log($"[AnimatorPlus2D] Play: {clip.name} (Loop: {isLoop})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13546c0bea421894db5da5d01493af9d
|
||||
Reference in New Issue
Block a user