diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation.meta
new file mode 100644
index 0000000..bc5ba08
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 22c4a6746deb208479f4b7a040eed7f3
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md
new file mode 100644
index 0000000..4597745
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md
@@ -0,0 +1,5 @@
+# UniFramework.Animation
+
+一个轻量级的高效率的动画系统。
+
+支持新的动画文件格式,不再依赖Animator文件来驱动动画,使用方式非常类似于老的Animation系统。
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md.meta
new file mode 100644
index 0000000..c47688a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 6a7da62cb3785ef45b2dda8fa0b3c8e5
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime.meta
new file mode 100644
index 0000000..1832fb4
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8664294e17a47c14c8d12545da2349a1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs
new file mode 100644
index 0000000..4d8ac73
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs
@@ -0,0 +1,106 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Playables;
+using UnityEngine.Animations;
+
+namespace UniFramework.Animation
+{
+ internal sealed class AnimClip : AnimNode
+ {
+ public readonly string Name;
+ private readonly AnimationClip _clip;
+ public AnimationClipPlayable _clipPlayable;
+
+ ///
+ /// 动画层级
+ ///
+ public int Layer = 0;
+
+ ///
+ /// 动画长度
+ ///
+ public float ClipLength
+ {
+ get
+ {
+ if (_clip == null)
+ return 0f;
+ if (Speed == 0f)
+ return Mathf.Infinity;
+ return _clip.length / Speed;
+ }
+ }
+
+ ///
+ /// 归一化时间轴
+ ///
+ public float NormalizedTime
+ {
+ set
+ {
+ if (_clip == null)
+ return;
+ Time = _clip.length * value;
+ }
+
+ get
+ {
+ if (_clip == null)
+ return 1f;
+ return Time / _clip.length;
+ }
+ }
+
+ ///
+ /// 动画模式
+ ///
+ public WrapMode WrapMode
+ {
+ set
+ {
+ if (_clip != null)
+ _clip.wrapMode = value;
+ }
+ get
+ {
+ if (_clip == null)
+ return WrapMode.Default;
+ return _clip.wrapMode;
+ }
+ }
+
+ ///
+ /// 动画状态
+ ///
+ public AnimState State { private set; get; }
+
+ public AnimClip(PlayableGraph graph, AnimationClip clip, string name, int layer) : base(graph)
+ {
+ _clip = clip;
+ Name = name;
+ Layer = layer;
+
+ _clipPlayable = AnimationClipPlayable.Create(graph, clip);
+ _clipPlayable.SetApplyFootIK(false);
+ _clipPlayable.SetApplyPlayableIK(false);
+ SetSourcePlayable(_clipPlayable);
+
+ if (clip.wrapMode == WrapMode.Once)
+ {
+ _clipPlayable.SetDuration(clip.length);
+ }
+
+ State = new AnimState(this);
+ }
+ public override void PlayNode()
+ {
+ if (_clip.wrapMode == WrapMode.Once || _clip.wrapMode == WrapMode.ClampForever)
+ {
+ Time = 0;
+ }
+
+ base.PlayNode();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs.meta
new file mode 100644
index 0000000..71a052f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimClip.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 606e5729d04cc8742a38f58e595c02f9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs
new file mode 100644
index 0000000..0af25bc
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs
@@ -0,0 +1,196 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Playables;
+using UnityEngine.Animations;
+
+namespace UniFramework.Animation
+{
+ internal sealed class AnimMixer : AnimNode
+ {
+ private const float HIDE_DURATION = 0.25f;
+ private readonly List _animClips = new List(10);
+ private AnimationMixerPlayable _mixer;
+ private bool _isQuiting = false;
+
+ ///
+ /// 动画层级
+ ///
+ public int Layer { private set; get; }
+
+
+ public AnimMixer(PlayableGraph graph, int layer) : base(graph)
+ {
+ Layer = layer;
+
+ _mixer = AnimationMixerPlayable.Create(graph);
+ SetSourcePlayable(_mixer);
+ }
+ public override void Update(float deltaTime)
+ {
+ base.Update(deltaTime);
+
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ var animClip = _animClips[i];
+ if (animClip != null)
+ animClip.Update(deltaTime);
+ }
+
+ bool isAllDone = true;
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ var animClip = _animClips[i];
+ if (animClip != null)
+ {
+ if (animClip.IsDone == false)
+ isAllDone = false;
+ }
+ }
+
+ // 当子节点都已经完成的时候断开连接
+ if (isAllDone && _isQuiting == false)
+ {
+ _isQuiting = true;
+ StartWeightFade(0, HIDE_DURATION);
+ }
+ if (_isQuiting)
+ {
+ if (Mathf.Approximately(Weight, 0f))
+ DisconnectMixer();
+ }
+ }
+
+ ///
+ /// 播放指定动画
+ ///
+ public void Play(AnimClip newAnimClip, float fadeDuration)
+ {
+ // 重新激活混合器
+ _isQuiting = false;
+ StartWeightFade(1f, 0);
+
+ if (IsContains(newAnimClip) == false)
+ {
+ // 优先插入到一个空位
+ int index = _animClips.FindIndex(s => s == null);
+ if (index == -1)
+ {
+ // Increase input count
+ int inputCount = _mixer.GetInputCount();
+ _mixer.SetInputCount(inputCount + 1);
+
+ newAnimClip.Connect(_mixer, inputCount);
+ _animClips.Add(newAnimClip);
+ }
+ else
+ {
+ newAnimClip.Connect(_mixer, index);
+ _animClips[index] = newAnimClip;
+ }
+ }
+
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ var animClip = _animClips[i];
+ if (animClip == null)
+ continue;
+
+ if (animClip == newAnimClip)
+ {
+ animClip.StartWeightFade(1f, fadeDuration);
+ animClip.PlayNode();
+ }
+ else
+ {
+ animClip.StartWeightFade(0f, fadeDuration);
+ animClip.PauseNode();
+ }
+ }
+ }
+
+ ///
+ /// 停止指定动画,恢复为初始状态
+ ///
+ public void Stop(string name)
+ {
+ AnimClip animClip = FindClip(name);
+ if (animClip == null)
+ return;
+
+ animClip.PauseNode();
+ animClip.ResetNode();
+ }
+
+ ///
+ /// 暂停所有动画
+ ///
+ public void PauseAll()
+ {
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ var animClip = _animClips[i];
+ if (animClip == null)
+ continue;
+ animClip.PauseNode();
+ }
+ }
+
+ ///
+ /// 是否包含该动画
+ ///
+ public bool IsContains(AnimClip clip)
+ {
+ foreach (var animClip in _animClips)
+ {
+ if (animClip == clip)
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// 移除一个动画
+ ///
+ public void RemoveClip(string name)
+ {
+ var animClip = FindClip(name);
+ if (animClip == null)
+ return;
+
+ _animClips[animClip.InputPort] = null;
+ animClip.Destroy();
+ }
+
+ ///
+ /// 获取指定的动画
+ ///
+ /// 如果没有返回NULL
+ private AnimClip FindClip(string name)
+ {
+ foreach (var animClip in _animClips)
+ {
+ if (animClip != null && animClip.Name == name)
+ return animClip;
+ }
+
+ UniLogger.Warning($"${nameof(AnimClip)} doesn't exist : {name}");
+ return null;
+ }
+
+ private void DisconnectMixer()
+ {
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ var animClip = _animClips[i];
+ if (animClip == null)
+ continue;
+
+ animClip.Disconnect();
+ _animClips[i] = null;
+ }
+
+ Disconnect();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs.meta
new file mode 100644
index 0000000..7842188
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimMixer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b33204afd07c00c4f8b425276778b8bf
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs
new file mode 100644
index 0000000..7dc96c3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs
@@ -0,0 +1,221 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Playables;
+using UnityEngine.Animations;
+
+namespace UniFramework.Animation
+{
+ internal abstract class AnimNode
+ {
+ private readonly PlayableGraph _graph;
+ private Playable _source;
+ private Playable _parent;
+
+ private float _fadeSpeed = 0f;
+ private float _fadeWeight = 0f;
+ private bool _isFading = false;
+
+
+ ///
+ /// 是否已经连接
+ ///
+ public bool IsConnect { get; private set; } = false;
+
+ ///
+ /// 输入端口
+ ///
+ public int InputPort { private set; get; }
+
+ ///
+ /// 是否已经完成
+ /// If the duration of the playable is set, when the time of the playable reaches its duration during playback this flag will be set to true.
+ ///
+ public bool IsDone
+ {
+ get
+ {
+ return _source.IsDone();
+ }
+ }
+
+ ///
+ /// 是否有效
+ /// if the Playable is properly constructed by the PlayableGraph and has not been destroyed, false otherwise.
+ ///
+ public bool IsValid
+ {
+ get
+ {
+ return _source.IsValid();
+ }
+ }
+
+ ///
+ /// 是否正在播放中
+ ///
+ public bool IsPlaying
+ {
+ get
+ {
+ return _source.GetPlayState() == PlayState.Playing;
+ }
+ }
+
+ ///
+ /// 时间轴
+ ///
+ public float Time
+ {
+ set
+ {
+ _source.SetTime(value);
+ }
+ get
+ {
+ return (float)_source.GetTime();
+ }
+ }
+
+ ///
+ /// 播放速度
+ ///
+ public float Speed
+ {
+ set
+ {
+ _source.SetSpeed(value);
+ }
+ get
+ {
+ return (float)_source.GetSpeed();
+ }
+ }
+
+ ///
+ /// 权重值
+ ///
+ public float Weight
+ {
+ set
+ {
+ _parent.SetInputWeight(InputPort, value);
+ }
+ get
+ {
+ return _parent.GetInputWeight(InputPort);
+ }
+ }
+
+
+ public AnimNode(PlayableGraph graph)
+ {
+ _graph = graph;
+ }
+ public virtual void Update(float deltaTime)
+ {
+ if (_isFading)
+ {
+ Weight = Mathf.MoveTowards(Weight, _fadeWeight, _fadeSpeed * deltaTime);
+ if (Mathf.Approximately(Weight, _fadeWeight))
+ {
+ _isFading = false;
+ }
+ }
+ }
+ public virtual void Destroy()
+ {
+ if (IsValid)
+ {
+ _graph.DestroySubgraph(_source);
+ }
+ }
+ public virtual void PlayNode()
+ {
+ // NOTE : When playing, the local time of this Playable will be updated during the evaluation of the PlayableGraph.
+ _source.Play();
+
+ // NOTE : Changes a flag indicating that a playable has completed its operation.
+ // Playable that reach the end of their duration are automatically marked as done.
+ _source.SetDone(false);
+ }
+ public virtual void PauseNode()
+ {
+ // NOTE : When paused, the local time of this Playable will not be updated during the evaluation of the PlayableGraph.
+ _source.Pause();
+
+ // NOTE : Changes a flag indicating that a playable has completed its operation.
+ // Playable that reach the end of their duration are automatically marked as done.
+ _source.SetDone(true);
+ }
+ public virtual void ResetNode()
+ {
+ _fadeSpeed = 0;
+ _fadeWeight = 0;
+ _isFading = false;
+
+ Time = 0;
+ Speed = 1;
+ Weight = 0;
+ }
+
+ ///
+ /// 连接到父节点
+ ///
+ /// 父节点对象
+ /// 父节点上的输入端口
+ public void Connect(Playable parent, int parentInputPort)
+ {
+ if (IsConnect)
+ throw new System.Exception("AnimNode is connected.");
+
+ _parent = parent;
+ InputPort = parentInputPort;
+
+ // 重置节点
+ ResetNode();
+
+ // 连接
+ _graph.Connect(_source, 0, parent, parentInputPort);
+ IsConnect = true;
+ }
+
+ ///
+ /// 同父节点断开连接
+ ///
+ public void Disconnect()
+ {
+ if (IsConnect == false)
+ throw new System.Exception("AnimNode is disconnected.");
+
+ // 断开
+ _graph.Disconnect(_parent, InputPort);
+ IsConnect = false;
+ }
+
+ ///
+ /// 开始权重值过渡
+ ///
+ /// 目标权重值
+ /// 过渡时间
+ public void StartWeightFade(float destWeight, float fadeDuration)
+ {
+ if (fadeDuration <= 0)
+ {
+ Weight = destWeight;
+ _isFading = false;
+ return;
+ }
+
+ //注意:保持统一的渐变速度
+ _fadeSpeed = 1f / fadeDuration;
+ _fadeWeight = destWeight;
+ _isFading = true;
+ }
+
+ protected void SetSourcePlayable(Playable playable)
+ {
+ _source = playable;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs.meta
new file mode 100644
index 0000000..1f91ab9
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b6928afd60ab2ed489e492e00d9ddaba
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs
new file mode 100644
index 0000000..274f65a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs
@@ -0,0 +1,238 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Playables;
+using UnityEngine.Animations;
+
+namespace UniFramework.Animation
+{
+ internal class AnimPlayable
+ {
+ private readonly List _animClips = new List(10);
+ private readonly List _animMixers = new List(10);
+
+ private PlayableGraph _graph;
+ private AnimationPlayableOutput _output;
+ private AnimationLayerMixerPlayable _mixerRoot;
+
+ public void Create(Animator animator)
+ {
+ string name = animator.gameObject.name;
+ _graph = PlayableGraph.Create(name);
+ _graph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
+
+ _mixerRoot = AnimationLayerMixerPlayable.Create(_graph);
+ _output = AnimationPlayableOutput.Create(_graph, name, animator);
+ _output.SetSourcePlayable(_mixerRoot);
+ }
+ public void Update(float deltaTime)
+ {
+ _graph.Evaluate(deltaTime);
+
+ // 更新所有层级
+ for (int i = 0; i < _animMixers.Count; i++)
+ {
+ var mixer = _animMixers[i];
+ if(mixer.IsConnect)
+ mixer.Update(deltaTime);
+ }
+ }
+ public void Destroy()
+ {
+ _graph.Destroy();
+ }
+
+ ///
+ /// Play the graph
+ ///
+ public void PlayGraph()
+ {
+ _graph.Play();
+ }
+
+ ///
+ /// Stop the graph
+ ///
+ public void StopGraph()
+ {
+ _graph.Stop();
+ }
+
+ ///
+ /// 获取动画的状态
+ ///
+ /// 动画名称
+ /// 如果动画不存在返回空
+ public AnimState GetAnimState(string name)
+ {
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ if (_animClips[i].Name == name)
+ return _animClips[i].State;
+ }
+ return null;
+ }
+
+ ///
+ /// 检测动画是否正在播放
+ ///
+ /// 动画名称
+ public bool IsPlaying(string name)
+ {
+ AnimClip animClip = GetAnimClip(name);
+ if (animClip == null)
+ return false;
+
+ return animClip.IsConnect && animClip.IsPlaying;
+ }
+
+ ///
+ /// 播放一个动画
+ ///
+ /// 动画名称
+ /// 融合时间
+ public void Play(string name, float fadeLength)
+ {
+ var animClip = GetAnimClip(name);
+ if (animClip == null)
+ {
+ UniLogger.Warning($"Not found animation {name}");
+ return;
+ }
+
+ int layer = animClip.Layer;
+ var animMixer = GetAnimMixer(layer);
+ if (animMixer == null)
+ animMixer = CreateAnimMixer(layer);
+
+ if(animMixer.IsConnect == false)
+ animMixer.Connect(_mixerRoot, animMixer.Layer);
+
+ animMixer.Play(animClip, fadeLength);
+ }
+
+ ///
+ /// 停止一个动画
+ ///
+ /// 动画名称
+ public void Stop(string name)
+ {
+ var animClip = GetAnimClip(name);
+ if (animClip == null)
+ {
+ UniLogger.Warning($"Not found animation {name}");
+ return;
+ }
+
+ if (animClip.IsConnect == false)
+ return;
+
+ var animMixer = GetAnimMixer(animClip.Layer);
+ if (animMixer == null)
+ throw new System.Exception("Should never get here.");
+
+ animMixer.Stop(animClip.Name);
+ }
+
+ ///
+ /// 添加一个动画片段
+ ///
+ /// 动画名称
+ /// 动画片段
+ /// 动画层级
+ public bool AddAnimation(string name, AnimationClip clip, int layer = 0)
+ {
+ if (string.IsNullOrEmpty(name))
+ throw new System.ArgumentException("Name is null or empty.");
+ if (clip == null)
+ throw new System.ArgumentNullException();
+ if (layer < 0)
+ throw new System.Exception("Layer must be greater than zero.");
+
+ if (IsContains(name))
+ {
+ UniLogger.Warning($"Animation already exists : {name}");
+ return false;
+ }
+
+ AnimClip animClip = new AnimClip(_graph, clip, name, layer);
+ _animClips.Add(animClip);
+ return true;
+ }
+
+ ///
+ /// 移除一个动画片段
+ ///
+ /// 动画名称
+ public bool RemoveAnimation(string name)
+ {
+ if (IsContains(name) == false)
+ {
+ UniLogger.Warning($"Not found Animation : {name}");
+ return false;
+ }
+
+ AnimClip animClip = GetAnimClip(name);
+ AnimMixer animMixer = GetAnimMixer(animClip.Layer);
+ if(animMixer != null)
+ animMixer.RemoveClip(animClip.Name);
+
+ animClip.Destroy();
+ _animClips.Remove(animClip);
+ return true;
+ }
+
+ ///
+ /// 是否包含一个动画状态
+ ///
+ /// 动画名称
+ public bool IsContains(string name)
+ {
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ if (_animClips[i].Name == name)
+ return true;
+ }
+ return false;
+ }
+
+ private AnimClip GetAnimClip(string name)
+ {
+ for (int i = 0; i < _animClips.Count; i++)
+ {
+ if (_animClips[i].Name == name)
+ return _animClips[i];
+ }
+ return null;
+ }
+ private AnimMixer GetAnimMixer(int layer)
+ {
+ for (int i = 0; i < _animMixers.Count; i++)
+ {
+ if (_animMixers[i].Layer == layer)
+ return _animMixers[i];
+ }
+ return null;
+ }
+ private AnimMixer CreateAnimMixer(int layer)
+ {
+ // Increase input count
+ int inputCount = _mixerRoot.GetInputCount();
+ if(layer == 0 && inputCount == 0)
+ {
+ _mixerRoot.SetInputCount(1);
+ }
+ else
+ {
+ if (layer > inputCount - 1)
+ {
+ _mixerRoot.SetInputCount(layer + 1);
+ }
+ }
+
+ var animMixer = new AnimMixer(_graph, layer);
+ _animMixers.Add(animMixer);
+ return animMixer;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs.meta
new file mode 100644
index 0000000..36714b0
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimPlayable.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 772b8a9edd8466646bab12d6f5ba1084
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs
new file mode 100644
index 0000000..c0ae266
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs
@@ -0,0 +1,126 @@
+using System.Collections;
+using UnityEngine;
+using UnityEngine.Playables;
+using UnityEngine.Animations;
+
+namespace UniFramework.Animation
+{
+ public class AnimState
+ {
+ private readonly AnimClip _animClip;
+
+ private AnimState()
+ {
+ }
+ internal AnimState(AnimClip animClip)
+ {
+ _animClip = animClip;
+ }
+
+
+ ///
+ /// The name of animation.
+ ///
+ public string Name
+ {
+ get
+ {
+ return _animClip.Name;
+ }
+ }
+
+ ///
+ /// The length of the animation clip in seconds.
+ ///
+ public float Length
+ {
+ get
+ {
+ return _animClip.ClipLength;
+ }
+ }
+
+ ///
+ /// The layer of animation.
+ ///
+ public int Layer
+ {
+ get
+ {
+ return _animClip.Layer;
+ }
+ }
+
+ ///
+ /// Wrapping mode of the animation.
+ ///
+ public WrapMode WrapMode
+ {
+ get
+ {
+ return _animClip.WrapMode;
+ }
+ }
+
+
+ ///
+ /// The weight of animation.
+ ///
+ public float Weight
+ {
+ get
+ {
+ return _animClip.Weight;
+ }
+ set
+ {
+ _animClip.Weight = value;
+ }
+ }
+
+ ///
+ /// The current time of the animation.
+ ///
+ public float Time
+ {
+ get
+ {
+ return _animClip.Time;
+ }
+ set
+ {
+ _animClip.Time = value;
+ }
+ }
+
+ ///
+ /// The normalized time of the animation.
+ ///
+ public float NormalizedTime
+ {
+ get
+ {
+ return _animClip.NormalizedTime;
+ }
+ set
+ {
+ _animClip.NormalizedTime = value;
+ }
+ }
+
+ ///
+ /// The playback speed of the animation. 1 is normal playback speed.
+ ///
+ public float Speed
+ {
+ get
+ {
+ return _animClip.Speed;
+ }
+ set
+ {
+ _animClip.Speed = value;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs.meta
new file mode 100644
index 0000000..3b2e4c8
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/AnimState.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5660d9e37e5c2a44f818506c9fe76624
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs
new file mode 100644
index 0000000..15471d4
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace UniFramework.Animation
+{
+ [RequireComponent(typeof(Animator))]
+ public class UniAnimation : MonoBehaviour
+ {
+ [Serializable]
+ public class AnimationWrapper
+ {
+ public int Layer;
+ public WrapMode Mode;
+ public AnimationClip Clip;
+ }
+
+ private AnimPlayable _animPlayable;
+ private Animator _animator;
+
+ [SerializeField]
+ private AnimationWrapper[] _animations;
+
+ [SerializeField]
+ private bool _playAutomatically = true;
+
+ [SerializeField]
+ private bool _animatePhysics = false;
+
+ ///
+ /// 自动播放动画
+ ///
+ public bool PlayAutomatically
+ {
+ get
+ {
+ return _playAutomatically;
+ }
+ set
+ {
+ _playAutomatically = value;
+ }
+ }
+
+ ///
+ /// 物理更新模式
+ ///
+ public bool AnimatePhysics
+ {
+ get
+ {
+ return _animatePhysics;
+ }
+ set
+ {
+ _animatePhysics = value;
+ _animator.updateMode = _animatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
+ }
+ }
+
+
+ public void Awake()
+ {
+ _animator = GetComponent();
+ _animator.updateMode = _animatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
+
+ _animPlayable = new AnimPlayable();
+ _animPlayable.Create(_animator);
+
+ // 添加列表动作
+ for (int i = 0; i < _animations.Length; i++)
+ {
+ var wrapper = _animations[i];
+ if (wrapper == null || wrapper.Clip == null)
+ continue;
+
+ wrapper.Clip.wrapMode = wrapper.Mode;
+ _animPlayable.AddAnimation(wrapper.Clip.name, wrapper.Clip, wrapper.Layer);
+ }
+ }
+ public void OnEnable()
+ {
+ _animPlayable.PlayGraph();
+
+ if (PlayAutomatically)
+ {
+ var wrapper = GetDefaultWrapper();
+ if (wrapper != null)
+ {
+ Play(wrapper.Clip.name, 0f);
+ }
+ }
+
+ _animPlayable.Update(float.MaxValue);
+ }
+ public void OnDisable()
+ {
+ _animPlayable.StopGraph();
+ }
+ public void OnDestroy()
+ {
+ _animPlayable.Destroy();
+ }
+ public void Update()
+ {
+ _animPlayable.Update(Time.deltaTime);
+ }
+
+ ///
+ /// 添加一个动画
+ ///
+ /// 动画片段
+ /// 动画层级
+ public bool AddAnimation(AnimationClip clip, int layer = 0)
+ {
+ return _animPlayable.AddAnimation(clip.name, clip, layer);
+ }
+
+ ///
+ /// 移除动画
+ ///
+ /// 动画名称
+ public bool RemoveAnimation(string name)
+ {
+ return _animPlayable.RemoveAnimation(name);
+ }
+
+ ///
+ /// 获取动画状态
+ ///
+ public AnimState GetState(string name)
+ {
+ return _animPlayable.GetAnimState(name);
+ }
+
+ ///
+ /// 动画是否在播放中
+ ///
+ public bool IsPlaying(string name)
+ {
+ return _animPlayable.IsPlaying(name);
+ }
+
+ ///
+ /// 是否包含动画片段
+ ///
+ public bool IsContains(string name)
+ {
+ return _animPlayable.IsContains(name);
+ }
+
+ ///
+ /// 播放动画
+ ///
+ public void Play(string name, float fadeLength = 0.25f)
+ {
+ _animPlayable.Play(name, fadeLength);
+ }
+
+ ///
+ /// 停止动画
+ ///
+ public void Stop(string name)
+ {
+ _animPlayable.Stop(name);
+ }
+
+ private AnimationWrapper GetDefaultWrapper()
+ {
+ for (int i = 0; i < _animations.Length; i++)
+ {
+ var wrapper = _animations[i];
+ if (wrapper == null || wrapper.Clip == null)
+ continue;
+
+ return wrapper;
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs.meta
new file mode 100644
index 0000000..18eabca
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniAnimation.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ef52174816df6104587b15c5b250201a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniWindow.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef
similarity index 67%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniWindow.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef
index bbad81a..9ad70f0 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniWindow.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef
@@ -1,12 +1,10 @@
{
- "name": "UniWindow",
+ "name": "UniFramework.Animation",
"rootNamespace": "",
- "references": [
- "GUID:e34a5702dd353724aa315fb8011f08c3"
- ],
+ "references": [],
"includePlatforms": [],
"excludePlatforms": [],
- "allowUnsafeCode": true,
+ "allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef.meta
new file mode 100644
index 0000000..0d81060
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniFramework.Animation.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ccbd3ee89c7c8614bb89388a769680c1
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs
new file mode 100644
index 0000000..4bd5ee6
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics;
+
+namespace UniFramework.Animation
+{
+ internal static class UniLogger
+ {
+ [Conditional("DEBUG")]
+ public static void Log(string info)
+ {
+ UnityEngine.Debug.Log(info);
+ }
+ public static void Warning(string info)
+ {
+ UnityEngine.Debug.LogWarning(info);
+ }
+ public static void Error(string info)
+ {
+ UnityEngine.Debug.LogError(info);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs.meta
new file mode 100644
index 0000000..7785b38
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniAnimation/Runtime/UniLogger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5c11371eb114ef24daad9fc81ac6e0cd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent.meta
index 74dfc81..bc5909c 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: f2801816f5bf9e74eb7f2e2b340ad4cc
+guid: c1cc49e5bd383f040b0f9d481de62f04
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniEvent.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniFramework.Event.asmdef
similarity index 91%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniEvent.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniFramework.Event.asmdef
index 23607c8..1ece224 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniEvent.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniFramework.Event.asmdef
@@ -1,5 +1,5 @@
{
- "name": "UniEvent",
+ "name": "UniFramework.Event",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniEvent.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniFramework.Event.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniEvent.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniEvent/Runtime/UniFramework.Event.asmdef.meta
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine.meta
index a932595..6725a37 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 16d76e3e6337b0c4cae28696d4be4c7c
+guid: 72dcc846338391f44a4134c21f94723a
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniPooling.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniFramework.Machine.asmdef
similarity index 90%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniPooling.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniFramework.Machine.asmdef
index 1a1d78e..811cf36 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniPooling.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniFramework.Machine.asmdef
@@ -1,5 +1,5 @@
{
- "name": "UniPooling",
+ "name": "UniFramework.Machine",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniMachine.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniFramework.Machine.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniMachine.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniFramework.Machine.asmdef.meta
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork.meta
new file mode 100644
index 0000000..eb88ee2
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 99ad37bbd721c834d8157bb257d4b8bb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md
new file mode 100644
index 0000000..9517f36
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md
@@ -0,0 +1,89 @@
+# UniFramework.Network
+
+一个高效的基于IOCP模型的网络系统。
+
+```c#
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using UnityEngine;
+using UniFramework.Network;
+
+// 登录请求消息
+class LoginRequestMessage
+{
+ public string Name;
+ public string Password;
+}
+
+// 登录反馈消息
+class LoginResponseMessage
+{
+ public string Result;
+}
+
+// TCP客户端
+UniFramework.Network.TcpClient _client = null;
+
+// 创建TCP客户端
+void CreateClient()
+{
+ // 初始化网络系统
+ UniNetwork.Initalize();
+
+ // 创建TCP客户端
+ int packageMaxSize = short.MaxValue;
+ var encoder = new DefaultNetPackageEncoder();
+ var decoder = new DefaultNetPackageDecoder();
+ _client = UniNetwork.CreateTcpClient(packageMaxSize, encoder, decoder);
+
+ // 连接服务器
+ var remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000);
+ _client.ConnectAsync(remote, OnConnectServer);
+}
+
+// 关闭TCP客户端
+void CloseClient()
+{
+ if(_client != null)
+ {
+ _client.Dispose();
+ _client = null;
+ }
+}
+
+void OnConnectServer(SocketError error)
+{
+ Debug.Log($"Server connect result : {error}");
+ if (error == SocketError.Success)
+ Debug.Log("服务器连接成功!");
+ else
+ Debug.Log("服务器连接失败!");
+}
+
+void Update()
+{
+ // 每帧去获取解析的网络包
+ DefaultNetPackage networkPackage = client.PickPackage() as DefaultNetPackage;
+ if(networkPackage != null)
+ {
+ string json = Encoding.UTF8.GetString(networkPackage.BodyBytes);
+ LoginResponseMessage message = JsonUtility.FromJson(json);
+ Debug.Log(message.Result);
+ }
+}
+
+// 发送登录请求消息
+void SendLoginMessage()
+{
+ LoginRequestMessage message = new LoginRequestMessage();
+ message.Name = "hevinci";
+ message.Password = "1234567";
+
+ DefaultNetPackage networkPackage = new DefaultNetPackage();
+ networkPackage.MsgID = 10001;
+ networkPackage.BodyBytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson(message));
+ _client.SendPackage(networkPackage);
+}
+```
+
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md.meta
new file mode 100644
index 0000000..ec85d20
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9325e3d425f106a41977ea6e672fecdb
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime.meta
new file mode 100644
index 0000000..cf9ffd7
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: efa01143ee531b6478df4aca44367f8a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package.meta
new file mode 100644
index 0000000..c5de313
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3cb02cc27ea1caf479c14cebf66a5dab
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs
new file mode 100644
index 0000000..f0c0713
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs
@@ -0,0 +1,16 @@
+
+namespace UniFramework.Network
+{
+ public class DefaultNetPackage : INetPackage
+ {
+ ///
+ /// 消息ID
+ ///
+ public int MsgID { set; get; }
+
+ ///
+ /// 包体数据
+ ///
+ public byte[] BodyBytes { set; get; }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs.meta
new file mode 100644
index 0000000..e6bde14
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 77bfd5d9f7d9c79478b19cf99a103c47
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs
new file mode 100644
index 0000000..58fbf86
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs
@@ -0,0 +1,86 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 网络包解码器
+ ///
+ public class DefaultNetPackageDecoder : INetPackageDecoder
+ {
+ private HandleErrorDelegate _handleErrorCallback;
+ private const int PackageHeaderLengthFiledSize = 4; //int类型
+ private const int PackageHeaderIDFiledSize = 4; //int类型
+
+ ///
+ /// 获取包头的尺寸
+ ///
+ public int GetPackageHeaderSize()
+ {
+ return PackageHeaderLengthFiledSize + PackageHeaderIDFiledSize;
+ }
+
+ ///
+ /// 注册异常错误回调方法
+ ///
+ ///
+ public void RigistHandleErrorCallback(HandleErrorDelegate callback)
+ {
+ _handleErrorCallback = callback;
+ }
+
+ ///
+ /// 网络消息解码
+ ///
+ /// 包体的最大尺寸
+ /// 解码需要的字节缓冲区
+ /// 接收的包裹列表
+ public void Decode(int packageBodyMaxSize, RingBuffer ringBuffer, List outputPackages)
+ {
+ // 循环解包
+ while (true)
+ {
+ // 如果数据不够判断消息长度
+ if (ringBuffer.ReadableBytes < PackageHeaderLengthFiledSize)
+ break;
+
+ ringBuffer.MarkReaderIndex();
+
+ // 读取Package长度
+ int packageSize = ringBuffer.ReadInt();
+
+ // 如果剩余可读数据小于Package长度
+ if (ringBuffer.ReadableBytes < packageSize)
+ {
+ ringBuffer.ResetReaderIndex();
+ break; //需要退出读够数据再解包
+ }
+
+ DefaultNetPackage package = new DefaultNetPackage();
+
+ // 读取包头
+ {
+ // 读取消息ID
+ package.MsgID = ringBuffer.ReadInt();
+ }
+
+ // 检测包体长度
+ int bodySize = packageSize - PackageHeaderIDFiledSize;
+ if (bodySize > packageBodyMaxSize)
+ {
+ _handleErrorCallback(true, $"The decode package {package.MsgID} body size is larger than {packageBodyMaxSize} !");
+ break;
+ }
+
+ // 读取包体
+ {
+ package.BodyBytes = ringBuffer.ReadBytes(bodySize);
+ outputPackages.Add(package);
+ }
+ }
+
+ // 注意:将剩余数据移至起始
+ ringBuffer.DiscardReadBytes();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs.meta
new file mode 100644
index 0000000..029bf18
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageDecoder.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6b9693105d824c8409392d251d920346
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs
new file mode 100644
index 0000000..58b099a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs
@@ -0,0 +1,84 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 网络包编码器
+ ///
+ public class DefaultNetPackageEncoder : INetPackageEncoder
+ {
+ private HandleErrorDelegate _handleErrorCallback;
+ private const int PackageHeaderLengthFiledSize = 4; //int类型
+ private const int PackageHeaderIDFiledSize = 4; //int类型
+
+ ///
+ /// 获取包头的尺寸
+ ///
+ public int GetPackageHeaderSize()
+ {
+ return PackageHeaderLengthFiledSize + PackageHeaderIDFiledSize;
+ }
+
+ ///
+ /// 注册异常错误回调方法
+ ///
+ ///
+ public void RigistHandleErrorCallback(HandleErrorDelegate callback)
+ {
+ _handleErrorCallback = callback;
+ }
+
+ ///
+ /// 编码
+ ///
+ /// 包体的最大尺寸
+ /// 编码填充的字节缓冲区
+ /// 发送的包裹
+ public void Encode(int packageBodyMaxSize, RingBuffer ringBuffer, INetPackage encodePackage)
+ {
+ if (encodePackage == null)
+ {
+ _handleErrorCallback(false, "The encode package object is null");
+ return;
+ }
+
+ DefaultNetPackage package = (DefaultNetPackage)encodePackage;
+ if (package == null)
+ {
+ _handleErrorCallback(false, $"The encode package object is invalid : {encodePackage.GetType()}");
+ return;
+ }
+
+ // 检测逻辑是否合法
+ if (package.BodyBytes == null)
+ {
+ _handleErrorCallback(false, $"The encode package BodyBytes field is null : {encodePackage.GetType()}");
+ return;
+ }
+
+ // 获取包体数据
+ byte[] bodyData = package.BodyBytes;
+
+ // 检测包体长度
+ if (bodyData.Length > packageBodyMaxSize)
+ {
+ _handleErrorCallback(false, $"The encode package {package.MsgID} body size is larger than {packageBodyMaxSize}");
+ return;
+ }
+
+ // 写入长度
+ int packetLength = PackageHeaderIDFiledSize + bodyData.Length;
+ ringBuffer.WriteInt(packetLength);
+
+ // 写入包头
+ {
+ // 写入消息ID
+ ringBuffer.WriteInt(package.MsgID);
+ }
+
+ // 写入包体
+ ringBuffer.WriteBytes(bodyData, 0, bodyData.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs.meta
new file mode 100644
index 0000000..172f28d
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/DefaultNetPackageEncoder.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a91c21858dd0d2645b67361f76d9e747
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs
new file mode 100644
index 0000000..f0eeb4c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs
@@ -0,0 +1,9 @@
+
+namespace UniFramework.Network
+{
+ public delegate void HandleErrorDelegate(bool isDispose, string error);
+
+ public interface INetPackage
+ {
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs.meta
new file mode 100644
index 0000000..6af8e91
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackage.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 00149ae4ecfb570418760bc2d359e7ca
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs
new file mode 100644
index 0000000..6234d62
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs
@@ -0,0 +1,30 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 网络包解码器
+ ///
+ public interface INetPackageDecoder
+ {
+ ///
+ /// 获取包头的尺寸
+ ///
+ int GetPackageHeaderSize();
+
+ ///
+ /// 注册异常错误回调方法
+ ///
+ ///
+ void RigistHandleErrorCallback(HandleErrorDelegate callback);
+
+ ///
+ /// 网络消息解码
+ ///
+ /// 包体的最大尺寸
+ /// 解码需要的字节缓冲区
+ /// 接收的包裹列表
+ void Decode(int packageBodyMaxSize, RingBuffer ringBuffer, List outputPackages);
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs.meta
new file mode 100644
index 0000000..8fc989c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageDecoder.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8c549df6ac813a74b9fd787e3991a254
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs
new file mode 100644
index 0000000..d56a48c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs
@@ -0,0 +1,30 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 网络包编码器
+ ///
+ public interface INetPackageEncoder
+ {
+ ///
+ /// 获取包头的尺寸
+ ///
+ int GetPackageHeaderSize();
+
+ ///
+ /// 注册异常错误回调方法
+ ///
+ ///
+ void RigistHandleErrorCallback(HandleErrorDelegate callback);
+
+ ///
+ /// 编码
+ ///
+ /// 包体的最大尺寸
+ /// 编码填充的字节缓冲区
+ /// 发送的包裹
+ void Encode(int packageBodyMaxSize, RingBuffer ringBuffer, INetPackage encodePackage);
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs.meta
new file mode 100644
index 0000000..799ad4f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/Package/INetPackageEncoder.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0c4bce3e31495bc4483ab697d895fd62
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs
new file mode 100644
index 0000000..b91fa37
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs
@@ -0,0 +1,537 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using System.Diagnostics;
+using UnityEngine;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 环形缓冲区
+ ///
+ public class RingBuffer
+ {
+ private readonly byte[] _buffer;
+ private int _readerIndex = 0;
+ private int _writerIndex = 0;
+ private int _markedReaderIndex = 0;
+ private int _markedWriterIndex = 0;
+
+
+ ///
+ /// 字节缓冲区
+ ///
+ public RingBuffer(int capacity)
+ {
+ _buffer = new byte[capacity];
+ }
+
+ ///
+ /// 字节缓冲区
+ ///
+ public RingBuffer(byte[] data)
+ {
+ _buffer = data;
+ _writerIndex = data.Length;
+ }
+
+ ///
+ /// 获取数据
+ ///
+ public byte[] GetBuffer()
+ {
+ return _buffer;
+ }
+
+ ///
+ /// 缓冲区容量
+ ///
+ public int Capacity
+ {
+ get { return _buffer.Length; }
+ }
+
+ ///
+ /// 清空缓冲区
+ ///
+ public void Clear()
+ {
+ _readerIndex = 0;
+ _writerIndex = 0;
+ _markedReaderIndex = 0;
+ _markedWriterIndex = 0;
+ }
+
+ ///
+ /// 删除已读部分,重新初始化数组
+ ///
+ public void DiscardReadBytes()
+ {
+ if (_readerIndex == 0)
+ return;
+
+ if (_readerIndex == _writerIndex)
+ {
+ _readerIndex = 0;
+ _writerIndex = 0;
+ }
+ else
+ {
+ for (int i = 0, j = _readerIndex, length = _writerIndex - _readerIndex; i < length; i++, j++)
+ {
+ _buffer[i] = _buffer[j];
+ }
+ _writerIndex -= _readerIndex;
+ _readerIndex = 0;
+ }
+ }
+
+ #region 读取相关
+ ///
+ /// 读取的下标位置
+ ///
+ public int ReaderIndex
+ {
+ get { return _readerIndex; }
+ }
+
+ ///
+ /// 当前可读数据量
+ ///
+ public int ReadableBytes
+ {
+ get { return _writerIndex - _readerIndex; }
+ }
+
+ ///
+ /// 查询是否可以读取
+ ///
+ /// 读取数据量
+ public bool IsReadable(int size = 1)
+ {
+ return _writerIndex - _readerIndex >= size;
+ }
+
+ ///
+ /// 标记读取的下标位置,便于某些时候回退到该位置
+ ///
+ public void MarkReaderIndex()
+ {
+ _markedReaderIndex = _readerIndex;
+ }
+
+ ///
+ /// 回退到标记的读取下标位置
+ ///
+ public void ResetReaderIndex()
+ {
+ _readerIndex = _markedReaderIndex;
+ }
+ #endregion
+
+ #region 写入相关
+ ///
+ /// 写入的下标位置
+ ///
+ public int WriterIndex
+ {
+ get { return _writerIndex; }
+ }
+
+ ///
+ /// 当前可写入数据量
+ ///
+ public int WriteableBytes
+ {
+ get { return Capacity - _writerIndex; }
+ }
+
+ ///
+ /// 查询是否可以写入
+ ///
+ /// 写入数据量
+ public bool IsWriteable(int size = 1)
+ {
+ return Capacity - _writerIndex >= size;
+ }
+
+ ///
+ /// 标记写入的下标位置,便于某些时候回退到该位置。
+ ///
+ public void MarkWriterIndex()
+ {
+ _markedWriterIndex = _writerIndex;
+ }
+
+ ///
+ /// 回退到标记的写入下标位置
+ ///
+ public void ResetWriterIndex()
+ {
+ _writerIndex = _markedWriterIndex;
+ }
+ #endregion
+
+ #region 读取操作
+ [Conditional("DEBUG")]
+ private void CheckReaderIndex(int length)
+ {
+ if (_readerIndex + length > _writerIndex)
+ {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public byte[] ReadBytes(int count)
+ {
+ CheckReaderIndex(count);
+ var data = new byte[count];
+ Buffer.BlockCopy(_buffer, _readerIndex, data, 0, count);
+ _readerIndex += count;
+ return data;
+ }
+ public bool ReadBool()
+ {
+ CheckReaderIndex(1);
+ return _buffer[_readerIndex++] == 1;
+ }
+ public byte ReadByte()
+ {
+ CheckReaderIndex(1);
+ return _buffer[_readerIndex++];
+ }
+ public sbyte ReadSbyte()
+ {
+ return (sbyte)ReadByte();
+ }
+ public short ReadShort()
+ {
+ CheckReaderIndex(2);
+ short result = BitConverter.ToInt16(_buffer, _readerIndex);
+ _readerIndex += 2;
+ return result;
+ }
+ public ushort ReadUShort()
+ {
+ CheckReaderIndex(2);
+ ushort result = BitConverter.ToUInt16(_buffer, _readerIndex);
+ _readerIndex += 2;
+ return result;
+ }
+ public int ReadInt()
+ {
+ CheckReaderIndex(4);
+ int result = BitConverter.ToInt32(_buffer, _readerIndex);
+ _readerIndex += 4;
+ return result;
+ }
+ public uint ReadUInt()
+ {
+ CheckReaderIndex(4);
+ uint result = BitConverter.ToUInt32(_buffer, _readerIndex);
+ _readerIndex += 4;
+ return result;
+ }
+ public long ReadLong()
+ {
+ CheckReaderIndex(8);
+ long result = BitConverter.ToInt64(_buffer, _readerIndex);
+ _readerIndex += 8;
+ return result;
+ }
+ public ulong ReadULong()
+ {
+ CheckReaderIndex(8);
+ ulong result = BitConverter.ToUInt64(_buffer, _readerIndex);
+ _readerIndex += 8;
+ return result;
+ }
+ public float ReadFloat()
+ {
+ CheckReaderIndex(4);
+ float result = BitConverter.ToSingle(_buffer, _readerIndex);
+ _readerIndex += 4;
+ return result;
+ }
+ public double ReadDouble()
+ {
+ CheckReaderIndex(8);
+ double result = BitConverter.ToDouble(_buffer, _readerIndex);
+ _readerIndex += 8;
+ return result;
+ }
+ public string ReadUTF()
+ {
+ ushort count = ReadUShort();
+ CheckReaderIndex(count);
+ string result = Encoding.UTF8.GetString(_buffer, _readerIndex, count - 1); // 注意:读取的时候忽略字符串末尾写入结束符
+ _readerIndex += count;
+ return result;
+ }
+
+ public List ReadListInt()
+ {
+ List result = new List();
+ int count = ReadInt();
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(ReadInt());
+ }
+ return result;
+ }
+ public List ReadListLong()
+ {
+ List result = new List();
+ int count = ReadInt();
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(ReadLong());
+ }
+ return result;
+ }
+ public List ReadListFloat()
+ {
+ List result = new List();
+ int count = ReadInt();
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(ReadFloat());
+ }
+ return result;
+ }
+ public List ReadListDouble()
+ {
+ List result = new List();
+ int count = ReadInt();
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(ReadDouble());
+ }
+ return result;
+ }
+ public List ReadListUTF()
+ {
+ List result = new List();
+ int count = ReadInt();
+ for (int i = 0; i < count; i++)
+ {
+ result.Add(ReadUTF());
+ }
+ return result;
+ }
+
+ public Vector2 ReadVector2()
+ {
+ float x = ReadFloat();
+ float y = ReadFloat();
+ return new Vector2(x, y);
+ }
+ public Vector3 ReadVector3()
+ {
+ float x = ReadFloat();
+ float y = ReadFloat();
+ float z = ReadFloat();
+ return new Vector3(x, y, z);
+ }
+ public Vector4 ReadVector4()
+ {
+ float x = ReadFloat();
+ float y = ReadFloat();
+ float z = ReadFloat();
+ float w = ReadFloat();
+ return new Vector4(x, y, z, w);
+ }
+ #endregion
+
+ #region 写入操作
+ [Conditional("DEBUG")]
+ private void CheckWriterIndex(int length)
+ {
+ if (_writerIndex + length > Capacity)
+ {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ public void WriteBytes(byte[] data)
+ {
+ WriteBytes(data, 0, data.Length);
+ }
+ public void WriteBytes(byte[] data, int offset, int count)
+ {
+ CheckWriterIndex(count);
+ Buffer.BlockCopy(data, offset, _buffer, _writerIndex, count);
+ _writerIndex += count;
+ }
+ public void WriteBool(bool value)
+ {
+ WriteByte((byte)(value ? 1 : 0));
+ }
+ public void WriteByte(byte value)
+ {
+ CheckWriterIndex(1);
+ _buffer[_writerIndex++] = value;
+ }
+ public void WriteSbyte(sbyte value)
+ {
+ // 注意:从sbyte强转到byte不会有数据变化或丢失
+ WriteByte((byte)value);
+ }
+ public void WriteShort(short value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteUShort(ushort value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteInt(int value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteUInt(uint value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteLong(long value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteULong(ulong value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteFloat(float value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteDouble(double value)
+ {
+ byte[] bytes = BitConverter.GetBytes(value);
+ WriteBytes(bytes);
+ }
+ public void WriteUTF(string value)
+ {
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ int num = bytes.Length + 1; // 注意:字符串末尾写入结束符
+ if (num > ushort.MaxValue)
+ throw new FormatException($"String length cannot be greater than {ushort.MaxValue} !");
+
+ WriteUShort(Convert.ToUInt16(num));
+ WriteBytes(bytes);
+ WriteByte((byte)'\0');
+ }
+
+ public void WriteListInt(List values)
+ {
+ int count = 0;
+ if (values != null)
+ count = values.Count;
+
+ WriteInt(count);
+ for (int i = 0; i < count; i++)
+ {
+ WriteInt(values[i]);
+ }
+ }
+ public void WriteListLong(List values)
+ {
+ int count = 0;
+ if (values != null)
+ count = values.Count;
+
+ WriteInt(count);
+ for (int i = 0; i < count; i++)
+ {
+ WriteLong(values[i]);
+ }
+ }
+ public void WriteListFloat(List values)
+ {
+ int count = 0;
+ if (values != null)
+ count = values.Count;
+
+ WriteInt(count);
+ for (int i = 0; i < count; i++)
+ {
+ WriteFloat(values[i]);
+ }
+ }
+ public void WriteListDouble(List values)
+ {
+ int count = 0;
+ if (values != null)
+ count = values.Count;
+
+ WriteInt(count);
+ for (int i = 0; i < count; i++)
+ {
+ WriteDouble(values[i]);
+ }
+ }
+ public void WriteListUTF(List values)
+ {
+ int count = 0;
+ if (values != null)
+ count = values.Count;
+
+ WriteInt(count);
+ for (int i = 0; i < count; i++)
+ {
+ WriteUTF(values[i]);
+ }
+ }
+
+ public void WriteVector2(Vector2 value)
+ {
+ WriteFloat(value.x);
+ WriteFloat(value.y);
+ }
+ public void WriteVector3(Vector3 value)
+ {
+ WriteFloat(value.x);
+ WriteFloat(value.y);
+ WriteFloat(value.z);
+ }
+ public void WriteVector4(Vector4 value)
+ {
+ WriteFloat(value.x);
+ WriteFloat(value.y);
+ WriteFloat(value.z);
+ WriteFloat(value.w);
+ }
+ #endregion
+
+ ///
+ /// 大小端转换
+ ///
+ public static void ReverseOrder(byte[] data)
+ {
+ ReverseOrder(data, 0, data.Length);
+ }
+ public static void ReverseOrder(byte[] data, int offset, int length)
+ {
+ if (length <= 1)
+ return;
+
+ int end = offset + length - 1;
+ int max = offset + length / 2;
+ byte temp;
+ for (int index = offset; index < max; index++, end--)
+ {
+ temp = data[end];
+ data[end] = data[index];
+ data[index] = temp;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs.meta
new file mode 100644
index 0000000..af52d37
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/RingBuffer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dcd2ef8207d26994497ffeb6e8f30d13
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP.meta
new file mode 100644
index 0000000..0372837
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f491992d09ff2c1498b496c4746ff01a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs
new file mode 100644
index 0000000..97df90b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+
+namespace UniFramework.Network
+{
+ internal class TcpChannel : IDisposable
+ {
+ private readonly SocketAsyncEventArgs _receiveArgs = new SocketAsyncEventArgs();
+ private readonly SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs();
+
+ private readonly Queue _sendQueue = new Queue(10000);
+ private readonly Queue _receiveQueue = new Queue(10000);
+ private readonly List _decodeTempList = new List(100);
+
+ private byte[] _receiveBuffer;
+ private RingBuffer _encodeBuffer;
+ private RingBuffer _decodeBuffer;
+ private int _packageBodyMaxSize;
+ private INetPackageEncoder _packageEncoder;
+ private INetPackageDecoder _packageDecoder;
+ private bool _isSending = false;
+ private bool _isReceiving = false;
+
+ ///
+ /// 通信Socket
+ ///
+ private Socket _socket;
+
+ ///
+ /// 同步上下文
+ ///
+ private ThreadSyncContext _context;
+
+ ///
+ /// 初始化频道
+ ///
+ internal void InitChannel(ThreadSyncContext context, Socket socket, int packageBodyMaxSize, INetPackageEncoder encoder, INetPackageDecoder decoder)
+ {
+ if (packageBodyMaxSize <= 0)
+ throw new System.ArgumentException($"PackageMaxSize is invalid : {packageBodyMaxSize}");
+
+ _context = context;
+ _socket = socket;
+ _socket.NoDelay = true;
+
+ // 创建编码解码器
+ _packageBodyMaxSize = packageBodyMaxSize;
+ _packageEncoder = encoder;
+ _packageEncoder.RigistHandleErrorCallback(HandleError);
+ _packageDecoder = decoder;
+ _packageDecoder.RigistHandleErrorCallback(HandleError);
+
+ // 创建字节缓冲类
+ // 注意:字节缓冲区长度,推荐4倍最大包体长度
+ int encoderPackageMaxSize = packageBodyMaxSize + _packageEncoder.GetPackageHeaderSize();
+ int decoderPakcageMaxSize = packageBodyMaxSize + _packageDecoder.GetPackageHeaderSize();
+ _encodeBuffer = new RingBuffer(encoderPackageMaxSize * 4);
+ _decodeBuffer = new RingBuffer(decoderPakcageMaxSize * 4);
+ _receiveBuffer = new byte[decoderPakcageMaxSize];
+
+ // 创建IOCP接收类
+ _receiveArgs.Completed += new EventHandler(IO_Completed);
+ _receiveArgs.SetBuffer(_receiveBuffer, 0, _receiveBuffer.Length);
+
+ // 创建IOCP发送类
+ _sendArgs.Completed += new EventHandler(IO_Completed);
+ _sendArgs.SetBuffer(_encodeBuffer.GetBuffer(), 0, _encodeBuffer.Capacity);
+ }
+
+ ///
+ /// 检测Socket是否已连接
+ ///
+ public bool IsConnected()
+ {
+ if (_socket == null)
+ return false;
+ return _socket.Connected;
+ }
+
+ ///
+ /// Dispose
+ ///
+ public void Dispose()
+ {
+ try
+ {
+ if (_socket != null)
+ _socket.Shutdown(SocketShutdown.Both);
+
+ _receiveArgs.Dispose();
+ _sendArgs.Dispose();
+
+ _sendQueue.Clear();
+ _receiveQueue.Clear();
+ _decodeTempList.Clear();
+
+ _encodeBuffer.Clear();
+ _decodeBuffer.Clear();
+
+ _isSending = false;
+ _isReceiving = false;
+ }
+ catch (Exception)
+ {
+ // throws if client process has already closed, so it is not necessary to catch.
+ }
+ finally
+ {
+ if (_socket != null)
+ {
+ _socket.Close();
+ _socket = null;
+ }
+ }
+ }
+
+ ///
+ /// 主线程内更新
+ ///
+ public void Update()
+ {
+ if (_socket == null || _socket.Connected == false)
+ return;
+
+ // 接收数据
+ UpdateReceiving();
+
+ // 发送数据
+ UpdateSending();
+ }
+ private void UpdateReceiving()
+ {
+ if (_isReceiving == false)
+ {
+ _isReceiving = true;
+
+ // 请求操作
+ bool willRaiseEvent = _socket.ReceiveAsync(_receiveArgs);
+ if (!willRaiseEvent)
+ {
+ ProcessReceive(_receiveArgs);
+ }
+ }
+ }
+ private void UpdateSending()
+ {
+ if (_isSending == false && _sendQueue.Count > 0)
+ {
+ _isSending = true;
+
+ // 清空缓存
+ _encodeBuffer.Clear();
+
+ // 合并数据一起发送
+ while (_sendQueue.Count > 0)
+ {
+ // 如果不够写入一个最大的消息包
+ int encoderPackageMaxSize = _packageBodyMaxSize + _packageEncoder.GetPackageHeaderSize();
+ if (_encodeBuffer.WriteableBytes < encoderPackageMaxSize)
+ break;
+
+ // 数据压码
+ INetPackage package = _sendQueue.Dequeue();
+ _packageEncoder.Encode(_packageBodyMaxSize, _encodeBuffer, package);
+ }
+
+ // 请求操作
+ _sendArgs.SetBuffer(0, _encodeBuffer.ReadableBytes);
+ bool willRaiseEvent = _socket.SendAsync(_sendArgs);
+ if (!willRaiseEvent)
+ {
+ ProcessSend(_sendArgs);
+ }
+ }
+ }
+
+ ///
+ /// 发送网络包
+ ///
+ public void SendPackage(INetPackage package)
+ {
+ lock (_sendQueue)
+ {
+ _sendQueue.Enqueue(package);
+ }
+ }
+
+ ///
+ /// 获取网络包
+ ///
+ public INetPackage PickPackage()
+ {
+ INetPackage package = null;
+ lock (_receiveQueue)
+ {
+ if (_receiveQueue.Count > 0)
+ package = _receiveQueue.Dequeue();
+ }
+ return package;
+ }
+
+
+ ///
+ /// This method is called whenever a receive or send operation is completed on a socket
+ ///
+ private void IO_Completed(object sender, SocketAsyncEventArgs e)
+ {
+ // determine which type of operation just completed and call the associated handler
+ switch (e.LastOperation)
+ {
+ case SocketAsyncOperation.Receive:
+ _context.Post(ProcessReceive, e);
+ break;
+ case SocketAsyncOperation.Send:
+ _context.Post(ProcessSend, e);
+ break;
+ default:
+ throw new ArgumentException("The last operation completed on the socket was not a receive or send");
+ }
+ }
+
+ ///
+ /// 数据接收完成时
+ ///
+ private void ProcessReceive(object obj)
+ {
+ if (_socket == null)
+ return;
+
+ SocketAsyncEventArgs e = obj as SocketAsyncEventArgs;
+
+ // check if the remote host closed the connection
+ if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
+ {
+ // 如果数据写穿
+ if (_decodeBuffer.IsWriteable(e.BytesTransferred) == false)
+ {
+ HandleError(true, "The channel fatal error");
+ return;
+ }
+
+ // 拷贝数据
+ _decodeBuffer.WriteBytes(e.Buffer, 0, e.BytesTransferred);
+
+ // 数据解码
+ _decodeTempList.Clear();
+ _packageDecoder.Decode(_packageBodyMaxSize, _decodeBuffer, _decodeTempList);
+ lock (_receiveQueue)
+ {
+ for (int i = 0; i < _decodeTempList.Count; i++)
+ {
+ _receiveQueue.Enqueue(_decodeTempList[i]);
+ }
+ }
+
+ // 为接收下一段数据,投递接收请求
+ e.SetBuffer(0, _receiveBuffer.Length);
+ bool willRaiseEvent = _socket.ReceiveAsync(e);
+ if (!willRaiseEvent)
+ {
+ ProcessReceive(e);
+ }
+ }
+ else
+ {
+ HandleError(true, $"ProcessReceive error : {e.SocketError}");
+ }
+ }
+
+ ///
+ /// 数据发送完成时
+ ///
+ private void ProcessSend(object obj)
+ {
+ if (_socket == null)
+ return;
+
+ SocketAsyncEventArgs e = obj as SocketAsyncEventArgs;
+ if (e.SocketError == SocketError.Success)
+ {
+ _isSending = false;
+ }
+ else
+ {
+ HandleError(true, $"ProcessSend error : {e.SocketError}");
+ }
+ }
+
+ ///
+ /// 捕获异常错误
+ ///
+ private void HandleError(bool isDispose, string error)
+ {
+ UniLogger.Error(error);
+ if (isDispose) Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs.meta
new file mode 100644
index 0000000..245c6e4
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpChannel.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 841a2723c2b01744fb4bcd170411249f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs
new file mode 100644
index 0000000..50397d6
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+
+namespace UniFramework.Network
+{
+ public class TcpClient : IDisposable
+ {
+ private class UserToken
+ {
+ public System.Action Callback;
+ }
+
+ private TcpChannel _channel;
+ private readonly int _packageBodyMaxSize;
+ private readonly INetPackageEncoder _encoder;
+ private readonly INetPackageDecoder _decoder;
+ private readonly ThreadSyncContext _syncContext;
+
+ private TcpClient()
+ {
+ }
+ internal TcpClient(int packageBodyMaxSize, INetPackageEncoder encoder, INetPackageDecoder decoder)
+ {
+ _packageBodyMaxSize = packageBodyMaxSize;
+ _encoder = encoder;
+ _decoder = decoder;
+ _syncContext = new ThreadSyncContext();
+ }
+
+ ///
+ /// 更新网络
+ ///
+ internal void Update()
+ {
+ _syncContext.Update();
+
+ if (_channel != null)
+ _channel.Update();
+ }
+
+ ///
+ /// 销毁网络
+ ///
+ internal void Destroy()
+ {
+ Dispose();
+ }
+
+ ///
+ /// Dispose
+ ///
+ public void Dispose()
+ {
+ if (_channel != null)
+ {
+ _channel.Dispose();
+ _channel = null;
+ }
+ }
+
+ ///
+ /// 发送网络包
+ ///
+ public void SendPackage(INetPackage package)
+ {
+ if (_channel != null)
+ _channel.SendPackage(package);
+ }
+
+ ///
+ /// 获取网络包
+ ///
+ public INetPackage PickPackage()
+ {
+ if (_channel == null)
+ return null;
+
+ return _channel.PickPackage();
+ }
+
+ ///
+ /// 检测Socket是否已连接
+ ///
+ public bool IsConnected()
+ {
+ if (_channel == null)
+ return false;
+
+ return _channel.IsConnected();
+ }
+
+
+ ///
+ /// 异步连接
+ ///
+ /// IP终端
+ /// 连接回调
+ public void ConnectAsync(IPEndPoint remote, System.Action callback)
+ {
+ UserToken token = new UserToken()
+ {
+ Callback = callback,
+ };
+
+ SocketAsyncEventArgs args = new SocketAsyncEventArgs();
+ args.RemoteEndPoint = remote;
+ args.Completed += new EventHandler(AcceptEventArg_Completed);
+ args.UserToken = token;
+
+ Socket clientSock = new Socket(remote.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+ bool willRaiseEvent = clientSock.ConnectAsync(args);
+ if (!willRaiseEvent)
+ {
+ ProcessConnected(args);
+ }
+ }
+
+ ///
+ /// 处理连接请求
+ ///
+ private void ProcessConnected(object obj)
+ {
+ SocketAsyncEventArgs e = obj as SocketAsyncEventArgs;
+ UserToken token = (UserToken)e.UserToken;
+ if (e.SocketError == SocketError.Success)
+ {
+ if (_channel != null)
+ throw new Exception("TcpClient channel is created.");
+
+ // 创建频道
+ _channel = new TcpChannel();
+ _channel.InitChannel(_syncContext, e.ConnectSocket, _packageBodyMaxSize, _encoder, _decoder);
+ }
+ else
+ {
+ UniLogger.Error($"Network connecte error : {e.SocketError}");
+ }
+
+ // 回调函数
+ if (token.Callback != null)
+ token.Callback.Invoke(e.SocketError);
+ }
+
+ private void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
+ {
+ switch (e.LastOperation)
+ {
+ case SocketAsyncOperation.Connect:
+ _syncContext.Post(ProcessConnected, e);
+ break;
+ default:
+ throw new ArgumentException("The last operation completed on the socket was not a connect");
+ }
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs.meta
new file mode 100644
index 0000000..5d0d895
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/TCP/TcpClient.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 23ae68566c8488c4099ef4652dd317c2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs
new file mode 100644
index 0000000..0cc141b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Threading;
+
+namespace UniFramework.Network
+{
+ ///
+ /// 同步其它线程里的回调到主线程里
+ /// 注意:Unity3D中需要设置Scripting Runtime Version为.NET4.6
+ ///
+ internal sealed class ThreadSyncContext : SynchronizationContext
+ {
+ private readonly ConcurrentQueue _safeQueue = new ConcurrentQueue();
+
+ ///
+ /// 更新同步队列
+ ///
+ public void Update()
+ {
+ while (true)
+ {
+ if (_safeQueue.TryDequeue(out Action action) == false)
+ return;
+ action.Invoke();
+ }
+ }
+
+ ///
+ /// 向同步队列里投递一个回调方法
+ ///
+ public override void Post(SendOrPostCallback callback, object state)
+ {
+ Action action = new Action(() => { callback(state); });
+ _safeQueue.Enqueue(action);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs.meta
new file mode 100644
index 0000000..2ff67ea
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/ThreadSyncContext.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8dc088445ce08dc4e81bfe04a381b449
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef
new file mode 100644
index 0000000..994608f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef
@@ -0,0 +1,14 @@
+{
+ "name": "UniFramework.Network",
+ "rootNamespace": "",
+ "references": [],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef.meta
new file mode 100644
index 0000000..e1ddb21
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniFramework.Network.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 456617c24a0e6ba4dbc9a80e49a9a021
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs
new file mode 100644
index 0000000..2e5a1e3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics;
+
+namespace UniFramework.Network
+{
+ internal static class UniLogger
+ {
+ [Conditional("DEBUG")]
+ public static void Log(string info)
+ {
+ UnityEngine.Debug.Log(info);
+ }
+ public static void Warning(string info)
+ {
+ UnityEngine.Debug.LogWarning(info);
+ }
+ public static void Error(string info)
+ {
+ UnityEngine.Debug.LogError(info);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs.meta
new file mode 100644
index 0000000..1d82d2b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniLogger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 96bf934b4c0166c489b7b967a7c23b32
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs
new file mode 100644
index 0000000..4da83ff
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace UniFramework.Network
+{
+ public static class UniNetwork
+ {
+ private static bool _isInitialize = false;
+ private static GameObject _driver = null;
+ private readonly static List _tcpClients = new List();
+
+ ///
+ /// 初始化网络系统
+ ///
+ public static void Initalize()
+ {
+ if (_isInitialize)
+ throw new Exception($"{nameof(UniNetwork)} is initialized !");
+
+ if (_isInitialize == false)
+ {
+ // 创建驱动器
+ _isInitialize = true;
+ _driver = new GameObject($"[{nameof(UniNetwork)}]");
+ _driver.AddComponent();
+ UnityEngine.Object.DontDestroyOnLoad(_driver);
+ UniLogger.Log($"{nameof(UniNetwork)} initalize !");
+ }
+ }
+
+ ///
+ /// 销毁网络系统
+ ///
+ public static void Destroy()
+ {
+ if (_isInitialize)
+ {
+ foreach (var client in _tcpClients)
+ {
+ client.Destroy();
+ }
+ _tcpClients.Clear();
+
+ _isInitialize = false;
+ if (_driver != null)
+ GameObject.Destroy(_driver);
+ UniLogger.Log($"{nameof(UniNetwork)} destroy all !");
+ }
+ }
+
+ ///
+ /// 更新网络系统
+ ///
+ internal static void Update()
+ {
+ if (_isInitialize)
+ {
+ foreach (var client in _tcpClients)
+ {
+ client.Update();
+ }
+ }
+ }
+
+ ///
+ /// 创建TCP客户端
+ ///
+ /// 网络包体最大长度
+ public static TcpClient CreateTcpClient(int packageBodyMaxSize, INetPackageEncoder encoder, INetPackageDecoder decoder)
+ {
+ if (_isInitialize == false)
+ throw new Exception($"{nameof(UniNetwork)} not initialized !");
+
+ var client = new TcpClient(packageBodyMaxSize, encoder, decoder);
+ _tcpClients.Add(client);
+ return client;
+ }
+
+ ///
+ /// 销毁TCP客户端
+ ///
+ public static void DestroyTcpClient(TcpClient client)
+ {
+ if (client == null)
+ return;
+
+ client.Dispose();
+ _tcpClients.Remove(client);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs.meta
new file mode 100644
index 0000000..868f2ed
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetwork.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6dce5e59401e1344bbd9aabf981383b5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs
new file mode 100644
index 0000000..687952a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+
+namespace UniFramework.Network
+{
+ internal class UniNetworkDriver : MonoBehaviour
+ {
+ void Update()
+ {
+ UniNetwork.Update();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs.meta
new file mode 100644
index 0000000..a94f2c1
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniNetwork/Runtime/UniNetworkDriver.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2490b5980d0936344a4c3574bcced111
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling.meta
index cd48b36..2f95771 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 7cfeaa68459d1cb4f96e62f6b7bd9fd7
+guid: 2348da7d2a69de841a7ad5508df0bf90
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/GameObjectPool.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/GameObjectPool.cs
index 4a52cf8..0a09c7a 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/GameObjectPool.cs
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/GameObjectPool.cs
@@ -8,7 +8,7 @@ namespace UniFramework.Pooling
{
internal class GameObjectPool
{
- private readonly Transform _poolRoot;
+ private readonly GameObject _root;
private readonly Queue _cacheOperations;
private readonly bool _dontDestroy;
private readonly int _initCapacity;
@@ -48,9 +48,10 @@ namespace UniFramework.Pooling
}
- public GameObjectPool(GameObject poolRoot, string location, bool dontDestroy, int initCapacity, int maxCapacity, float destroyTime)
+ public GameObjectPool(GameObject poolingRoot, string location, bool dontDestroy, int initCapacity, int maxCapacity, float destroyTime)
{
- _poolRoot = poolRoot.transform;
+ _root = new GameObject(location);
+ _root.transform.parent = poolingRoot.transform;
Location = location;
_dontDestroy = dontDestroy;
@@ -73,7 +74,7 @@ namespace UniFramework.Pooling
// 创建初始对象
for (int i = 0; i < _initCapacity; i++)
{
- var operation = AssetHandle.InstantiateAsync(_poolRoot);
+ var operation = AssetHandle.InstantiateAsync(_root.transform);
_cacheOperations.Enqueue(operation);
}
}
@@ -88,11 +89,7 @@ namespace UniFramework.Pooling
AssetHandle = null;
// 销毁游戏对象
- foreach (var operation in _cacheOperations)
- {
- if (operation.Result != null)
- GameObject.Destroy(operation.Result);
- }
+ GameObject.Destroy(_root);
_cacheOperations.Clear();
SpawnCount = 0;
@@ -207,7 +204,7 @@ namespace UniFramework.Pooling
if (gameObj != null)
{
gameObj.SetActive(false);
- gameObj.transform.SetParent(_poolRoot);
+ gameObj.transform.SetParent(_root.transform);
gameObj.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
}
}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniSingleton.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniFramework.Pooling.asmdef
similarity index 90%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniSingleton.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniFramework.Pooling.asmdef
index 76ce370..67d8d9e 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniSingleton.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniFramework.Pooling.asmdef
@@ -1,5 +1,5 @@
{
- "name": "UniSingleton",
+ "name": "UniFramework.Pooling",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniPooling.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniFramework.Pooling.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniPooling.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniPooling/Runtime/UniFramework.Pooling.asmdef.meta
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton.meta
index 664903f..dd63952 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: c4d0461b6228c584dab24fbeb8dc4907
+guid: 645ad92cafefcc144b8a9811864e1d73
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniFramework.Singleton.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniFramework.Singleton.asmdef
new file mode 100644
index 0000000..874b7db
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniFramework.Singleton.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "UniFramework.Singleton",
+ "rootNamespace": "",
+ "references": [
+ "GUID:e34a5702dd353724aa315fb8011f08c3"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": true,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniSingleton.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniFramework.Singleton.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniSingleton.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniSingleton/Runtime/UniFramework.Singleton.asmdef.meta
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween.meta
new file mode 100644
index 0000000..953684c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 13f396e17446c5545bd76be7fda54f4d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md
new file mode 100644
index 0000000..0b2bc49
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md
@@ -0,0 +1,90 @@
+# UniFramework.Tween
+
+一个轻量级的补间动画系统。(扩展方便,使用灵活,功能强大)
+
+初始化补间动画系统
+
+```c#
+using UnityEngine;
+using UniFramework.Tween;
+
+void Start()
+{
+ // 初始化补间动画系统
+ UniTween.Initalize();
+}
+```
+
+传统编程
+
+```c#
+void Start()
+{
+ // 原地停留1秒,然后向上移动,停留1秒,然后同时缩小并回归原位。
+ var tween = UniTween.AllocateSequence
+ (
+ UniTween.AllocateDelay(1f),
+ this.transform.TweenMove(0.5f, new Vector3(0, 256, 0)),
+ UniTween.AllocateDelay(1f),
+ UniTween.AllocateParallel
+ (
+ this.transform.TweenScaleTo(0.5f, new Vector3(0.2f, 0.2f, 1f)),
+ this.transform.TweenMove(0.5f, new Vector3(0, 0, 0))
+ )
+ );
+ this.gameObject.PlayTween(tween);
+}
+```
+
+链式编程
+
+```c#
+void Start()
+{
+ // 原地停留1秒,然后向上移动,停留1秒,然后同时缩小并回归原位。
+ ITweenChain tween = UniTween.AllocateSequence();
+ tween.Delay(1f).
+ Append(this.transform.TweenMove(0.5f, new Vector3(0, 256, 0))).
+ Delay(1f).
+ SwitchToParallel().
+ Append(this.transform.TweenScaleTo(0.5f, new Vector3(0.2f, 0.2f, 1f))).
+ Append(this.transform.TweenMove(0.5f, new Vector3(0, 0, 0)));
+ this.gameObject.PlayTween(tween);
+}
+```
+
+默认的公共补间方法一共有30种,还可以使用AnimationCurve补充效果
+
+```c#
+public AnimationCurve EaseCurve;
+
+public void PlayAnim()
+{
+ var tween = this.transform.TweenScaleTo(1f, Vector3.zero).SetEase(EaseCurve);
+ UniTween.Play(tween);
+}
+```
+
+扩展支持任意对象
+
+```c#
+// 扩展支持Image对象
+public static class UnityEngine_UI_Image_Tween_Extension
+{
+ public static ColorTween TweenColor(this Image obj, float duration, Color from, Color to)
+ {
+ ColorTween node = ColorTween.Allocate(duration, from, to);
+ node.SetOnUpdate((result) => { obj.color = result; });
+ return node;
+ }
+ public static ColorTween TweenColorTo(this Image obj, float duration, Color to)
+ {
+ return TweenColor(obj, duration, obj.color, to);
+ }
+ public static ColorTween TweenColorFrom(this Image obj, float duration, Color from)
+ {
+ return TweenColor(obj, duration, from, obj.color);
+ }
+}
+```
+
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md.meta
new file mode 100644
index 0000000..1e8f028
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/README.md.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ac85f5ddcea96cd46931986ac50d5204
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime.meta
new file mode 100644
index 0000000..3bb6307
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f3cdaa08c50e0dd4c940fb957314cf2d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs
new file mode 100644
index 0000000..5569aea
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs
@@ -0,0 +1,24 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 补间循环类型
+ ///
+ public enum ETweenLoop
+ {
+ ///
+ /// 只执行一次
+ ///
+ None,
+
+ ///
+ /// 从头执行
+ ///
+ Restart,
+
+ ///
+ /// 反复执行
+ ///
+ PingPong,
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs.meta
new file mode 100644
index 0000000..22a8cd7
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenLoop.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1391131ea350c9640a05910d947a38b8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs
new file mode 100644
index 0000000..2bafdf6
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs
@@ -0,0 +1,29 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 补间动画状态
+ ///
+ public enum ETweenStatus
+ {
+ ///
+ /// 空闲状态
+ ///
+ Idle,
+
+ ///
+ /// 运行中
+ ///
+ Runing,
+
+ ///
+ /// 已经完成
+ ///
+ Completed,
+
+ ///
+ /// 已被终止
+ ///
+ Abort,
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs.meta
new file mode 100644
index 0000000..ef4c580
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ETweenStatus.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 315dd5291803c6b40a9ab70933c4d50b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs
new file mode 100644
index 0000000..09de75b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs
@@ -0,0 +1,8 @@
+
+namespace UniFramework.Tween
+{
+ public interface ITweenChain
+ {
+ ITweenChain Append(ITweenNode node);
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs.meta
new file mode 100644
index 0000000..fe790ee
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenChain.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1a69c912d23f3f446aa6dee33054bcc1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs
new file mode 100644
index 0000000..82e50fc
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs
@@ -0,0 +1,15 @@
+
+namespace UniFramework.Tween
+{
+ public interface ITweenNode
+ {
+ ///
+ /// 节点状态
+ ///
+ ETweenStatus Status { get; }
+
+ void OnUpdate(float deltaTime);
+ void OnDispose();
+ void Abort();
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs.meta
new file mode 100644
index 0000000..61a9ba8
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/ITweenNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d96ae9e29e307e44087fc62fdc6fc259
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain.meta
new file mode 100644
index 0000000..024641d
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 466dbe54c22685f48b0bc73113a7edd1
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs
new file mode 100644
index 0000000..0f380e9
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs
@@ -0,0 +1,126 @@
+
+namespace UniFramework.Tween
+{
+ public static partial class TweenChainExtension
+ {
+ ///
+ /// 执行节点
+ ///
+ public static ITweenChain Execute(this ITweenChain chain, System.Action execute)
+ {
+ return chain.Append(UniTween.AllocateExecute(execute));
+ }
+
+ ///
+ /// 条件等待节点
+ ///
+ public static ITweenChain Until(this ITweenChain chain, System.Func condition)
+ {
+ return chain.Append(UniTween.AllocateUntil(condition));
+ }
+
+
+ ///
+ /// 并行执行的复合节点
+ ///
+ public static ITweenChain AppendParallel(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateParallel(nodes);
+ chain.Append(node);
+ return chain;
+ }
+
+ ///
+ /// 顺序执行的复合节点
+ ///
+ public static ITweenChain AppendSequence(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateSequence(nodes);
+ chain.Append(node);
+ return chain;
+ }
+
+ ///
+ /// 随机执行的复合节点
+ ///
+ public static ITweenChain AppendSelector(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateSelector(nodes);
+ chain.Append(node);
+ return chain;
+ }
+
+
+ ///
+ /// 并行执行的复合节点
+ ///
+ public static ITweenChain SwitchToParallel(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateParallel(nodes);
+ chain.Append(node);
+ return node;
+ }
+
+ ///
+ /// 顺序执行的复合节点
+ ///
+ public static ITweenChain SwitchToSequence(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateSequence(nodes);
+ chain.Append(node);
+ return node;
+ }
+
+ ///
+ /// 随机执行的复合节点
+ ///
+ public static ITweenChain SwitchToSelector(this ITweenChain chain, params ITweenNode[] nodes)
+ {
+ var node = UniTween.AllocateSelector(nodes);
+ chain.Append(node);
+ return node;
+ }
+
+
+ ///
+ /// 延迟计时节点
+ ///
+ public static ITweenChain Delay(this ITweenChain chain, float delay, System.Action trigger = null)
+ {
+ return chain.Append(UniTween.AllocateDelay(delay, trigger));
+ }
+
+ ///
+ /// 重复计时节点
+ /// 注意:该节点为无限时长
+ ///
+ public static ITweenChain Repeat(this ITweenChain chain, float delay, float interval, System.Action trigger = null)
+ {
+ return chain.Append(UniTween.AllocateRepeat(delay, interval, trigger));
+ }
+
+ ///
+ /// 重复计时节点
+ ///
+ public static ITweenChain Repeat(this ITweenChain chain, float delay, float interval, float duration, System.Action trigger = null)
+ {
+ return chain.Append(UniTween.AllocateRepeat(delay, interval, duration, trigger));
+ }
+
+ ///
+ /// 重复计时节点
+ ///
+ public static ITweenChain Repeat(this ITweenChain chain, float delay, float interval, long maxRepeatCount, System.Action trigger = null)
+ {
+ return chain.Append(UniTween.AllocateRepeat(delay, interval, maxRepeatCount, trigger));
+ }
+
+ ///
+ /// 持续计时节点
+ ///
+ public static ITweenChain Duration(this ITweenChain chain, float delay, float duration, System.Action trigger = null)
+ {
+ return chain.Append(UniTween.AllocateDuration(delay, duration, trigger));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs.meta
new file mode 100644
index 0000000..0614d2b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenChain/TweenChainExtension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7f62323a6b951174b9a207f7e8d3971b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs
new file mode 100644
index 0000000..29dd736
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs
@@ -0,0 +1,228 @@
+//--------------------------------------------------
+// Author : David Ochmann
+// Website:https://easings.net/
+//--------------------------------------------------
+using System;
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 公共补间方法
+ ///
+ public static class TweenEase
+ {
+ public static class Linear
+ {
+ public static float Default(float t, float b, float c, float d)
+ {
+ return c * t / d + b;
+ }
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c * t / d + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return c * t / d + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ return c * t / d + b;
+ }
+ }
+ public static class Sine
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return -c * (float)Math.Cos(t / d * ((float)Math.PI / 2)) + c + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return c * (float)Math.Sin(t / d * ((float)Math.PI / 2)) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ return -c / 2f * ((float)Math.Cos((float)Math.PI * t / d) - 1) + b;
+ }
+ }
+ public static class Quad
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c * (t /= d) * t + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return -c * (t /= d) * (t - 2) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if ((t /= d / 2) < 1) return c / 2 * t * t + b;
+ return -c / 2 * ((--t) * (t - 2) - 1) + b;
+ }
+ }
+ public static class Cubic
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c * (t /= d) * t * t + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return c * ((t = t / d - 1) * t * t + 1) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
+ return c / 2 * ((t -= 2) * t * t + 2) + b;
+ }
+ }
+ public static class Quart
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c * (t /= d) * t * t * t + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return -c * ((t = t / d - 1) * t * t * t - 1) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
+ return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
+ }
+ }
+ public static class Quint
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c * (t /= d) * t * t * t * t + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
+ return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
+ }
+ }
+ public static class Expo
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return (t == 0) ? b : c * (float)Math.Pow(2, 10 * (t / d - 1)) + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return (t == d) ? b + c : c * (-(float)Math.Pow(2, -10 * t / d) + 1) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if (t == 0) return b;
+ if (t == d) return b + c;
+ if ((t /= d / 2) < 1) return c / 2 * (float)Math.Pow(2, 10 * (t - 1)) + b;
+ return c / 2 * (-(float)Math.Pow(2, -10 * --t) + 2) + b;
+ }
+ }
+ public static class Circ
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return -c * ((float)Math.Sqrt(1 - (t /= d) * t) - 1) + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ return c * (float)Math.Sqrt(1 - (t = t / d - 1) * t) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if ((t /= d / 2) < 1) return -c / 2 * ((float)Math.Sqrt(1 - t * t) - 1) + b;
+ return c / 2 * ((float)Math.Sqrt(1 - (t -= 2) * t) + 1) + b;
+ }
+ }
+ public static class Back
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ float s = 1.70158f;
+ return c * (t /= d) * t * ((s + 1) * t - s) + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ float s = 1.70158f;
+ return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ float s = 1.70158f;
+ if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b;
+ return c / 2 * ((t -= 2) * t * (((s *= (1.525f)) + 1) * t + s) + 2) + b;
+ }
+ }
+ public static class Elastic
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ if (t == 0) return b; if ((t /= d) == 1) return b + c; float p = d * .3f;
+
+ float a = c;
+ float s = p / 4;
+
+ return -(a * (float)Math.Pow(2, 10 * (t -= 1)) * (float)Math.Sin((t * d - s) * (2 * (float)Math.PI) / p)) + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ if (t == 0) return b; if ((t /= d) == 1) return b + c; float p = d * .3f;
+
+ float a = c;
+ float s = p / 4;
+
+ return (a * (float)Math.Pow(2, -10 * t) * (float)Math.Sin((t * d - s) * (2 * (float)Math.PI) / p) + c + b);
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if (t == 0) return b; if ((t /= d / 2) == 2) return b + c; float p = d * (.3f * 1.5f);
+
+ float a = c;
+ float s = p / 4;
+
+ if (t < 1) return -.5f * (a * (float)Math.Pow(2, 10 * (t -= 1)) * (float)Math.Sin((t * d - s) * (2 * (float)Math.PI) / p)) + b;
+ return a * (float)Math.Pow(2, -10 * (t -= 1)) * (float)Math.Sin((t * d - s) * (2 * (float)Math.PI) / p) * .5f + c + b;
+ }
+ }
+ public static class Bounce
+ {
+ public static float EaseIn(float t, float b, float c, float d)
+ {
+ return c - Bounce.EaseOut(d - t, 0, c, d) + b;
+ }
+ public static float EaseOut(float t, float b, float c, float d)
+ {
+ if ((t /= d) < (1 / 2.75f))
+ {
+ return c * (7.5625f * t * t) + b;
+ }
+ else if (t < (2 / 2.75f))
+ {
+ return c * (7.5625f * (t -= (1.5f / 2.75f)) * t + .75f) + b;
+ }
+ else if (t < (2.5f / 2.75f))
+ {
+ return c * (7.5625f * (t -= (2.25f / 2.75f)) * t + .9375f) + b;
+ }
+ else
+ {
+ return c * (7.5625f * (t -= (2.625f / 2.75f)) * t + .984375f) + b;
+ }
+ }
+ public static float EaseInOut(float t, float b, float c, float d)
+ {
+ if (t < d / 2) return Bounce.EaseIn(t * 2, 0, c, d) * .5f + b;
+ else return Bounce.EaseOut(t * 2 - d, 0, c, d) * .5f + c * .5f + b;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs.meta
new file mode 100644
index 0000000..fa0abdf
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenEase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f73be75c1e900a64bab71022ae49d368
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension.meta
new file mode 100644
index 0000000..54cad7e
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 688bba5b21bb5fa40ac50ba0292aae82
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs
new file mode 100644
index 0000000..40b2357
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs
@@ -0,0 +1,22 @@
+using UniFramework.Tween;
+
+namespace UnityEngine
+{
+ public static class UnityEngine_CanvasGroup_Tween_Extension
+ {
+ public static FloatTween TweenAlpha(this CanvasGroup obj, float duration, float from, float to)
+ {
+ FloatTween node = FloatTween.Allocate(duration, from, to);
+ node.SetOnUpdate((result) => { obj.alpha = result; });
+ return node;
+ }
+ public static FloatTween TweenAlphaTo(this CanvasGroup obj, float duration, float to)
+ {
+ return TweenAlpha(obj, duration, obj.alpha, to);
+ }
+ public static FloatTween TweenAlphaFrom(this CanvasGroup obj, float duration, float from)
+ {
+ return TweenAlpha(obj, duration, from, obj.alpha);
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs.meta
new file mode 100644
index 0000000..09ed09d
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_CanvasGroup_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8852afd144dfb644d9828c95d09536fd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs
new file mode 100644
index 0000000..9487ef2
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs
@@ -0,0 +1,31 @@
+using UniFramework.Tween;
+
+namespace UnityEngine
+{
+ public static class UnityEngine_GameObject_Tween_Extension
+ {
+ ///
+ /// 播放补间动画
+ ///
+ public static TweenHandle PlayTween(this GameObject go, ITweenNode tweenRoot)
+ {
+ return UniTween.Play(tweenRoot, go);
+ }
+
+ ///
+ /// 播放补间动画
+ ///
+ public static TweenHandle PlayTween(this GameObject go, ITweenChain tweenRoot)
+ {
+ return UniTween.Play(tweenRoot, go);
+ }
+
+ ///
+ /// 播放补间动画
+ ///
+ public static TweenHandle PlayTween(this GameObject go, ChainNode tweenRoot)
+ {
+ return UniTween.Play(tweenRoot, go);
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs.meta
new file mode 100644
index 0000000..5bf4645
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_GameObject_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 257bf3445be76d349a37454396799650
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs
new file mode 100644
index 0000000..3efe150
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs
@@ -0,0 +1,26 @@
+using UniFramework.Tween;
+
+namespace UnityEngine
+{
+ public static class UnityEngine_RectTransform_Tween_Extension
+ {
+ public static Vector2Tween TweenAnchoredPosition(this RectTransform obj, float duration, Vector2 from, Vector2 to)
+ {
+ Vector2Tween node = Vector2Tween.Allocate(duration, from, to);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ obj.anchoredPosition = result;
+ });
+ return node;
+ }
+ public static Vector2Tween TweenAnchoredPositionTo(this RectTransform obj, float duration, Vector2 to)
+ {
+ return TweenAnchoredPosition(obj, duration, obj.anchoredPosition, to);
+ }
+ public static Vector2Tween TweenAnchoredPositionFrom(this RectTransform obj, float duration, Vector2 from)
+ {
+ return TweenAnchoredPosition(obj, duration, from, obj.anchoredPosition);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs.meta
new file mode 100644
index 0000000..0f30928
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_RectTransform_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6c8bdaa0ab683904f9b5c002995e43e5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs
new file mode 100644
index 0000000..7cd48c3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs
@@ -0,0 +1,137 @@
+using UniFramework.Tween;
+
+namespace UnityEngine
+{
+ public static class UnityEngine_Transform_Tween_Extension
+ {
+ public static Vector3Tween TweenScale(this Transform obj, float duration, Vector3 from, Vector3 to)
+ {
+ Vector3Tween node = Vector3Tween.Allocate(duration, from, to);
+ node.SetOnUpdate((result) => { obj.localScale = result; });
+ return node;
+ }
+ public static Vector3Tween TweenScaleTo(this Transform obj, float duration, Vector3 to)
+ {
+ return TweenScale(obj, duration, obj.localScale, to);
+ }
+ public static Vector3Tween TweenScaleFrom(this Transform obj, float duration, Vector3 from)
+ {
+ return TweenScale(obj, duration, from, obj.localScale);
+ }
+
+ public static Vector3Tween ShakePosition(this Transform obj, float duration, Vector3 magnitude, bool relativeWorld = false)
+ {
+ Vector3 position = relativeWorld ? obj.position : obj.localPosition;
+ Vector3Tween node = Vector3Tween.Allocate(duration, position, position);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ if (relativeWorld)
+ obj.position = result;
+ else
+ obj.localPosition = result;
+ });
+ node.SetLerp(
+ (from, to, progress) =>
+ {
+ return TweenMath.Shake(magnitude, from, progress);
+ });
+ node.SetLoop(ETweenLoop.PingPong, 1);
+ return node;
+ }
+ public static Vector3Tween TweenMove(this Transform obj, float duration, Vector3 dest, bool relativeWorld = false)
+ {
+ Vector3Tween node = Vector3Tween.Allocate(duration, dest, dest);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ if (relativeWorld)
+ obj.position = result;
+ else
+ obj.localPosition = result;
+ });
+ node.SetOnBegin(
+ () =>
+ {
+ if (relativeWorld)
+ node.SetValueFrom(obj.position);
+ else
+ node.SetValueFrom(obj.localPosition);
+ }
+ );
+ return node;
+ }
+ public static Vector3Tween TweenPosition(this Transform obj, float duration, Vector3 from, Vector3 to, bool relativeWorld = false)
+ {
+ Vector3Tween node = Vector3Tween.Allocate(duration, from, to);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ if (relativeWorld)
+ obj.position = result;
+ else
+ obj.localPosition = result;
+ });
+ return node;
+ }
+ public static Vector3Tween TweenPositionTo(this Transform obj, float duration, Vector3 to, bool relativeWorld = false)
+ {
+ Vector3 from = relativeWorld ? obj.position : obj.localPosition;
+ return TweenPosition(obj, duration, from, to, relativeWorld);
+ }
+ public static Vector3Tween TweenPositionFrom(this Transform obj, float duration, Vector3 from, bool relativeWorld = false)
+ {
+ Vector3 to = relativeWorld ? obj.position : obj.localPosition;
+ return TweenPosition(obj, duration, from, to, relativeWorld);
+ }
+
+ public static Vector3Tween TweenAngles(this Transform obj, float duration, Vector3 from, Vector3 to, bool relativeWorld = false)
+ {
+ Vector3Tween node = Vector3Tween.Allocate(duration, from, to);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ if (relativeWorld)
+ obj.eulerAngles = result;
+ else
+ obj.localEulerAngles = result;
+ });
+ node.SetLerp(TweenMath.AngleLerp);
+ return node;
+ }
+ public static Vector3Tween TweenAnglesTo(this Transform obj, float duration, Vector3 to, bool relativeWorld = false)
+ {
+ Vector3 from = relativeWorld ? obj.eulerAngles : obj.localEulerAngles;
+ return TweenAngles(obj, duration, from, to, relativeWorld);
+ }
+ public static Vector3Tween TweenAnglesFrom(this Transform obj, float duration, Vector3 from, bool relativeWorld = false)
+ {
+ Vector3 to = relativeWorld ? obj.eulerAngles : obj.localEulerAngles;
+ return TweenAngles(obj, duration, from, to, relativeWorld);
+ }
+
+ public static QuaternionTween TweenRotation(this Transform obj, float duration, Quaternion from, Quaternion to, bool relativeWorld = false)
+ {
+ QuaternionTween node = QuaternionTween.Allocate(duration, from, to);
+ node.SetOnUpdate(
+ (result) =>
+ {
+ if (relativeWorld)
+ obj.rotation = result;
+ else
+ obj.localRotation = result;
+ });
+ return node;
+ }
+ public static QuaternionTween TweenRotationTo(this Transform obj, float duration, Quaternion to, bool relativeWorld = false)
+ {
+ Quaternion from = relativeWorld ? obj.rotation : obj.localRotation;
+ return TweenRotation(obj, duration, from, to, relativeWorld);
+ }
+ public static QuaternionTween TweenRotationFrom(this Transform obj, float duration, Quaternion from, bool relativeWorld = false)
+ {
+ Quaternion to = relativeWorld ? obj.rotation : obj.localRotation;
+ return TweenRotation(obj, duration, from, to, relativeWorld);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs.meta
new file mode 100644
index 0000000..a081e54
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_Transform_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3848269d8b1e18e4fab08c34a729fc36
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs
new file mode 100644
index 0000000..9e76390
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs
@@ -0,0 +1,22 @@
+using UniFramework.Tween;
+
+namespace UnityEngine.UI
+{
+ public static class UnityEngine_UI_Image_Tween_Extension
+ {
+ public static ColorTween TweenColor(this Image obj, float duration, Color from, Color to)
+ {
+ ColorTween node = ColorTween.Allocate(duration, from, to);
+ node.SetOnUpdate((result) => { obj.color = result; });
+ return node;
+ }
+ public static ColorTween TweenColorTo(this Image obj, float duration, Color to)
+ {
+ return TweenColor(obj, duration, obj.color, to);
+ }
+ public static ColorTween TweenColorFrom(this Image obj, float duration, Color from)
+ {
+ return TweenColor(obj, duration, from, obj.color);
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs.meta
new file mode 100644
index 0000000..53468a5
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Image_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dc5c855c625d63e429c5975f4c87ae20
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs
new file mode 100644
index 0000000..6af1889
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs
@@ -0,0 +1,22 @@
+using UniFramework.Tween;
+
+namespace UnityEngine.UI
+{
+ public static class UnityEngine_UI_Text_Tween_Extension
+ {
+ public static ColorTween TweenColor(this Text obj, float duration, Color from, Color to)
+ {
+ ColorTween node = ColorTween.Allocate(duration, from, to);
+ node.SetOnUpdate((result) => { obj.color = result; });
+ return node;
+ }
+ public static ColorTween TweenColorTo(this Text obj, float duration, Color to)
+ {
+ return TweenColor(obj, duration, obj.color, to);
+ }
+ public static ColorTween TweenColorFrom(this Text obj, float duration, Color from)
+ {
+ return TweenColor(obj, duration, from, obj.color);
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs.meta
new file mode 100644
index 0000000..687fe05
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenExtension/UnityEngine_UI_Text_Tween_Extension.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 65a5efc0be7931241ba1ad7ea25398d5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs
new file mode 100644
index 0000000..0da22dd
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs
@@ -0,0 +1,90 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 补间动画句柄
+ ///
+ public class TweenHandle
+ {
+ private readonly ITweenNode _tweenRoot;
+ private readonly UnityEngine.Object _unityObject;
+ private readonly bool _safeMode;
+ private bool _hasException = false;
+ internal int InstanceID { private set; get; }
+
+ private TweenHandle()
+ {
+ }
+ internal TweenHandle(ITweenNode tweenRoot, UnityEngine.Object unityObject)
+ {
+ _tweenRoot = tweenRoot;
+ _unityObject = unityObject;
+
+ if (unityObject == null)
+ {
+ InstanceID = 0;
+ _safeMode = false;
+ }
+ else
+ {
+ InstanceID = unityObject.GetInstanceID();
+ _safeMode = true;
+ }
+ }
+ internal void Update(float deltaTime)
+ {
+ try
+ {
+ _tweenRoot.OnUpdate(deltaTime);
+ }
+ catch (System.Exception e)
+ {
+ _hasException = true;
+ UniLogger.Warning($"TweenNode has exception : {e}");
+ }
+ }
+ internal void Dispose()
+ {
+ try
+ {
+ _tweenRoot.OnDispose();
+ }
+ catch(System.Exception e)
+ {
+ UniLogger.Warning($"TweenNode has exception : {e}");
+ }
+ }
+ internal bool IsCanRemove()
+ {
+ // 检测游戏对象是否销毁
+ if (_safeMode)
+ {
+ if (_unityObject == null)
+ {
+ _tweenRoot.Abort();
+ return true;
+ }
+ }
+
+ // 检测运行过程是否发生异常
+ if (_hasException)
+ {
+ _tweenRoot.Abort();
+ return true;
+ }
+
+ if (_tweenRoot.Status == ETweenStatus.Abort || _tweenRoot.Status == ETweenStatus.Completed)
+ return true;
+ else
+ return false;
+ }
+
+ ///
+ /// 终止补间动画
+ ///
+ public void Abort()
+ {
+ _tweenRoot.Abort();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs.meta
new file mode 100644
index 0000000..6dadae0
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenHandle.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 20d19c757b8deb54790d4fb99e8a5315
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs
new file mode 100644
index 0000000..dbc9235
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs
@@ -0,0 +1,65 @@
+using UnityEngine;
+
+namespace UniFramework.Tween
+{
+ public static class TweenMath
+ {
+ ///
+ /// 角度插值
+ ///
+ public static Vector3 AngleLerp(Vector3 from, Vector3 to, float progress)
+ {
+ float x = Mathf.LerpAngle(from.x, to.x, progress);
+ float y = Mathf.LerpAngle(from.y, to.y, progress);
+ float z = Mathf.LerpAngle(from.z, to.z, progress);
+ Vector3 result = new Vector3(x, y, z);
+ return result;
+ }
+
+ ///
+ /// 二阶贝塞尔曲线
+ ///
+ public static Vector3 QuadBezier(Vector3 p1, Vector3 c, Vector3 p2, float progress)
+ {
+ float t = progress;
+ float d = 1f - t;
+ return d * d * p1 + 2f * d * t * c + t * t * p2;
+ }
+
+ ///
+ /// 三阶贝塞尔曲线
+ ///
+ public static Vector3 CubicBezier(Vector3 p1, Vector3 c1, Vector3 c2, Vector3 p2, float progress)
+ {
+ float t = progress;
+ float d = 1f - t;
+ return d * d * d * p1 + 3f * d * d * t * c1 + 3f * d * t * t * c2 + t * t * t * p2;
+ }
+
+ ///
+ /// 样条曲线
+ ///
+ public static Vector3 CatmullRoom(Vector3 c1, Vector3 p1, Vector3 p2, Vector3 c2, float progress)
+ {
+ float t = progress;
+ return .5f *
+ (
+ (-c1 + 3f * p1 - 3f * p2 + c2) * (t * t * t)
+ + (2f * c1 - 5f * p1 + 4f * p2 - c2) * (t * t)
+ + (-c1 + p2) * t
+ + 2f * p1
+ );
+ }
+
+ ///
+ /// 震动采样
+ ///
+ public static Vector3 Shake(Vector3 magnitude, Vector3 position, float progress)
+ {
+ float x = Random.Range(-magnitude.x, magnitude.x) * progress;
+ float y = Random.Range(-magnitude.y, magnitude.y) * progress;
+ float z = Random.Range(-magnitude.z, magnitude.z) * progress;
+ return position + new Vector3(x, y, z);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs.meta
new file mode 100644
index 0000000..466105e
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenMath.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0a8b3a494b08ef3408b6f52b5abe7db2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode.meta
new file mode 100644
index 0000000..7594f67
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f1ce3e0893e80104fbc320d03a5bf5bc
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs
new file mode 100644
index 0000000..404aeb3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs
@@ -0,0 +1,103 @@
+using System.Collections.Generic;
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 复合节点基类
+ ///
+ public abstract class ChainNode : ITweenNode, ITweenChain
+ {
+ protected List _nodes = new List();
+
+ private System.Action _onBegin = null;
+ private System.Action _onComplete = null;
+ private System.Action _onDispose = null;
+
+ ///
+ /// 节点状态
+ ///
+ public ETweenStatus Status { private set; get; } = ETweenStatus.Idle;
+
+
+ ///
+ /// 添加节点
+ ///
+ public void AddNode(ITweenNode node)
+ {
+ if (_nodes.Contains(node) == false)
+ _nodes.Add(node);
+ }
+
+ ///
+ /// 添加节点
+ ///
+ ///
+ public void AddNode(params ITweenNode[] nodes)
+ {
+ foreach (var node in nodes)
+ {
+ AddNode(node);
+ }
+ }
+
+ public ITweenChain SetOnBegin(System.Action onBegin)
+ {
+ _onBegin = onBegin;
+ return this;
+ }
+ public ITweenChain SetOnComplete(System.Action onComplete)
+ {
+ _onComplete = onComplete;
+ return this;
+ }
+ public ITweenChain SetDispose(System.Action onDispose)
+ {
+ _onDispose = onDispose;
+ return this;
+ }
+
+ void ITweenNode.OnUpdate(float deltaTime)
+ {
+ if (Status == ETweenStatus.Idle)
+ {
+ Status = ETweenStatus.Runing;
+ _onBegin?.Invoke();
+ }
+
+ if (Status == ETweenStatus.Runing)
+ {
+ bool isComplete = UpdateChainNodes(deltaTime);
+ if (isComplete)
+ {
+ Status = ETweenStatus.Completed;
+ _onComplete?.Invoke();
+ }
+ }
+ }
+ void ITweenNode.OnDispose()
+ {
+ foreach (var node in _nodes)
+ {
+ node.OnDispose();
+ }
+ _nodes.Clear();
+ _onDispose?.Invoke();
+ }
+ void ITweenNode.Abort()
+ {
+ foreach (var node in _nodes)
+ {
+ node.Abort();
+ }
+ Status = ETweenStatus.Abort;
+ }
+
+ ITweenChain ITweenChain.Append(ITweenNode node)
+ {
+ AddNode(node);
+ return this;
+ }
+
+ protected abstract bool UpdateChainNodes(float deltaTime);
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs.meta
new file mode 100644
index 0000000..99f8511
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ChainNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a7a4c117e42263644943d618569e16fd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs
new file mode 100644
index 0000000..94facfa
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs
@@ -0,0 +1,47 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 执行节点
+ ///
+ public sealed class ExecuteNode : ITweenNode
+ {
+ private System.Action _execute = null;
+
+ ///
+ /// 节点状态
+ ///
+ public ETweenStatus Status { private set; get; } = ETweenStatus.Idle;
+
+
+ ///
+ /// 设置执行方法
+ ///
+ public ExecuteNode SetExecute(System.Action execute)
+ {
+ _execute = execute;
+ return this;
+ }
+
+ void ITweenNode.OnUpdate(float deltaTime)
+ {
+ if (Status == ETweenStatus.Idle)
+ {
+ Status = ETweenStatus.Runing;
+ }
+
+ if (Status == ETweenStatus.Runing)
+ {
+ _execute?.Invoke();
+ Status = ETweenStatus.Completed;
+ }
+ }
+ void ITweenNode.OnDispose()
+ {
+ }
+ void ITweenNode.Abort()
+ {
+ Status = ETweenStatus.Abort;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs.meta
new file mode 100644
index 0000000..174da4c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ExecuteNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0e71daf2e3846f438e94207f355c106
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs
new file mode 100644
index 0000000..86a5435
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs
@@ -0,0 +1,25 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 并行执行的复合节点
+ /// 说明:节点列表并行执行,所有子节点同时执行,所有节点都结束时复合节点结束。
+ ///
+ public sealed class ParallelNode : ChainNode
+ {
+ protected override bool UpdateChainNodes(float deltaTime)
+ {
+ bool isComplete = true;
+ for (int index = 0; index < _nodes.Count; index++)
+ {
+ var node = _nodes[index];
+ node.OnUpdate(deltaTime);
+ if (node.Status == ETweenStatus.Idle || node.Status == ETweenStatus.Runing)
+ {
+ isComplete = false;
+ }
+ }
+ return isComplete;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs.meta
new file mode 100644
index 0000000..a35d1e1
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ParallelNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 53828e1dbd1e0ef4fa95b13237dbd166
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs
new file mode 100644
index 0000000..a94234a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs
@@ -0,0 +1,36 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 随机执行的复合节点
+ /// 说明:节点列表随机执行,在随机节点结束后复合节点结束。
+ ///
+ public sealed class SelectorNode : ChainNode
+ {
+ private ITweenNode _selectNode = null;
+
+ protected override bool UpdateChainNodes(float deltaTime)
+ {
+ if (_selectNode == null)
+ {
+ if (_nodes.Count > 0)
+ {
+ int index = UnityEngine.Random.Range(0, _nodes.Count);
+ _selectNode = _nodes[index];
+ }
+ }
+
+ if (_selectNode != null)
+ {
+ _selectNode.OnUpdate(deltaTime);
+ if (_selectNode.Status == ETweenStatus.Idle || _selectNode.Status == ETweenStatus.Runing)
+ return false;
+ else
+ return true;
+ }
+
+ // 如果没有执行节点直接返回完成
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs.meta
new file mode 100644
index 0000000..e548dcc
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SelectorNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 35ae6d86b02c78d4baa5c5b45112304e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs
new file mode 100644
index 0000000..f6969e8
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs
@@ -0,0 +1,26 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 顺序执行的复合节点
+ /// 说明:节点列表依次执行,每个子节点结束之后便执行下一个节点,所有节点都结束时复合节点结束。
+ ///
+ public sealed class SequenceNode : ChainNode
+ {
+ protected override bool UpdateChainNodes(float deltaTime)
+ {
+ bool isComplete = true;
+ for (int index = 0; index < _nodes.Count; index++)
+ {
+ var node = _nodes[index];
+ node.OnUpdate(deltaTime);
+ if (node.Status == ETweenStatus.Idle || node.Status == ETweenStatus.Runing)
+ {
+ isComplete = false;
+ break;
+ }
+ }
+ return isComplete;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs.meta
new file mode 100644
index 0000000..54eb437
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/SequenceNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: de086a12be6a3f04ea3e6edac31cd23c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs
new file mode 100644
index 0000000..3901c38
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs
@@ -0,0 +1,57 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 计时器节点
+ ///
+ public sealed class TimerNode : ITweenNode
+ {
+ private readonly UniTimer _timer;
+ private System.Action _trigger;
+
+ ///
+ /// 节点状态
+ ///
+ public ETweenStatus Status { private set; get; } = ETweenStatus.Idle;
+
+
+ public TimerNode(UniTimer timer)
+ {
+ _timer = timer;
+ }
+
+ ///
+ /// 设置触发方法
+ ///
+ public TimerNode SetTrigger(System.Action trigger)
+ {
+ _trigger = trigger;
+ return this;
+ }
+
+ void ITweenNode.OnUpdate(float deltaTime)
+ {
+ if (Status == ETweenStatus.Idle)
+ {
+ Status = ETweenStatus.Runing;
+ }
+
+ if (Status == ETweenStatus.Runing)
+ {
+ if (_timer.Update(deltaTime))
+ _trigger?.Invoke();
+
+ bool result = _timer.IsOver;
+ if (result)
+ Status = ETweenStatus.Completed;
+ }
+ }
+ void ITweenNode.OnDispose()
+ {
+ }
+ void ITweenNode.Abort()
+ {
+ Status = ETweenStatus.Abort;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs.meta
new file mode 100644
index 0000000..1aa5584
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/TimerNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 57190cc55d5fba24ca7f6e22dcbf38fb
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs
new file mode 100644
index 0000000..ffc2824
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs
@@ -0,0 +1,55 @@
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 条件等待节点
+ ///
+ public sealed class UntilNode : ITweenNode
+ {
+ private System.Func _condition = null;
+
+ ///
+ /// 节点状态
+ ///
+ public ETweenStatus Status { private set; get; } = ETweenStatus.Idle;
+
+ ///
+ /// 设置条件方法
+ ///
+ public UntilNode SetCondition(System.Func condition)
+ {
+ _condition = condition;
+ return this;
+ }
+
+ void ITweenNode.OnUpdate(float deltaTime)
+ {
+ if (Status == ETweenStatus.Idle)
+ {
+ Status = ETweenStatus.Runing;
+ }
+
+ if (Status == ETweenStatus.Runing)
+ {
+ if (_condition == null)
+ {
+ UniLogger.Warning($"The {nameof(UntilNode)} condition is null. Set completed !");
+ Status = ETweenStatus.Completed;
+ }
+ else
+ {
+ bool result = _condition.Invoke();
+ if (result)
+ Status = ETweenStatus.Completed;
+ }
+ }
+ }
+ void ITweenNode.OnDispose()
+ {
+ }
+ void ITweenNode.Abort()
+ {
+ Status = ETweenStatus.Abort;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs.meta
new file mode 100644
index 0000000..fe0da14
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/UntilNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 010500ebd041e5b4d89e581f33e4b0d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs
new file mode 100644
index 0000000..ff0ac66
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs
@@ -0,0 +1,363 @@
+using UnityEngine;
+
+namespace UniFramework.Tween
+{
+ public abstract class ValueNode : ITweenNode where ValueType : struct
+ {
+ ///
+ /// 补间委托
+ ///
+ /// 运行时长
+ /// 起始数值
+ /// 变化差值
+ /// 总时长
+ public delegate float TweenEaseDelegate(float t, float b, float c, float d);
+
+ ///
+ /// 插值委托
+ ///
+ /// 起始数值
+ /// 目标数值
+ /// 进度值
+ public delegate ValueType TweenLerpDelegate(ValueType from, ValueType to, float progress);
+
+
+ private readonly float _duration;
+ private ValueType _valueFrom;
+ private ValueType _valueTo;
+
+ private ETweenLoop _tweenLoop = ETweenLoop.None;
+ private int _loopCount = -1;
+ private long _loopCounter = 0;
+ private float _timeReverse = 1f;
+ private float _runningTime = 0;
+
+ private System.Action _onUpdate = null;
+ private System.Action _onBegin = null;
+ private System.Action _onComplete = null;
+ private System.Action _onDispose = null;
+ protected TweenEaseDelegate _easeFun = null;
+ protected TweenLerpDelegate _lerpFun = null;
+
+ ///
+ /// 补间结果
+ ///
+ public ValueType Result { get; private set; }
+
+ ///
+ /// 节点状态
+ ///
+ public ETweenStatus Status { private set; get; } = ETweenStatus.Idle;
+
+
+ public ValueNode(float duration, ValueType from, ValueType to)
+ {
+ _duration = duration;
+ _valueFrom = from;
+ _valueTo = to;
+ _easeFun = TweenEase.Linear.Default;
+ }
+ void ITweenNode.OnDispose()
+ {
+ _onDispose?.Invoke();
+ }
+ void ITweenNode.OnUpdate(float deltaTime)
+ {
+ if(Status == ETweenStatus.Idle)
+ {
+ Status = ETweenStatus.Runing;
+ _onBegin?.Invoke();
+ }
+
+ if(Status == ETweenStatus.Runing)
+ {
+ _runningTime += (deltaTime * _timeReverse);
+ if (_duration > 0 && _runningTime > 0 && _runningTime < _duration)
+ {
+ float progress = _easeFun.Invoke(_runningTime, 0, 1, _duration);
+ Result = GetResultValue(_valueFrom, _valueTo, progress);
+ _onUpdate?.Invoke(Result);
+ }
+ else
+ {
+ if (_tweenLoop == ETweenLoop.None)
+ {
+ Result = _valueTo;
+ _onUpdate?.Invoke(Result);
+
+ Status = ETweenStatus.Completed;
+ _onComplete?.Invoke();
+ }
+ else if (_tweenLoop == ETweenLoop.Restart)
+ {
+ _runningTime = 0;
+ Result = _valueTo;
+ _onUpdate?.Invoke(Result);
+
+ _loopCounter++;
+ if (_loopCount > 0 && _loopCounter >= _loopCount)
+ {
+ Status = ETweenStatus.Completed;
+ _onComplete?.Invoke();
+ }
+ }
+ else if (_tweenLoop == ETweenLoop.PingPong)
+ {
+ _timeReverse *= -1;
+ if (_timeReverse > 0)
+ {
+ _runningTime = 0;
+ Result = _valueFrom;
+ _onUpdate?.Invoke(Result);
+
+ // 注意:完整PingPong算一次
+ _loopCounter++;
+ if (_loopCount > 0 && _loopCounter >= _loopCount)
+ {
+ Status = ETweenStatus.Completed;
+ _onComplete?.Invoke();
+ }
+ }
+ else
+ {
+ _runningTime = _duration;
+ Result = _valueTo;
+ _onUpdate?.Invoke(Result);
+ }
+ }
+ else
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+ }
+ }
+ void ITweenNode.Abort()
+ {
+ Status = ETweenStatus.Abort;
+ }
+
+ public ValueNode SetRunningTime(float runingTime)
+ {
+ _runningTime = runingTime;
+ return this;
+ }
+ public ValueNode SetValueFrom(ValueType value)
+ {
+ _valueFrom = value;
+ return this;
+ }
+ public ValueNode SetValueTo(ValueType value)
+ {
+ _valueTo = value;
+ return this;
+ }
+ public ValueNode SetLoop(ETweenLoop tweenLoop, int loopCount = -1)
+ {
+ _tweenLoop = tweenLoop;
+ _loopCount = loopCount;
+ return this;
+ }
+ public ValueNode SetEase(AnimationCurve easeCurve)
+ {
+ if (easeCurve == null)
+ {
+ UniLogger.Error($"{nameof(AnimationCurve)} param is null.");
+ return this;
+ }
+
+ // 获取动画总时长
+ float length = 0f;
+ for (int i = 0; i < easeCurve.keys.Length; i++)
+ {
+ var key = easeCurve.keys[i];
+ if (key.time > length)
+ length = key.time;
+ }
+
+ _easeFun = delegate (float t, float b, float c, float d)
+ {
+ float time = length * (t / d);
+ return easeCurve.Evaluate(time) * c + b;
+ };
+
+ return this;
+ }
+ public ValueNode SetEase(TweenEaseDelegate easeFun)
+ {
+ if (easeFun == null)
+ {
+ UniLogger.Error($"{nameof(TweenEaseDelegate)} param is null.");
+ return this;
+ }
+
+ _easeFun = easeFun;
+ return this;
+ }
+ public ValueNode SetLerp(TweenLerpDelegate lerpFun)
+ {
+ if (lerpFun == null)
+ {
+ UniLogger.Error($"{nameof(TweenLerpDelegate)} param is null.");
+ return this;
+ }
+
+ _lerpFun = lerpFun;
+ return this;
+ }
+ public ValueNode SetOnUpdate(System.Action onUpdate)
+ {
+ _onUpdate = onUpdate;
+ return this;
+ }
+ public ValueNode SetOnBegin(System.Action onBegin)
+ {
+ _onBegin = onBegin;
+ return this;
+ }
+ public ValueNode SetOnComplete(System.Action onComplete)
+ {
+ _onComplete = onComplete;
+ return this;
+ }
+ public ValueNode SetOnDispose(System.Action onDispose)
+ {
+ _onDispose = onDispose;
+ return this;
+ }
+
+ protected abstract ValueType GetResultValue(ValueType from, ValueType to, float progress);
+ }
+
+ ///
+ /// Float Tween
+ ///
+ public sealed class FloatTween : ValueNode
+ {
+ public static FloatTween Allocate(float duration, float from, float to)
+ {
+ return new FloatTween(duration, from, to);
+ }
+
+ public FloatTween(float duration, float from, float to) : base(duration, from, to)
+ {
+ }
+ protected override float GetResultValue(float from, float to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Mathf.LerpUnclamped(from, to, progress);
+ }
+ }
+
+ ///
+ /// Vector2 Tween
+ ///
+ public sealed class Vector2Tween : ValueNode
+ {
+ public static Vector2Tween Allocate(float duration, Vector2 from, Vector2 to)
+ {
+ return new Vector2Tween(duration, from, to);
+ }
+
+ public Vector2Tween(float duration, Vector2 from, Vector2 to) : base(duration, from, to)
+ {
+ }
+ protected override Vector2 GetResultValue(Vector2 from, Vector2 to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Vector2.LerpUnclamped(from, to, progress);
+ }
+ }
+
+ ///
+ /// Vector3 Tween
+ ///
+ public sealed class Vector3Tween : ValueNode
+ {
+ public static Vector3Tween Allocate(float duration, Vector3 from, Vector3 to)
+ {
+ return new Vector3Tween(duration, from, to);
+ }
+
+ public Vector3Tween(float duration, Vector3 from, Vector3 to) : base(duration, from, to)
+ {
+ }
+ protected override Vector3 GetResultValue(Vector3 from, Vector3 to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Vector3.LerpUnclamped(from, to, progress);
+ }
+ }
+
+ ///
+ /// Vector4 Tween
+ ///
+ public sealed class Vector4Tween : ValueNode
+ {
+ public static Vector4Tween Allocate(float duration, Vector4 from, Vector4 to)
+ {
+ return new Vector4Tween(duration, from, to);
+ }
+
+ public Vector4Tween(float duration, Vector4 from, Vector4 to) : base(duration, from, to)
+ {
+ }
+ protected override Vector4 GetResultValue(Vector4 from, Vector4 to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Vector4.LerpUnclamped(from, to, progress);
+ }
+ }
+
+ ///
+ /// Color Tween
+ ///
+ public sealed class ColorTween : ValueNode
+ {
+ public static ColorTween Allocate(float duration, Color from, Color to)
+ {
+ return new ColorTween(duration, from, to);
+ }
+
+ public ColorTween(float duration, Color from, Color to) : base(duration, from, to)
+ {
+ }
+ protected override Color GetResultValue(Color from, Color to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Color.LerpUnclamped(from, to, progress);
+ }
+ }
+
+ ///
+ /// Quaternion Tween
+ ///
+ public sealed class QuaternionTween : ValueNode
+ {
+ public static QuaternionTween Allocate(float duration, Quaternion from, Quaternion to)
+ {
+ return new QuaternionTween(duration, from, to);
+ }
+
+ public QuaternionTween(float duration, Quaternion from, Quaternion to) : base(duration, from, to)
+ {
+ }
+ protected override Quaternion GetResultValue(Quaternion from, Quaternion to, float progress)
+ {
+ if (_lerpFun != null)
+ return _lerpFun.Invoke(from, to, progress);
+ else
+ return Quaternion.LerpUnclamped(from, to, progress);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs.meta
new file mode 100644
index 0000000..e5d5b17
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/TweenNode/ValueNode.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b6764a4a4b1300a4886350df53844828
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniUtility.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef
similarity index 90%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniUtility.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef
index 80c7396..025e4ae 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniUtility.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef
@@ -1,5 +1,5 @@
{
- "name": "UniUtility",
+ "name": "UniFramework.Tween",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef.meta
new file mode 100644
index 0000000..80db938
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniFramework.Tween.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 44de5b8c35e72e2488d54682724e6105
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs
new file mode 100644
index 0000000..bad20e3
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics;
+
+namespace UniFramework.Tween
+{
+ internal static class UniLogger
+ {
+ [Conditional("DEBUG")]
+ public static void Log(string info)
+ {
+ UnityEngine.Debug.Log(info);
+ }
+ public static void Warning(string info)
+ {
+ UnityEngine.Debug.LogWarning(info);
+ }
+ public static void Error(string info)
+ {
+ UnityEngine.Debug.LogError(info);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs.meta
new file mode 100644
index 0000000..b066e9e
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniLogger.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: dbad3cd04905bab4fb6391f5184bcfa0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs
new file mode 100644
index 0000000..763cef1
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs
@@ -0,0 +1,199 @@
+
+namespace UniFramework.Tween
+{
+ public sealed class UniTimer
+ {
+ ///
+ /// 延迟后,触发一次
+ ///
+ public static UniTimer CreateOnceTimer(float delay)
+ {
+ return new UniTimer(delay, -1, -1, 1);
+ }
+
+ ///
+ /// 延迟后,永久性的间隔触发
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ public static UniTimer CreatePepeatTimer(float delay, float interval)
+ {
+ return new UniTimer(delay, interval, -1, -1);
+ }
+
+ ///
+ /// 延迟后,在一段时间内间隔触发
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 触发周期
+ public static UniTimer CreatePepeatTimer(float delay, float interval, float duration)
+ {
+ return new UniTimer(delay, interval, duration, -1);
+ }
+
+ ///
+ /// 延迟后,间隔触发一定次数
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 最大触发次数
+ public static UniTimer CreatePepeatTimer(float delay, float interval, long maxTriggerCount)
+ {
+ return new UniTimer(delay, interval, -1, maxTriggerCount);
+ }
+
+ ///
+ /// 延迟后,在一段时间内触发
+ ///
+ /// 延迟时间
+ /// 触发周期
+ public static UniTimer CreateDurationTimer(float delay, float duration)
+ {
+ return new UniTimer(delay, -1, duration, -1);
+ }
+
+ ///
+ /// 延迟后,永久触发
+ ///
+ public static UniTimer CreateForeverTimer(float delay)
+ {
+ return new UniTimer(delay, -1, -1, -1);
+ }
+
+
+ private readonly float _intervalTime;
+ private readonly float _durationTime;
+ private readonly long _maxTriggerCount;
+
+ // 需要重置的变量
+ private float _delayTimer = 0;
+ private float _durationTimer = 0;
+ private float _intervalTimer = 0;
+ private long _triggerCount = 0;
+
+ ///
+ /// 延迟时间
+ ///
+ public float DelayTime { private set; get; }
+
+ ///
+ /// 是否已经结束
+ ///
+ public bool IsOver { private set; get; }
+
+ ///
+ /// 是否已经暂停
+ ///
+ public bool IsPause { private set; get; }
+
+ ///
+ /// 延迟剩余时间
+ ///
+ public float Remaining
+ {
+ get
+ {
+ if (IsOver)
+ return 0f;
+ else
+ return System.Math.Max(0f, DelayTime - _delayTimer);
+ }
+ }
+
+ ///
+ /// 计时器
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 运行时间
+ /// 最大触发次数
+ public UniTimer(float delay, float interval, float duration, long maxTriggerCount)
+ {
+ DelayTime = delay;
+ _intervalTime = interval;
+ _durationTime = duration;
+ _maxTriggerCount = maxTriggerCount;
+ }
+
+ ///
+ /// 暂停计时器
+ ///
+ public void Pause()
+ {
+ IsPause = true;
+ }
+
+ ///
+ /// 恢复计时器
+ ///
+ public void Resume()
+ {
+ IsPause = false;
+ }
+
+ ///
+ /// 结束计时器
+ ///
+ public void Kill()
+ {
+ IsOver = true;
+ }
+
+ ///
+ /// 重置计时器
+ ///
+ public void Reset()
+ {
+ _delayTimer = 0;
+ _durationTimer = 0;
+ _intervalTimer = 0;
+ _triggerCount = 0;
+ IsOver = false;
+ IsPause = false;
+ }
+
+ ///
+ /// 更新计时器
+ ///
+ public bool Update(float deltaTime)
+ {
+ if (IsOver || IsPause)
+ return false;
+
+ _delayTimer += deltaTime;
+ if (_delayTimer < DelayTime)
+ return false;
+
+ if(_intervalTime > 0)
+ _intervalTimer += deltaTime;
+ if (_durationTime > 0)
+ _durationTimer += deltaTime;
+
+ // 检测间隔执行
+ if (_intervalTime > 0)
+ {
+ if (_intervalTimer < _intervalTime)
+ return false;
+ _intervalTimer = 0;
+ }
+
+ // 检测结束条件
+ if (_durationTime > 0)
+ {
+ if (_durationTimer >= _durationTime)
+ Kill();
+ }
+
+ // 检测结束条件
+ if (_maxTriggerCount > 0)
+ {
+ _triggerCount++;
+ if (_triggerCount >= _maxTriggerCount)
+ Kill();
+ }
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs.meta
new file mode 100644
index 0000000..73e498b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTimer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 60ae01c18fb54794c92589be693490e4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs
new file mode 100644
index 0000000..78e280a
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs
@@ -0,0 +1,344 @@
+using System;
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace UniFramework.Tween
+{
+ ///
+ /// 补间动画系统
+ ///
+ public static class UniTween
+ {
+ private static bool _isInitialize = false;
+ private static GameObject _driver = null;
+ private static readonly List _tweens = new List(1000);
+ private static readonly List _newer = new List(1000);
+ private static readonly List _remover = new List(1000);
+
+ ///
+ /// 是否忽略时间戳缩放
+ ///
+ public static bool IgnoreTimeScale { set; get; } = false;
+
+ ///
+ /// 所有补间动画的播放速度
+ ///
+ public static float PlaySpeed { set; get; } = 1f;
+
+
+ ///
+ /// 初始化补间动画系统
+ ///
+ public static void Initalize()
+ {
+ if (_isInitialize)
+ throw new Exception($"{nameof(UniTween)} is initialized !");
+
+ if(_isInitialize == false)
+ {
+ // 创建驱动器
+ _isInitialize = true;
+ _driver = new GameObject($"[{nameof(UniTween)}]");
+ _driver.AddComponent();
+ UnityEngine.Object.DontDestroyOnLoad(_driver);
+ UniLogger.Log($"{nameof(UniTween)} initalize !");
+ }
+ }
+
+ ///
+ /// 销毁补间动画系统
+ ///
+ public static void Destroy()
+ {
+ if (_isInitialize)
+ {
+ foreach (var tween in _tweens)
+ {
+ tween.Dispose();
+ }
+ foreach (var tween in _newer)
+ {
+ tween.Dispose();
+ }
+ foreach (var tween in _remover)
+ {
+ tween.Dispose();
+ }
+
+ _tweens.Clear();
+ _newer.Clear();
+ _remover.Clear();
+
+ _isInitialize = false;
+ if (_driver != null)
+ GameObject.Destroy(_driver);
+ UniLogger.Log($"{nameof(UniTween)} destroy all !");
+ }
+ }
+
+ ///
+ /// 更新补间动画系统
+ ///
+ internal static void Update()
+ {
+ if (_isInitialize)
+ {
+ // 添加新的补间动画
+ if (_newer.Count > 0)
+ {
+ _tweens.AddRange(_newer);
+ _newer.Clear();
+ }
+
+ // 更新所有补间动画
+ float deltaTime = IgnoreTimeScale ? UnityEngine.Time.unscaledDeltaTime : UnityEngine.Time.deltaTime;
+ deltaTime *= PlaySpeed;
+ for (int i = 0; i < _tweens.Count; i++)
+ {
+ var handle = _tweens[i];
+ if (handle.IsCanRemove())
+ _remover.Add(handle);
+ else
+ handle.Update(deltaTime);
+ }
+
+ // 移除完成的补间动画
+ for (int i = 0; i < _remover.Count; i++)
+ {
+ var handle = _remover[i];
+ handle.Dispose();
+ _tweens.Remove(handle);
+ }
+ _remover.Clear();
+ }
+ }
+
+
+ ///
+ /// 播放一个补间动画
+ ///
+ /// 补间根节点
+ /// 游戏对象
+ public static TweenHandle Play(ITweenNode tweenRoot, UnityEngine.Object unityObject = null)
+ {
+ DebugCheckInitialize();
+
+ if (tweenRoot == null)
+ throw new System.ArgumentNullException();
+
+ TweenHandle handle = new TweenHandle(tweenRoot, unityObject);
+ _newer.Add(handle);
+ return handle;
+ }
+
+ ///
+ /// 播放一个补间动画
+ ///
+ /// 补间链节点
+ /// 游戏对象
+ public static TweenHandle Play(ITweenChain tweenChain, UnityEngine.Object unityObject = null)
+ {
+ ITweenNode tweenRoot = tweenChain as ITweenNode;
+ if (tweenRoot == null)
+ throw new System.InvalidCastException();
+
+ return Play(tweenRoot, unityObject);
+ }
+
+ ///
+ /// 播放一个补间动画
+ ///
+ /// 补间链节点
+ /// 游戏对象
+ public static TweenHandle Play(ChainNode chainNode, UnityEngine.Object unityObject = null)
+ {
+ ITweenNode tweenRoot = chainNode as ITweenNode;
+ if (tweenRoot == null)
+ throw new System.InvalidCastException();
+
+ return Play(tweenRoot, unityObject);
+ }
+
+ ///
+ /// 中途关闭补间动画
+ ///
+ /// 关闭的补间动画句柄
+ public static void Abort(TweenHandle tweenHandle)
+ {
+ DebugCheckInitialize();
+
+ if (tweenHandle != null)
+ tweenHandle.Abort();
+ }
+
+ ///
+ /// 中途关闭补间动画
+ ///
+ /// 关闭该游戏对象下的所有补间动画
+ public static void Abort(UnityEngine.Object unityObject)
+ {
+ DebugCheckInitialize();
+
+ int instanceID = unityObject.GetInstanceID();
+ for (int i = 0; i < _tweens.Count; i++)
+ {
+ var handle = _tweens[i];
+ if (handle.InstanceID == instanceID)
+ {
+ handle.Abort();
+ }
+ }
+ for (int i = 0; i < _newer.Count; i++)
+ {
+ var handle = _newer[i];
+ if (handle.InstanceID == instanceID)
+ {
+ handle.Abort();
+ }
+ }
+ }
+
+
+ #region Tween Allocate
+ ///
+ /// 执行节点
+ ///
+ /// 执行方法
+ public static ExecuteNode AllocateExecute(System.Action execute)
+ {
+ ExecuteNode node = new ExecuteNode();
+ node.SetExecute(execute);
+ return node;
+ }
+
+ ///
+ /// 条件等待节点
+ ///
+ /// 条件方法
+ public static UntilNode AllocateUntil(System.Func condition)
+ {
+ UntilNode node = new UntilNode();
+ node.SetCondition(condition);
+ return node;
+ }
+
+
+ ///
+ /// 并行执行的复合节点
+ ///
+ /// 成员节点列表
+ public static ParallelNode AllocateParallel(params ITweenNode[] nodes)
+ {
+ ParallelNode node = new ParallelNode();
+ node.AddNode(nodes);
+ return node;
+ }
+
+ ///
+ /// 顺序执行的复合节点
+ ///
+ /// 成员节点列表
+ public static SequenceNode AllocateSequence(params ITweenNode[] nodes)
+ {
+ SequenceNode node = new SequenceNode();
+ node.AddNode(nodes);
+ return node;
+ }
+
+ ///
+ /// 随机执行的复合节点
+ ///
+ /// 成员节点列表
+ public static SelectorNode AllocateSelector(params ITweenNode[] nodes)
+ {
+ SelectorNode node = new SelectorNode();
+ node.AddNode(nodes);
+ return node;
+ }
+
+
+ ///
+ /// 延迟计时节点
+ ///
+ /// 延迟时间
+ /// 触发事件
+ public static TimerNode AllocateDelay(float delay, System.Action trigger = null)
+ {
+ UniTimer timer = UniTimer.CreateOnceTimer(delay);
+ TimerNode node = new TimerNode(timer);
+ node.SetTrigger(trigger);
+ return node;
+ }
+
+ ///
+ /// 重复计时节点
+ /// 注意:该节点为无限时长
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 触发事件
+ public static TimerNode AllocateRepeat(float delay, float interval, System.Action trigger = null)
+ {
+ UniTimer timer = UniTimer.CreatePepeatTimer(delay, interval);
+ TimerNode node = new TimerNode(timer);
+ node.SetTrigger(trigger);
+ return node;
+ }
+
+ ///
+ /// 重复计时节点
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 持续时间
+ /// 触发事件
+ public static TimerNode AllocateRepeat(float delay, float interval, float duration, System.Action trigger = null)
+ {
+ UniTimer timer = UniTimer.CreatePepeatTimer(delay, interval, duration);
+ TimerNode node = new TimerNode(timer);
+ node.SetTrigger(trigger);
+ return node;
+ }
+
+ ///
+ /// 重复计时节点
+ ///
+ /// 延迟时间
+ /// 间隔时间
+ /// 最大触发次数
+ /// 触发事件
+ public static TimerNode AllocateRepeat(float delay, float interval, long maxRepeatCount, System.Action trigger = null)
+ {
+ UniTimer timer = UniTimer.CreatePepeatTimer(delay, interval, maxRepeatCount);
+ TimerNode node = new TimerNode(timer);
+ node.SetTrigger(trigger);
+ return node;
+ }
+
+ ///
+ /// 持续计时节点
+ ///
+ /// 延迟时间
+ /// 持续时间
+ /// 触发事件
+ public static TimerNode AllocateDuration(float delay, float duration, System.Action trigger = null)
+ {
+ UniTimer timer = UniTimer.CreateDurationTimer(delay, duration);
+ TimerNode node = new TimerNode(timer);
+ node.SetTrigger(trigger);
+ return node;
+ }
+ #endregion
+
+ #region 调试方法
+ [Conditional("DEBUG")]
+ private static void DebugCheckInitialize()
+ {
+ if (_isInitialize == false)
+ throw new Exception($"{nameof(UniTween)} not initialize !");
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs.meta
new file mode 100644
index 0000000..d39a552
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTween.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4942da830749fca4e9cb7bbdf1bda924
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs
new file mode 100644
index 0000000..e49ecc2
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+
+namespace UniFramework.Tween
+{
+ internal class UniTweenDriver : MonoBehaviour
+ {
+ void Update()
+ {
+ UniTween.Update();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs.meta
new file mode 100644
index 0000000..df391ff
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniTween/Runtime/UniTweenDriver.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d2cbc1a9339629f47ae487886e5bae0b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility.meta
index b141726..e665295 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 039eb69f46ea8bf4c873ab10b816da92
+guid: 97c99cc0a7d8c8f42a1b15c81f6e71e0
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs
new file mode 100644
index 0000000..b8e100f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace UniFramework.Utility
+{
+ internal struct BitMask32
+ {
+ private int _mask;
+
+ public static implicit operator int(BitMask32 mask) { return mask._mask; }
+ public static implicit operator BitMask32(int mask) { return new BitMask32(mask); }
+
+ public BitMask32(int mask)
+ {
+ _mask = mask;
+ }
+
+ ///
+ /// 打开位
+ ///
+ public void Open(int bit)
+ {
+ if (bit < 0 || bit > 31)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask |= 1 << bit;
+ }
+
+ ///
+ /// 关闭位
+ ///
+ public void Close(int bit)
+ {
+ if (bit < 0 || bit > 31)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask &= ~(1 << bit);
+ }
+
+ ///
+ /// 位取反
+ ///
+ public void Reverse(int bit)
+ {
+ if (bit < 0 || bit > 31)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask ^= 1 << bit;
+ }
+
+ ///
+ /// 所有位取反
+ ///
+ public void Inverse()
+ {
+ _mask = ~_mask;
+ }
+
+ ///
+ /// 比对位值
+ ///
+ public bool Test(int bit)
+ {
+ if (bit < 0 || bit > 31)
+ throw new ArgumentOutOfRangeException();
+ else
+ return (_mask & (1 << bit)) != 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs.meta
new file mode 100644
index 0000000..18d1885
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask32.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 60c7594328ef976408edadfdf2b9aa3d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs
new file mode 100644
index 0000000..c61432c
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace UniFramework.Utility
+{
+ internal struct BitMask64
+ {
+ private long _mask;
+
+ public static implicit operator long(BitMask64 mask) { return mask._mask; }
+ public static implicit operator BitMask64(long mask) { return new BitMask64(mask); }
+
+ public BitMask64(long mask)
+ {
+ _mask = mask;
+ }
+
+ ///
+ /// 打开位
+ ///
+ public void Open(int bit)
+ {
+ if (bit < 0 || bit > 63)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask |= 1L << bit;
+ }
+
+ ///
+ /// 关闭位
+ ///
+ public void Close(int bit)
+ {
+ if (bit < 0 || bit > 63)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask &= ~(1L << bit);
+ }
+
+ ///
+ /// 位取反
+ ///
+ public void Reverse(int bit)
+ {
+ if (bit < 0 || bit > 63)
+ throw new ArgumentOutOfRangeException();
+ else
+ _mask ^= 1L << bit;
+ }
+
+ ///
+ /// 所有位取反
+ ///
+ public void Inverse()
+ {
+ _mask = ~_mask;
+ }
+
+ ///
+ /// 比对位值
+ ///
+ public bool Test(int bit)
+ {
+ if (bit < 0 || bit > 63)
+ throw new ArgumentOutOfRangeException();
+ else
+ return (_mask & (1L << bit)) != 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs.meta
new file mode 100644
index 0000000..5d62c53
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/BitMask64.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6b03684bc5163694ab3983243512b4cc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs
new file mode 100644
index 0000000..5fdf413
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace UniFramework.Utility
+{
+ public static class StringConvert
+ {
+ ///
+ /// 正则表达式
+ ///
+ private static readonly Regex REGEX = new Regex(@"\{[-+]?[0-9]+\.?[0-9]*\}", RegexOptions.IgnoreCase);
+
+ ///
+ /// 字符串转换为BOOL
+ ///
+ public static bool StringToBool(string str)
+ {
+ int value = (int)Convert.ChangeType(str, typeof(int));
+ return value > 0;
+ }
+
+ ///
+ /// 字符串转换为数值
+ ///
+ public static T StringToValue(string str)
+ {
+ return (T)Convert.ChangeType(str, typeof(T));
+ }
+
+ ///
+ /// 字符串转换为数值列表
+ ///
+ /// 分隔符
+ public static List StringToValueList(string str, char separator)
+ {
+ List result = new List();
+ if (!String.IsNullOrEmpty(str))
+ {
+ string[] splits = str.Split(separator);
+ foreach (string split in splits)
+ {
+ if (!String.IsNullOrEmpty(split))
+ {
+ result.Add((T)Convert.ChangeType(split, typeof(T)));
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// 字符串转为字符串列表
+ ///
+ public static List StringToStringList(string str, char separator)
+ {
+ List result = new List();
+ if (!String.IsNullOrEmpty(str))
+ {
+ string[] splits = str.Split(separator);
+ foreach (string split in splits)
+ {
+ if (!String.IsNullOrEmpty(split))
+ {
+ result.Add(split);
+ }
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// 转换为枚举
+ /// 枚举索引转换为枚举类型
+ ///
+ public static T IndexToEnum(string index) where T : IConvertible
+ {
+ int enumIndex = (int)Convert.ChangeType(index, typeof(int));
+ return IndexToEnum(enumIndex);
+ }
+
+ ///
+ /// 转换为枚举
+ /// 枚举索引转换为枚举类型
+ ///
+ public static T IndexToEnum(int index) where T : IConvertible
+ {
+ if (Enum.IsDefined(typeof(T), index) == false)
+ {
+ throw new ArgumentException($"Enum {typeof(T)} is not defined index {index}");
+ }
+ return (T)Enum.ToObject(typeof(T), index);
+ }
+
+ ///
+ /// 转换为枚举
+ /// 枚举名称转换为枚举类型
+ ///
+ public static T NameToEnum(string name)
+ {
+ if (Enum.IsDefined(typeof(T), name) == false)
+ {
+ throw new ArgumentException($"Enum {typeof(T)} is not defined name {name}");
+ }
+ return (T)Enum.Parse(typeof(T), name);
+ }
+
+ ///
+ /// 字符串转换为参数列表
+ ///
+ public static List StringToParams(string str)
+ {
+ List result = new List();
+ MatchCollection matches = REGEX.Matches(str);
+ for (int i = 0; i < matches.Count; i++)
+ {
+ string value = matches[i].Value.Trim('{', '}');
+ result.Add(StringToValue(value));
+ }
+ return result;
+ }
+ }
+}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs.meta
new file mode 100644
index 0000000..17ff13f
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringConvert.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 889d01b55e38f7c49bbfb8908d9bf17f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs
new file mode 100644
index 0000000..48bff68
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Text;
+
+namespace UniFramework.Utility
+{
+ public static class StringFormat
+ {
+ [ThreadStatic]
+ private static StringBuilder _cacheBuilder = new StringBuilder(1024);
+
+ public static string Format(string format, object arg0)
+ {
+ if (string.IsNullOrEmpty(format))
+ throw new ArgumentNullException();
+
+ _cacheBuilder.Length = 0;
+ _cacheBuilder.AppendFormat(format, arg0);
+ return _cacheBuilder.ToString();
+ }
+ public static string Format(string format, object arg0, object arg1)
+ {
+ if (string.IsNullOrEmpty(format))
+ throw new ArgumentNullException();
+
+ _cacheBuilder.Length = 0;
+ _cacheBuilder.AppendFormat(format, arg0, arg1);
+ return _cacheBuilder.ToString();
+ }
+ public static string Format(string format, object arg0, object arg1, object arg2)
+ {
+ if (string.IsNullOrEmpty(format))
+ throw new ArgumentNullException();
+
+ _cacheBuilder.Length = 0;
+ _cacheBuilder.AppendFormat(format, arg0, arg1, arg2);
+ return _cacheBuilder.ToString();
+ }
+ public static string Format(string format, params object[] args)
+ {
+ if (string.IsNullOrEmpty(format))
+ throw new ArgumentNullException();
+
+ if (args == null)
+ throw new ArgumentNullException();
+
+ _cacheBuilder.Length = 0;
+ _cacheBuilder.AppendFormat(format, args);
+ return _cacheBuilder.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs.meta
new file mode 100644
index 0000000..4403b6b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/StringFormat.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 86ae09fcbdc5301499fb61e9bd4a5794
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniFramework.Utility.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniFramework.Utility.asmdef
new file mode 100644
index 0000000..4f6e14b
--- /dev/null
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniFramework.Utility.asmdef
@@ -0,0 +1,14 @@
+{
+ "name": "UniFramework.Utility",
+ "rootNamespace": "",
+ "references": [],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniUtility.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniFramework.Utility.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniUtility.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniUtility/Runtime/UniFramework.Utility.asmdef.meta
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow.meta
index f6718e6..e091003 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow.meta
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 5079914495c00a74e873f6490a7a5673
+guid: 047e2424cfccd68479ce85171e28d9f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniMachine.asmdef b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniFramework.Window.asmdef
similarity index 91%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniMachine.asmdef
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniFramework.Window.asmdef
index 9fdb4ab..a4792e1 100644
--- a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniMachine/Runtime/UniMachine.asmdef
+++ b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniFramework.Window.asmdef
@@ -1,5 +1,5 @@
{
- "name": "UniMachine",
+ "name": "UniFramework.Window",
"rootNamespace": "",
"references": [
"GUID:e34a5702dd353724aa315fb8011f08c3"
diff --git a/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniWindow.asmdef.meta b/Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniFramework.Window.asmdef.meta
similarity index 100%
rename from Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniWindow.asmdef.meta
rename to Assets/YooAsset/Samples~/Space Shooter/ThirdParty/UniFramework/UniWindow/Runtime/UniFramework.Window.asmdef.meta