12.10 进度 基本完成

This commit is contained in:
SoulliesOfficial
2025-12-10 18:22:26 -05:00
parent 8d6267e1a2
commit f7cab3e784
224 changed files with 11116 additions and 6240 deletions

View File

@@ -0,0 +1,3 @@
{
"name": "AnimatorPlus"
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4acc6fc9b40b3234ab7a3d47290f0be8
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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)
{

View 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})");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 13546c0bea421894db5da5d01493af9d