以下内容均在Unity4.5版本中通过
1:使用编辑器创建动画
假设场景中新建了一个Cube,名字为CubeTest。
选中该Cube, 打开Animation面板,点击AddCurve按钮,出现一个“Create New Animation”的保存框:
默认情况下为Cube添加了Animator组件,
同时创建了一个AnimatorController(AnimatorController的默认名字和选中的物体名字一致),一个名字为test的anim clip片段.
如图,可见Clip的属性也是和Animator中的Clip是一致的。
接下来为这个Clip编辑方块在5秒钟时间内旋转52°的动画。
如上图:Sample代表每秒采样的次数,图示60,则上面300代表的就是5秒时间。同时在Rotation.y处修改度数为52即可。若不使用这种方法而纯粹的通过托右边区域的红线,往往会造成误差。上图中右边区域可见黄线右边还有很多重复的灰色的线段,表示该动画是Loop循环的。若要取消该循环,可以选中该Clip,然后在Inspector面板中取消Loop Time的选项 。再刷新一下Animation面板,发现灰线消失:
若要仍使用老版本的Animation动画组件。则必须先为Cube添加Animation组件,然后再打开Animation面板->AddCurve。这个时候创建的Clip便是符合Animation组件的动画片段了。
可以通过设置WrapMode来调整动画的循环方式。
2:使用脚本创建动画
依旧以上述Cube为例。新建一个Cube
2.1 AnimationCurve
2.1.1编辑AnimationCurve
新建一个脚本,拖拽到Cube上。代码如下:
public class test : MonoBehaviour
{
public AnimationCurve curve;
void Start()
{
}
void Update()
{
}
}
点击上述红色处,便打开AnimationCurve编辑面板
选中一种线形后,如图
红色区域,可以选择循环的方式,包括:Loop,Clamp,Pingpang。像1中Animation编辑界面一样,这里也可以为动画线添加Key,设置弯曲等等复杂的操作。
最终如图,做了一个5秒,52个单位的动画,并且动画循环方式为Pingpong。下面需要用代码把Curve对应到旋转上
最终代码如下:
public class test : MonoBehaviour
{
public AnimationCurve curve;
void Start()
{
}
void Update()
{
transform.eulerAngles = new Vector3(0, curve.Evaluate(Time.time), 0);
}
}
2.1.2 代码创建AnimationCurve
下面使用代码来完成2.1.1中的Curve细节的创建
public class test : MonoBehaviour
{
AnimationCurve curve;
void Start()
{
//curve = AnimationCurve.Linear(0, 0, 5, 52);
curve = new AnimationCurve();
curve.AddKey(new Keyframe(0, 0));
curve.AddKey((new Keyframe(5, 52)));
//两种设置Curve的方式都可以。
//第一个调用静态方法来设置(开始时间、开始值、结束时间、结束值 )
//第二个是先构造函数实例化Curve,然后添加Keyframe(time,value);
curve.preWrapMode = WrapMode.Clamp;
curve.postWrapMode = WrapMode.PingPong;
}
void Update()
{
transform.eulerAngles = new Vector3(0, curve.Evaluate(Time.time), 0);
}
}
2.2 Animation
可以发现上述2.1中动画的播放没有使用到Animation组件,而是使用的AnimationCurve. Evaluate(float time)方法来根据时间对应相对的值。
其实也可以使用Animation组件来播放动画,这里以2.1.2中的curve为例。
代码如下:
public class test : MonoBehaviour
{
void Start()
{
AnimationCurve curve = AnimationCurve.Linear(0, 0, 5, 52);
AnimationClip clip = new AnimationClip();
clip.wrapMode = WrapMode.Loop;
clip.SetCurve("", typeof(Transform), "localRotation.y", curve);
animation.AddClip(clip, "test");
animation.Play("test");
}
}
经测试不生效,表现为y rotation瞬间从0变成180。
把localRotation.y改成localPosition.y可行。
改成localScale.y也不可行。表现为localScale.x和localScale.z变成了0。然后在y上缩放。
具体支持的string字符串参见文档,反正是不支持诸如rotation.y之类的。
搞不清楚什么原因,TODO:
3:综合实例
需要实现这样一个功能,实例化某个物体后,物体先下降,然后反弹,最后再下降到底部。
首先考虑到Animation编辑器,对Y轴进行编辑,结果如下
该图共有4个节点(0,12),(1,3),(1.3,12),(3,-12)
然后使用该动作,问题出来了。该动作限制了Position.x为0,因此无论初始化使用这个animation clip的物体在什么地方,都会强制使得position.x变成0。
为了解决这个问题,必须使用程序,两套curve,一个模拟图示的曲线控制y的位置。一个用来控制x的位置为初始化位置。
代码如下:
float xPos;
void Awake()
{
xPos = transform.position.x;
}
void Start()
{
/*模拟Y轴上的位移动画*/
AnimationCurve curveY = new AnimationCurve();
curveY.AddKey(new Keyframe(0f, 12f));
curveY.AddKey(new Keyframe(1f, 3f));
curveY.AddKey(new Keyframe(1.3f, 12f));
curveY.AddKey(new Keyframe(3f, -12f));
//curveY.SmoothTangents(0,)//默认AddKey后,经测试程序里面就是按照布泽尔曲线拟合的
/*X轴上保持初始化位置*/
AnimationCurve curveX = new AnimationCurve();
curveX.AddKey(new Keyframe(0f, xPos));
curveX.AddKey(new Keyframe(3f, xPos));
/*添加自毁函数*/
AnimationEvent aniEvent = new AnimationEvent();
aniEvent.functionName = "DestroySelf";
aniEvent.time = 3f;
AnimationClip clip = new AnimationClip();
clip.wrapMode = WrapMode.Once;
clip.AddEvent(aniEvent);
clip.SetCurve("", typeof(Transform), "localPosition.y", curveY);
clip.SetCurve("", typeof(Transform), "localPosition.x", curveX);
animation.AddClip(clip, "supplyAnimation");
animation.Play("supplyAnimation");
}
void DestroySelf()
{
Destroy(gameObject);
}