动画脚本
在很多游戏中我们可以看到游戏角色可以攻击,跳跃,跑步,待机等各种动作,那么这些
动作是如何实现的呢?这就需要不仅仅是角色本身的静态模型了,更需要有相应的动作动
画来控制。使用Unity的动画系统可以制作出漂亮的动画效果。动画系统可以支持融合,
附加,动画混合,同步,动画图层,动画播放的控制(时间,速度,混合权重),每个顶
点有1,2,4个骨骼影响到mesh,当然也支持物理上的布偶和过程动画。
要制作一个动画角色需要用相应的脚本去控制角色的动画。
动画融合-Animation Blending
在现如今的游戏中,动画融合已经广泛应用于角色动画中。美工人员做出角色的不同动作
动画,如跑步,攻击,行走,静止等。而程序需要做的就是让这些静止的动画平缓的播放
出来。比如玩家可能一边跑步一边攻击这就是动作的混合。当然这些动画要很平缓的进行,这样才有真实感。
而要做到平缓的播放每个不同动作的动画,就需要用到动画混合技术。在Unity中,可以
有无限个动作动画在同一个角色身上播放。所有的动画可以混合起来产生最终的动画效果。
首先,我们来做一个比较平缓的在行走和静止之间的一个动画效果。为了使我们脚本实现
起来更容易,可以先把动画的Wrap Mode设置为Loop然后关闭Play Automatically(自动播
放功能),这样就能确保脚本是唯一来播放动画的方式。
function Update () {
if (Input.GetAxis("Vertical") > 0.2) //判断向前的速度如果大于0.2,就
播放行走的动画
animation.CrossFade ("walk"); //CrossFade是unity提供的一个
动作混合的函数,它主要是用来过渡一个动画正在播放而另一个动画准备即将要播放之间的时间差
else
animation.CrossFade ("idle"); //如果没有向前,那么就播放静止的动画
}
以上代码只是判定向前的动作,如果角色转向或者倒退择不会有任何的动画播放,如果要
让角色不管前后左右都播放行走这个动画,不妨修改以上代码为这样:
if (Input.GetAxis("Vertical") > 0.2 || Input.GetAxis("Vertical") < -0.2)
animation.CrossFade("walk");
else if (Input.GetAxis("Horizontal") > 0.2 || Input.GetAxis("Horizontal") < -0.2)
animation.CrossFade("walk");
要想让这段脚本运行,首先得建立你的游戏角色,并且这个角色带有动画,然后把脚本加
入到该角色上,即可正常播放。
待机
战斗姿势
动画层-Animation Layers
动画层是针对有很多组不同的动画而进行控制的一个方法,因为在Unity3d中如果要把所有的动作动画写进一个层里,最后运行的效果只会显示其中的2个动作动画,因为在每个层中Unity3d只支持2个动作动画,所以为了要混合更多的动画我们不得不用到动画层这一概念。
下面来看一个例子,或许你创建了一个这样的游戏,游戏里的角色可能会有静止,行走和射击3个不同的动画,但是我们知道Unity3d中每个层只支持2个动作的动画,怎么样让我们的角色可以都有这3个动作呢?原理很简单,可以使用Unity3d中的动画层来解决这一问题,可以自由先组合3个动作中的其中2个为一个层,最后一个动作作为另外一个动画层,这样这3个动画层就不会有任何冲突,那我们角色的动作动画也就可以自然而然的播放出来,下面来看下代码该如何实现:
function Start () {
// 设置所有动作进入动画层模式
animation.wrapMode = WrapMode.Loop;
// 现在我们假设让行走和静止为一个层,那么就得把射击这个动作隔离出来为另外一个动画层
animation["shoot"].wrapMode = WrapMode.Once;
//设置射击为第二个层,在unity3d中默认层为0,即idle和walk这2个为0层,shoot为1层
animation["shoot"].layer = 1;
// 停止动画播放
//为了避免有时候我们忘记设置Play Automatically为关闭状态
animation.Stop();
}
function Update () {
//首先混合静止和行走2个动作
if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1)
animation.CrossFade("walk");
else
animation.CrossFade("idle");
// 最后播放射击
if (Input.GetButtonDown ("Fire1"))
animation.CrossFade("shoot");
}
跳跃和射击同时进行
动画混合-Animation Mixing
动画混合可以让你缩减你必须为游戏制作的动画片段数量,方法是制作只对身体某个部分起作用的动画.这意味着这些动画可以和其他动画合并起来一起使用。只要使用AddMixingTransform()这个函数即可为动画添加一个mixing transform。
呵呵也许到这里脑子有点乱,那不妨我们来假设一下,假如说现在有2个游戏角色,它们需要的动作是站立,行走,还有招手这几个动作,我们需要看到的是行走的角色在做招手,站立的角色也在做招手的动画,如果没有动画混合即Animation Mixing,那就得创建2个招手的动画分别给2个游戏角色,一个给静止的角色,一个给行走的角色。然而,如果你将招手这个动画作为一个混合坐标(mixing transform)添加到肩膀坐标(shoulder transform),招手动画只控制肩膀,而角色剩下的其余身体的部位则不会有任
何影响,这样一来我们就减少了为角色去添加动画的数量,也许2个角色的动画数量有限,如果成千上万呢,那不是可以减少很多毫无疑又浪费时间的工作了。因为我们只是想看到
招手这个动画而已,何必去为每个角色都创建一个招手动画呢!
/// 给肩膀上添加一个“招手”的坐标
var shoulder : Transform;
animation["wave_hand"].AddMixingTransform(shoulder);
一个使用路径的例子
function Start () {
// 使用路径去给肩膀上添加一个“招手”的坐标
var mixTransform : Transform =
transform.Find("root/upper_body/left_shoulder");
animation["wave_hand"].AddMixingTransform(mixTransform);
}
附加动画- Animation Additive
附加动画和动画混合都可以让我们减少对游戏中要制作动画的数量,尤其对于一些表情动画。
让我们来看看现在假如要创建一个正在跑步和转身的角色并且让它的身体有些倾斜,假设
已经为角色做好了跑步和行走的动画,现在还得分别添加单独的走路向左倾斜,走路向右
倾斜,跑步向左倾斜,跑步向右倾斜4个动画,这意味还得去添加4个额外的动画,显然
这样做非常不明智,我们需要附加和混合动画啊!
附加动画实例
附加动画允许你在顶层覆盖其它所有可能播放的动画效果。当你制作一个附加动画时,Unity将计算动画片段里的第一帧和当前帧之间的差异。然后它将在所有其它播放的动画之上应用这个差异。
现在只需做一个左倾和右倾的动画。Unity将为此倾斜动画新建一个层并置于walk,idle或run循环的层级之上。
如下是具体实现方法:
private var leanLeft : AnimationState;
private var leanRight : AnimationState;
function Start () {
leanLeft = animation["leanLeft"];
leanRight = animation["leanRight"];
// Put the leaning animation in a separate layer
// So that other calls to CrossFade won't affect it.
https://www.sodocs.net/doc/9b13875262.html,yer = 10;
https://www.sodocs.net/doc/9b13875262.html,yer = 10;
// Set the lean animation to be additive
leanLeft.blendMode = AnimationBlendMode.Additive;
leanRight.blendMode = AnimationBlendMode.Additive;
// Set the lean animation ClampForever
// With ClampForever animations will not stop
// automatically when reaching the end of the clip
leanLeft.wrapMode = WrapMode.ClampForever;
leanRight.wrapMode = WrapMode.ClampForever;
// Enable the animation and fade it in completely
// We don't use animation.Play here because we manually adjust the time
// in the Update function.
// Instead we just enable the animation and set it to full weight
leanRight.enabled = true;
leanLeft.enabled = true;
leanRight.weight = 1.0;
leanLeft.weight = 1.0;
// For testing just play "walk" animation and loop it
animation["walk"].wrapMode = WrapMode.Loop;
animation.Play("walk");
}
// Every frame just set the normalized time
// based on how much lean we want to apply
function Update () {
var lean = Input.GetAxis("Horizontal");
// normalizedTime is 0 at the first frame and 1 at the last frame in the clip
leanLeft.normalizedTime = -lean;
leanRight.normalizedTime = lean;
}
提示:
以上代码不妨参考下上面所提到的动画层这一概念,兴许就不难理解了。当使用附加动画时,特别要注意非附加动画和附加动画在坐标上的控制,否则不会正常播放,这也不是我们想看到的。
角色过程动画-Procedurally Animating Characters
试想一下吧,有时候我们可能想播放一些角色的骨骼动画。举个例子比如说你想让一个角
色在3D的环境下对着一个点去做一些头部的动作,这么说吧比方现在场景中有一个角色
然后还有一部摄像机,用鼠标来控制摄像机,当鼠标移动到不同位置时角色的头部也在跟
着摄像机做旋转。当然要实现这些离不开脚本,但是别担心,在Unity里使用这些脚本非
常方便。在 Unity中所有的骨骼坐标就可以来驾驭蒙皮网格,所以你就可以通过脚本来控
制角色骨骼就好象控制其它的游戏对象一样。
需要注意的是在LateUpdate()调用前,在调用Update()这个函数后动画系统会每帧更新一
下坐标。所以如果要写一个角色头部跟着摄像机做旋转的功能(我们可以姑且命名它为LookAt()),就应该把它写进LateUpdate()这个函数中来确保动画的播放是正常进行的。换言之,摄像机移动了,头部的动作在确认了摄像机的坐标已经改变了,头部的动作才会
去更新坐标。因为LateUpdate()是在Update()这个函数执行完才执行的。
布偶的创建跟上面的原理是一样的。如果已经给对象的不同骨骼加上了刚体(Rigidbody),关节(Character Joints)和胶囊碰撞(Capsule Colliders),那么你的角色就会产生物理上
的过程动画了。
提示:官方有一个很有用的示例https://www.sodocs.net/doc/9b13875262.html,/support/resources/example-
projects/procedural-examples可供具体参考
字母的变化过程
球体的变化过程立方体的变化过程
动画回放和采样-Animation Playback and Sampling 这里主要解释在Unity中当动画在使用引擎回放时是如何采样的。
动画片段在固定的帧率(frame rate)上很有代表性。举个例子,当你在3ds Max或者Maya中创建了一个每秒60帧的动画后,当导入进Unity,同样也是60帧的动画。然而游戏在运行的时候,帧率却不是恒定不变的。在一些速度较快的PC上帧率会更快,帧率也会每一秒在摄像机与给出的任意一点上所看到复杂度不同。基本上这意味着我们可以不用当游戏运行的时候去假设确切的帧率。如果有一个60帧的动画,它应该是可以从不同的帧率上回放回来,比如56.72 fps,或者83.14fps,可以是任何的点。
Unity在不同帧率上的的采样动画,并不是它们真正的帧率。但是很幸运,3D电脑图形上的动画不是由分离的帧所组成的,而是连续的曲线。这些曲线对任何点的采样都是很适合的,不是光只是在时间轴上原始帧的那些点。这意味着游戏在运行的时候,在比较高的帧率上,动画效果看起来会更平滑和流畅。
在大多数练习的情况下,事实上Unity采样动画在这些可变的帧率上并不是你想像中还需要去做连接的。然而,如果你有一个在游戏逻辑上要去判断控制动画的坐标属性,那就得注意了。举个例子,如果你有一个30帧的动画是来旋转一个对象从0-180度,你想知道当代码何时进行到当动画进行到一半的时候即90度,不应该去添加一个条件语句来判断现在对象的旋转是不是已经进行到了90度。因为Unity的动画采样是依照游戏不同的帧率来进行的,当旋转在90度以下的时候就该判断了,等到90度的时候就刚好。如果你需要知道何时动画中一个指定点的时候,应该去用AnimationEvent代替。
要注意在可变帧率上的因果关系,一个回放动画要用WrapMode.Once是不可能为一个上一帧的准确时间来采样的。在游戏的动画帧上可以在动画播放后去采样,在下一个帧上的时间上就有多余动画长度,所以就关闭也不会去采样。如果你真的需要上一帧的动画去做采样,就需要WrapMode.ClampForever.这样动画就会正常保持上一帧的采样直到你要停止播放动画。