前言
作为一个“不务正业”的东川路某男子职业技术学校的大学汪(如果有幸遇到隔壁东川路某幼师学校的大佬,求带华师小龙虾!!!),平时就喜欢用Unity用Editor,Editor Window什么的工具写一些奇奇怪怪的东西,因为想要学习研究的东西网上有效的信息都不多,只能一点点看着代码提示看着各种方法的名字配着官网的API慢慢摸索,过程艰难不说还效率低下。在海澜大佬的建议下,开始在简书将学习过程中学到的东西整理一下,如果在写的过程中能帮助到别人的话,那真的是非常开心的一件事!因为是学习的整理,如果对某个东西的理解有问题的话,请大家多多指正,非常感谢!
AnimationClip是什么
它是 储存基于关键帧的动画,但是AnimationClip和KeyFrame(关键帧)并不是直接的父子关系。AnimationClip通过EditorCurveBind或者ObjectReferenceCurveBindings(下两个统称Bind)连接AnimationCurve,一个Bind对应着一个AnimationCurve,而一个AnimationCurve对应着一个KeyFrame[ ]。其中EditorCurveBind用来绑定浮点数类型字段,Position.x Rotation.x等,而ObjectReferenceCurveBinding用来绑定其他非浮点数类型的字段,如SpriteRender里面的字段。两者差别不大,结构和使用方法基本上一样,后面只讲有关EditorCurveBind的内容。
怎么获取AnimationClip里面的信息
我们通过Unity界面大概知道了AnimationClip大概包含了什么内容,现在该到我们自己领域——代码域由顶到底去探究一下他到底是怎样的一个结构。
(1)创建一个脚本作为测试,并如图创建物体,给他的Animator一个AnimatorControl,并给它添加一个Animation,如下图随意K几帧。
(2) 认识EditorCurveBinding
通过代码提示,我们可以简单发现EditorCurveBinding主要含有两个字段:path和propertyName。键入如下代码:
PS:使用OnDrawGizmos主要是因为它可以实时debug,gizmosCount是为了避免Debug过快的问题
public class AnimationLoad : MonoBehaviour
{
public AnimationClip anim;
public int gizmosCount = 0;
public void OnDrawGizmos()
{
if (anim == null)
{
return;
}
if (gizmosCount != 20)
{
gizmosCount++;
return;
}
else
{
gizmosCount = 0;
//Coding
//EditorCurveBinding[] binds = AnimationUtility.GetObjectReferenceCurveBindings(anim)
EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
foreach (var bind in binds)
{
Debug.Log("Path: "+bind.path);
Debug.Log("Property Name: "+bind.propertyName);
}
//Coding
}
}
}
观察Console可以判断path为被控制物体相对于根物体的位置。
而propertyName为被控制组件被控制property(属性)的名字。而后面的x y z 对应这个属性内部的各个字段(一般一条Curve只能控制一个简单的值类型的字段,如:浮点数,布尔等)
Bind里面还有一个字段必须设置,Bind.type为被控制组件的类型,如果不设置set的时候会报错。
Debug.Log(“Path:”+bind.path+“,Type:”+bind.type+“,Property Name: ”+“bind.propertyName”);
后输出第一条Curve:Path: Cube ,Type:Transform, Property Name: m_LocalPosition.x 。
就代表着这条AnimationCurve控制着Cube这个物体的Transform组件的localPosition的x这个值。
Transform相关的几个PropertyName如下
Position 位置
"m_LocalPosition"
Rotation——有三种插值类型
(1)Euler Angle 欧拉角插值
"LocalEulerAnglesRaw"
(2)Euler Angle(Quarternion) ?欧拉四元数混合类型?
"m_LocalRotation"
(3)Quarternion 四元数插值
"m_LocalRotation"
Scale 缩放
"m_LocalScale"
其他属性可以通过类似方法通过Debug查询。
知道了Bind的功能,我们可以通过
AnimationCurve curve = AnimationUtility.GetEditorCurve(AnimationClip anim,EditorCurveBinding bind);来获取Bind所绑定的曲线。
//Coding
EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
foreach (var bind in binds)
{
AnimationCurve curve = AnimationUtility.GetEditorCurve(anim,bind);
Keyframe[] keys = curve.keys;
}
//Coding
通过观察AnimationCurve我们会发现,它主要管理着Keyframe[] keys, 并提供了一些处理keys的方法。我还没有看AnimationCurve其他参数的具体用法,自行研究,哈哈。
通过遍历Keys并观察Keyframe内的字段,我们会发现他的几个主要的字段。
其中:
time:(float)帧所在的时间,帧的帧号(第几帧) = time * 每秒播放的帧数
value: (float) 这一帧AnimationCurve所控制属性的值
//插值相关 Hermite曲线参数
inTangent: 此帧左边进入曲线的切线斜率
inWeight: 此帧左边进入曲线的切线的权重(TangentMode为Weight才有用)
outTangent:此帧右边出去曲线的切线斜率
outWeight: 此帧左边进入曲线的切线的权重(TangentMode为Weight才有用)
tangentMode:切线的模式
tangentMode.Free 自由模式,只能控制切线的斜率此时为标准hermite曲线
tangentMode.Linear 线性插值模式,此时根据相邻两帧位置线性插值,曲线与俩切线无关
tangentMode.Const 常数模式,没有插值,数值直接在帧位置突变
tangentMode.Weight 权重模式,能控制切线的斜率和权重,更方便控制曲线,切线的斜率*权重为Hermite参数
怎么代码生成AnimationClip
知道AnimationClip里面有什么东西之后,代码生成他就易如反掌了。
下面生成一段动画,动画里面的方块的Y坐标随时间呈正弦变化,插值模式为线性插值。
public void CreateAnimation(string name)
{
//Coding
EditorCurveBinding[] binds = AnimationUtility.GetCurveBindings(anim);
//创建Keyframes
Keyframe[] keys = new Keyframe[60];
//对Keys进行赋值
for (int i = 0; i < keys.Length; i++)
{
keys[i].time = i / 30f;
keys[i].value = 2 * Mathf.Sin(2 * Mathf.PI * i / 15);
}
//创建曲线
AnimationCurve curve = new AnimationCurve();
curve.keys = keys;
//设置模式
for (int i = 0; i < keys.Length; i++)
{
AnimationUtility.SetKeyLeftTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
AnimationUtility.SetKeyRightTangentMode(curve, i, AnimationUtility.TangentMode.Linear);
}
//创建Bind
EditorCurveBinding bind = new EditorCurveBinding();
bind.path = "Cude";
bind.propertyName = "m_LocalPosition.y";
//这个是被控制
bind.type = typeof(Transform);
AnimationClip animCreate = new AnimationClip();
AnimationUtility.SetEditorCurve(animCreate, bind, curve);
AssetDatabase.CreateAsset(animCreate, "Assets/"+name+".anim");
//Coding
}
如果有其他需求Key的赋值处,Curve的设置处进行修改就可以了,原理基本上一样。