DOTween
通过简化的代码为任何内容制作动画。DOTween 是一个快速、高效、完全类型安全的面向对象的动画引擎,针对 C# 进行了优化(它是以前的 Unity 补间引擎 HOTween 的演变)。
-
特性
-
速度和效率:所有内容都被缓存和重用
-
IntelliSense 和类型安全
-
IntelliSense [ɪn'telisns]:代码补全辅助工具
-
类型安全:任何地方都没有字符串
-
-
快捷方式:直接扩展常见对象的快捷方式
// Move a transform to position 1,2,3 in 1 second transform.DOMove(new Vector3(1,2,3), 1); // Scale the Y of a transform to 3 in 1 second transform.DOScaleY(3, 1); // Pause a transform's tween transform.DOPause();
-
极其准确:时间是以非常精确的方式计算
-
逻辑且易于使用的 API
-
为一切制作动画(几乎):可以对每个数值以及一些非数值进行动画处理。它甚至可以对字符串进行动画处理,并支持富文本。
-
模块:可以通过 DOTween Modules 激活/停用对 Unity 系统(物理/音频/UI/等)的引用。
-
完全控制:播放,暂停,倒带,重新启动,完成,转到以及大量其他有用的方法来控制补间。
-
分组:将补间组合成序列以创建复杂的动画(不需要在序列中:它们也可以相互重叠)。
-
可混合补间:一些补间可以实时相互混合。
-
路径:沿着线性和曲线路径制作动画
-
在播放时更改值和持续时间
-
-
使用
-
在资源商店下载并安装DOTween
-
在PackageManager导入到要使用的项目中。
-
安装完成后点击 Setup DOTween 会自动根据unity的版本导入/重新导入内部的一些文件,激活或者停用一些模块。
-
Tools/Demigiant/DOTween Utility Panel 打开该面板。
-
-
在使用DOTween需引入对应的命名空间:
using DG.Tweening;
-
初始化DOTween,设置一些全局设置。
-
默认的设定可以在初始面板中的首选项(Preferences)中更改。
-
DOTween.Init();
参数
功能
recycleAllByDefault
bool类型,如果为true,所有的 动画补间将会在调用完后被回收放入一个对象池中,而不是直接被销毁。
useSafeMode
bool类型,如果为true,补间会变慢,但是会更加安全,允许补间照顾一些东西,当一个物体被销毁时,补间仍然执行。
logBehaviour
据所选模式,DOTween 将只记录错误(ErrorsOnly)或者错误和警告(Default),或所有内容以及其他信息(Verbose)
命名法
-
Tweener :补间,控制值并为其生成动画。
-
Sequence:序列,控制多个补间作为组来处理。
-
Tween:通用词,通用词表示补间和序列。
-
Nested tween:嵌套补间,序列中包含的补间。
前缀
-
DO:所有快速实现一些补间效果的前缀(如变换Transform)的前缀。
-
Set:对当前效果进行设置。
-
On:一系的列回调。
-
DOTween详情:https://dotween.demigiant.com/documentation.php#globalSettings
spine动画
详情:https://zh.esotericsoftware.com/spine-unity
插件库导入
-
从开源库导入:
-
把
spine-runtimes/spine-unity/Assets/
里的文件拷贝到你项目里的Assets/
文件夹里. -
把
spine-runtimes/spine-csharp/src
文件夹拷贝到你项目里的Assets/Spine/Runtime/spine-csharp
文件夹中.
-
从官网插件导入
-
导入这个Unity组件包 (双击它就可以让Unity打开).
通过软件包管理器安装spine-unity运行时
使用Unity的包管理器-'Add package from git URL'而非直接打开Unity组件包(unitypackage) 如果你的Unity版本比较新, 且你的Unity包管理器提供了
Add package from git URL...
选项, 你也可以直接使用下方的三个URL来添加这三个包:
https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-csharp/src#4.1
https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-unity/Assets/Spine#4.1
https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-unity/Assets/Spine
Examples#4.1
要打开
Spine Examples
包的示例场景请使用操作系统的文件管理器(Explorer或Finder), 应将场景文件从包目录复制到你的Assets
目录. 因为如果你试图直接打开通过git URL下载的包中的场景, Unity中的一个bug会导致出现"Opening scene in read-only package!"
错误:
在Unity中导入Spine 资产
-
Json格式
-
二进制数据格式
-
打开导出文件的文件夹
-
将导出的文件(或包含它们的文件夹)复制到项目的
Assets
文件夹中 -
spine-unity自动生成文件
-
_Atlas 文件是texture atlas文件 (
.atlas.txt
). 它包含对material和.atlas.txt
文件的引用. -
_Material 包含了各个 texture atlas页 (
.png
). 它包含对着色器和.png
texture的引用. -
_SkeletonData 存储了skeleton数据 (
.json
,.skel.bytes
). 它包含了对.json
或.skel.bytes
文件以及生成的 _Atlas 资产的引用. 它还为skeleton提供了自定义的导入和动画设置, 详见 Skeleton Data 资产部分.
-
将Skeleton添加到场景中
-
方法1:
-
_SkeletonData 资产拖入Scene视图或Hierarchy面板然后选择
SkeletonAnimation
. 这将实例化一个带有所需Spine组件的新GameObject.
-
-
方法2:
-
用
GameObject -> Create Empty
菜单创建一个新的空GameObject. -
在检查器中选择GameObject然后点击
Add Component
, 然后选择SkeletonAnimation
. 这会自动为GameObject添加MeshRenderer
和MeshFilter
组件. -
在 SkeletonAnimation 组件中, 把所需的 _SkeletonData 资产赋值给
Skeleton Data Asset
属性
-
三种实例化skeleton的方法
-
SkeletonAnimation - 使用Spine定制的动画和事件系统, 提供最高的可定制性. 渲染使用的是
MeshRenderer
, 可以像Unity sprite一样与SpriteMask
等遮罩进行交互. 在Unity中推荐以这种方式使用Spine skeleton. -
SkeletonGraphic (UI) - 与Unity
Canvas
一起作为UI元素使用. 像内置的Unity UI元素一样渲染并与UI遮罩(如RectMask2D
)交互. 动画和事件行为与 SkeletonAnimation相同. -
SkeletonMecanim - 使用Unity的Mecanim动画和事件系统来启动、mix和过渡动画. 与SkeletonAnimation相比,提供的动画mix和过渡选项较少.当使用
SkeletonMecanim
时, 无法保证动画过渡看起来和Spine Editor中的预览一致.
高级 - 运行时实例化
注意: 推荐通过正常的工作流将skeleton添加到场景中, 并将其存储于prefabs内, 而非从实例池中取出池化对象来复用. 这样会使得修改和调整更加容易.
// 从 SkeletonDataAsset 实例化 SkeletonAnimation 游戏对象 SkeletonAnimation instance = SkeletonAnimation.NewSkeletonAnimationGameObject(skeletonDataAsset); // 从 SkeletonDataAsset 实例化 SkeletonGraphic 游戏对象 SkeletonGraphic instance = SkeletonGraphic.NewSkeletonGraphicGameObject(skeletonDataAsset, transform, skeletonGraphicMaterial);
// 从导出的资产实例化,无需事先导入 // 1. 创建 AtlasAsset(需要 Atlas 文本资源和纹理,以及材质/着色器); SpineAtlasAsset runtimeAtlasAsset = SpineAtlasAsset.CreateRuntimeInstance(atlasTxt, textures, materialPropertySource, true); // 2. 创建 SkeletonDataAsset(需要 json 或二进制资产文件,以及 AtlasAsset) SkeletonDataAsset runtimeSkeletonDataAsset = SkeletonDataAsset.CreateRuntimeInstance(skeletonJson, runtimeAtlasAsset, true); // 3. 创建 SkeletonAnimation(需要有效的 SkeletonDataAsset) SkeletonAnimation instance = SkeletonAnimation.NewSkeletonAnimationGameObject(runtimeSkeletonDataAsset);
SkeletonAnimation
参数
-
Initial Skin:该皮肤将在动画开始时显示.注意:如果你看到的skeleton没有附加任何图像,可以切换到
default
以外的皮肤来显示皮肤. -
Animation Name.:该动画将在开始时播放.
-
Loop:定义初始动画是循环播放还是只播放一次.
-
Time Scale:设置时间比例来减慢或加快动画的播放速度.
-
Unscaled Time:当置为
true
时, 更新将根据Time.unscaledDeltaTime时间而非Time.deltaTime进行. 这对于不适用慢动作效果的动画UI元素来说非常有用.
SkeletonAnimation Update 回调
-
SkeletonAnimation.
BeforeApply
事件在应用该帧动画之前被引发. 当你想在动画应用到skeleton上之前改变skeleton的状态时, 请使用这个回调. -
SkeletonAnimation.
UpdateLocal
事件在该帧动画更新完成并应用于skeleton的局部值之后被引发. 如果你需要读取或修改骨骼的局部值, 请使用它. -
SkeletonAnimation.
UpdateComplete
在计算完Skeleton中所有骨骼的世界值后被引发. SkeletonAnimation在这之后不会在Update中做进一步的操作. 如果你只需要读取骨骼的世界值, 就使用它. 如果有代码在SkeletonAnimation的Update之后修改了这些值, 这些值可能仍会发生变化. -
SkeletonAnimation.
UpdateWorld
是在计算了Skeleton中所有骨骼的世界值后引发的. 若订阅了该事件则将二次调用skeleton.
UpdateWorldTransform
. 如果你的skeleton复杂或正在执行其他计算, 那这将是多余甚至是浪费的行为. 如果需要根据骨骼的世界值来修改骨骼的局部值, 请使用该事件. 它在Unity代码中实现自定义约束很有用.
SkeletonRenderer Update 回调
-
OnRebuild
在skeleton成功初始化后触发. -
OnMeshAndMaterialsUpdated
会在更新完网格和所有material后, 于LateUpdate()
结束时触发.
Skeleton
SkeletonAnimation 组件通过 SkeletonAnimation.Skeleton
属性提供对底层skeleton的访问. 一个Skeleton存储了对一个skeleton data资产的引用,而skeleton data又引用了一个或多个atlas资产.
通过Skeleton可以设置皮肤、附件、重置骨骼为setup pose、比例以及翻转整个skeleton.
设置附件
设置一个附件需要提供槽位和附件名称.
bool success = skeletonAnimation.Skeleton.SetAttachment("slotName", "attachmentName");
重置为Setup Pose
skeleton.SetToSetupPose(); skeleton.SetBonesToSetupPose(); skeleton.SetSlotsToSetupPose();
设置皮肤
bool success = skeletonAnimation.Skeleton.SetSkin("skinName"); skeletonAnimation.Skeleton.SetSlotsToSetupPose(); // see note below
组合皮肤
var skeleton = skeletonAnimation.Skeleton; var skeletonData = skeleton.Data; var mixAndMatchSkin = new Skin("custom-girl"); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("skin-base")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("nose/short")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("eyelids/girly")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("eyes/violet")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("hair/brown")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("clothes/hoodie-orange")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("legs/pants-jeans")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("accessories/bag")); mixAndMatchSkin.AddSkin(skeletonData.FindSkin("accessories/hat-red-yellow")); skeleton.SetSkin(mixAndMatchSkin); skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
运行时重打包
在组合皮肤时会有多个material累积, 这将引发额外的绘制调用. 使用Skin.GetRepackedSkin()
方法可以在运行时将收集到的皮肤中使用过的texture区域合并为一个texture.
using Spine.Unity.AttachmentTools; // Create a repacked skin. Skin repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas); collectedSkin.Clear(); // Use the repacked skin. skeletonAnimation.Skeleton.Skin = repackedSkin; skeletonAnimation.Skeleton.SetSlotsToSetupPose(); skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); // skeletonMecanim.Update() for SkeletonMecanim // You can optionally clear the cache after multiple repack operations. AtlasUtilities.ClearCache();
重要提示: 如果重打包失败或产生意外问题, 可能源于以下原因:
禁用了读/写. 你可能需要在并入重打包texture的源textures上设置
Read/Write Enabled
参数.启用了压缩: 需要确保源texture的Texture导入设置中
Compression
为None
, 而不是Normal Quality
.质量层使用了half/quarter分辨率的textures: 这个是Unity的bug, 当使用half/quarter分辨率的texture时会复制错误区域. 确保项目设置中的所有质量层都使用全分辨率texture.
源texture不是2次texture但Unity将其放大为了最接近次数:a)从Spine导出时启用 Pack Settings 中的
Power of two
, 或者b)确保Unity的Atlas Texture导入设置中将Non-Power of Two
置为None
.
动画 - AnimationState
生命周期
SkeletonAnimation 组件实现了 Update
方法,它根据delta时间更新底层 AnimationState, 将 AnimationState
应用于skeleton上, 并更新skeleton上所有骨骼的世界transforms.
skeleton动画组件通过 SkeletonAnimation.AnimationState
属性暴露了AnimationState API.
时间比例(Scale)
你可以设置skeleton动画组件的时间比例, 以减慢或加快动画的播放速度. 用于推进动画的delta时间会乘上时间比例来决定动画播放速度, 例如时间比例为0.5时, 动画会减慢到正常速度的一半, 时间比例为2时, 动画会加速为正常速度的两倍.
float timeScale = skeletonAnimation.timeScale; skeletonAnimation.timeScale = 0.5f;
设置动画
要设置一个动画,需要确定轨道索引(index)、动画名称和是否循环动画.
TrackEntry entry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, "walk", true);
也可以传入 AnimationReferenceAsset 作为参数而非动画名字.
// using AnimationReferenceAsset public AnimationReferenceAsset animationReferenceAsset; // assign a generated AnimationReferenceAsset to this property ... TrackEntry entry = skeletonAnimation.AnimationState.SetAnimation(trackIndex, animationReferenceAsset, true);
动画队列:要排队动画, 需要提供轨道索引、动画名称、是否循环播放该动画, 以及该动画在轨道上开始播放的延迟时间(以秒计).
TrackEntry entry = skeletonAnimation.AnimationState.AddAnimation(trackIndex, "run", true, 2);
TrackEntry entry = skeletonAnimation.AnimationState.SetEmptyAnimation(trackIndex, mixDuration); entry = skeletonAnimation.AnimationState.AddEmptyAnimation(trackIndex, mixDuration, delay); skeletonAnimation.AnimationState.ClearTrack(trackIndex); skeletonAnimation.AnimationState.ClearTracks();
所有的方法都会返回一个 TrackEntry 对象,可以通过它来进一步定制具体动画的回放,以及定制绑定到轨道条目的具体事件的委托.
注意: 返回的轨道条目只在底层动画状态中删除了对应动画之前有效. Unity的垃圾收集器会自动释放它们. 在接收到轨道条目的销毁事件(dispose event)后, 它就无法再被存储或访问.
TrackEntry entry = ... entry.EventThreshold = 2; float trackEnd = entry.TrackEnd;
处理AnimationStates事件
底层的 AnimationState
回放动画时,将引发下列事件来通知监听器(listener):
-
动画已开始(started) .
-
动画被中断(interrupted), 例如清空了一条轨道或设置了一个新的动画.
-
动画无中断地播放已完成(completed) , 如果是循环动画, 该事件可能会多次出现.
-
动画已停止(ended) .
-
动画和其所处的
TrackEntry
已被销毁(disposed) . -
触发了用户定义的事件(event).
注意: 当设置了一个新动画时, 如果中断了之前的动画, 将不会引发完成(
complete
)事件,而会引发中断(interrupt
)和停止(end
)事件.
Skeleton动画组件提供了C#代码可以绑定的委托, 以便对全部轨道上全部队列中的全部动画的事件做出反应. 监听器也可以只与特定 TrackEntry
的委托绑定.所以你可以注册到如 AnimationState.Complete
事件来处理任何后续的动画 Complete
事件的事件回调(event callbacks),或者注册到 TrackEntry.Complete
事件来处理由某个入队动画引发的 Complete
事件.
常见问题
https://zh.esotericsoftware.com/spine-unity#%E5%B7%B2%E7%9F%A5%E9%97%AE%E9%A2%98