0.写在前面#
动画在游戏开发中很重要,缺乏动画的支持,则难以建立完整的游戏和真正意义上的交互式体验.如果游戏中的元素处于静止状态,将缺乏生命力.
从最基本的层面上看,动画表示为两个特定且独立的特征之间的关系,即变化和时间.从技术讲,动画定义了一段时间内的变化,通过动画以及一段时间内的特征变化,可以有效地表达情绪,氛围,场景,以及理念等特征.
对动画基础知识的掌握需要理解的内容有:动画的概念(帧,关键帧)|动画的类型(刚体动画,骨骼动画,精灵动画,物理动画,变形动画,视频动画,粒子动画,可编程动画)以及编写代码实现动画.
1.动画的概念#
1.1帧
帧:将动画表达中的时间划分为变化过程中独立且离散的单位.
作为离散事物,人们可以实时感受并产生更为明确的场景体验,此类事物可发生在某一时刻或者位于某一帧内.动画帧提供了属性变化的机会,如游戏角色的移动行为或颜色的变化等.在视频游戏中,每秒必须维持或包含特定数量的帧.每秒的帧数量称为FPS每秒帧数,通常用作游戏性能的测算标准.
1.2关键帧(或称重要帧)
如果每秒内传递了多个帧,但并不是每一个帧都需要改变,那么动画设计师可以在动画序列中定义关键帧,随后计算机可以自动生成中间帧.由于定义了动画中的关键时刻,因此此类状态被称为关键帧.
在关键帧的基础上,Unity自动生成中间帧,即补间动画,例如对房门定义两个关键状态:开启状态和闭合状态,定义动画序列的起始点和结束点,对应着起始帧和结束帧,在这两帧之间的中间帧可以平滑的旋转门,中间帧的数学处理过程称作插值计算.
2.动画的类型#
从技术的视角区分视频游戏中不同的动画类型.不同的动画类型的实现方式也有所不同.由于本质上的差别,需采用不同的处理和工作方式,包括特定的工作流以及所涉猎的技术.
2.1刚体动画
刚体动画用于创建预制动画序列,将对象视为整体实体,与具有少量可运动部分的物体不同.在刚体动画中,虽然对象在关键帧之间有所变化,但依然是作为独立的整体进行操作,动画的过程中要始终保持物体的物理结构,仅仅可以是位置,旋转和缩放产生变化.
因此,刚体动画中,关键帧之间的改变仅仅作用于整体物体及其高层属性中,没有渗透到其子属性或内部组成中,对象的本质内部形式一定保持不变.
这一类动画在U3D或3D动画软件中直接加以定义,并于随后通过网格文件导入至U3D中.
2.2骨骼动画
骨骼动画也称为搭建动画,这一类动画并不改变对象的位置,旋转和缩放内容,但是会在帧间对其内部组成进行移动或变形.例如手臂,腿部,头部转动,嘴部运动以及舞动的树叶等等.通常情况下,各个动画需要在3D建模软件中作为完整的动画序列予以创建,随后通过网格文件导入至U3D中.
2.3精灵动画
有时候需要使用包含动画纹理,标准的四边形和平面网格,比如2D动画,图形用户界面以及各种3D特效(Eg.水面波纹).这个时候,对象不需要像刚体动画一样产生运动,也不需要内部结构产生任何变化,因为纹理自身就处于动画状态.这样的动画类型就叫做精灵动画.
精灵动画利用图像或帧序列以特定的帧速率播放,进而呈现出一致的动画外观.例如2D横向卷轴游戏中某一角色的行走动作循环过程.
2.4物理动画
在玩家或其他各种场景因素无法预知的情况下,动画需要呈现真实效果并采用动态方式与场景反馈,比如,采用了U3D的物理系统就可以有因重力作用下坠落到地面的物体.Component>Physics
2.5变形动画
有些情况下,刚体动画,骨骼动画,精灵动画或物理动画都无法满足要求,例如用户可能需要呈现不同物体之间的变形效果(从人变成狼人,从青蛙变成王子,从巧克力棒变成一座城堡等等).
变形动画可以做形状混合,将网格状态混合或者通过平滑的方式从一帧合并至另一帧的不同状态中去.实际上,该方法依赖于动画关键帧之间网格的对应顶点,以及中间帧不同状态间的混合效果.
计算量大,影响性能,但是产生精美逼真的外观.
2.6视频动画
U3D可以播放视频文件,接受OGV(OggTheora)格式的视频,并将其作为资源文件.将音视频作为场景网格对象上的动画纹理进行回放.
功能强大,影响性能.
2.7粒子动画
不同于精灵对象或网格对象有些物体无法被清晰地定义形状,即不具备特定形状的非实体对象,例如,火焰,气泡,花火,烟雾,蜂群,焰火以及云朵等等.
粒子系统不可或缺.粒子系统整体可表示为一类可配置的对象,并用于模拟雨,雪和鸟群等效果.
2.8可编程动画
大多数常见的动画类型都是可编程动画或者动态动画,我们经常需要对一类行为进行编程设计(比如,角色到达门口的时候门的开启行为,玩家操作游戏角色在环境中移动等等),开发人员针对特定的功能编写代码,使得一段时间内对象属性的变化.与其他形式不同,编程行为无法通过设计师事先构建,不过,多数情况下,动画的效果可通过设计师制作完成,代码仅在运行期间简单地对动画行为进行触发和指引.
3.编写代码实现动画#
3.1脚本
基于代码的动画效果是启动动画行为的主要方式,可以通过C#脚本与运动对象实现绑定,脚本内容一般默认包括两个函数:Start()和Update()
Update函数与动画行为密不可分,并与帧和帧率相关,对于FPS=70的游戏,基于脚本的各个对象,Update函数每秒会被执行70次,进而使该对象处于活动状态.
usingUnityEngine;
usingSystem.Collections;
publicclassMover:MonoBehaviour{
voidStart(){}
voidUpdate(){
TransformthisTransform=GetComponent
thisTransform.position+=newVector3(1f,0f,0f);
}
}
3.2一致性动画(速度,时间和deltaTime变量)
由于帧速率在不同的计算机上有所不同,甚至同一计算机的一段时间内也会发生变化.在FPS=70的系统上,对象每秒将更新70个单位,在FPS=90的系统上则为90个,如果这样用户将得不到一致的游戏体验,也会导致多玩家的游戏全部玩家无法处于同步状态的情况.这是绝对不可以的.
行进距离=速度x时间.时间可以在不同的计算设备间保持一致,所以应该直接将运动行为映射至时间.
thisTransform.position+=newVector3(1f*Time.deltaTime,0f,0f);
放在Update函数中的代码是以帧来执行的.如果我们需要物体的移动以秒来执行,就需要将物体移动的值乘以Time.deltaTime.在各帧中,Time.deltaTime显示了距上一帧所经历了的时间值(秒).使用这个变量和游戏帧速率无关.实际表示的将是:每秒移动物体1米而不是每帧移动1米.
当从MonoBehaviour的FixedUpdate里调用时,返回固定帧速率增量时间(fixedDeltaTime).
另外,OnGUI里不应该依赖Time.deltaTime,因为OnGUI可以在每帧被多次调用并且每个调用deltaTime将持有相同的值,直到下一帧再次更新.
3.3某一方向上的运动
这里是向量的概念,形如(x,y,z)的向量包含了3个分量,并以此为某一方向.三个轴同步运动.
usingUnityEngine;
usingSystem.Collections;
//方向控制
publicclassMover:MonoBehaviour{
publicfloatspeed=1f;
publicVector3direction=Vector3.zero;
voidUpdate(){
TransformthisTransform=GetComponent
thisTransform.position+=direction.normalized*speed*Time.deltaTime; } } 3.4动画曲线对中间帧进行编码 游戏对象还需要实现曲线运动,仅仅直线路径想必是不足以的,或者需要对象实现变速运动,以上对此可以使用动画曲线这一特定的对象,构建定义动画的中间帧的曲线,进而控制对象在关键帧之间的变化方式. usingUnityEngine; usingSystem.Collections; //速度调整 publicclassMover:MonoBehaviour{ publicfloatspeed=1f; publicVector3direction=Vector3.zero; publicAnimationCurveanimCurve; voidUpdate(){ TransformthisTransform=GetComponent thisTransform.position+=direction.normalized*speed*animCurve.Evaluate(Time.time)*Time.deltaTime; } } 在对象查看器中对其进行考察,单击查看器中的曲线,曲线编辑器可以作为一个单独的对话框显示,可以通过速度值控制中间帧. 曲线编辑器的水平轴表示时间(秒),垂直轴表示为速度值.用户可以在左下角的预制图生成初始曲线,并针对对象速度控制其插值计算,还可以在曲线上双击插入新的控制点,并对曲线加以控制,如果最新控制点使曲线产生了边角失去平滑特征,可以使用FreeSmooth 3.5利用协同程序旋转对象 编写一个脚本,缓慢平滑地旋转对象,并使其一直朝向目标对象. usingUnityEngine; usingSystem.Collections; [ExecuteInEditMode] publicclassLookAt:MonoBehaviour{ privateTransformthisTransform=null; publicTransformtarget=null; publicfloatrotateSpeed=100f; voidAwake(){ thisTransform=GetComponent } voidStart(){ StartCoroutine(TrackRotation(target)); } IEnumeratorTrackRotation(Transformtarget){ while(true){ if(thisTransform!=null&&target!=null){ Vector3relativePos=target.position-thisTransform.position; QuaternionnewRotation=Quaternion.LookRotation(RelativePos); thisTransform.rotation=Quaternion.RotateTowards(thisTransform.rotation,newRotation,rotateSpeed*Time.deltaTime); } yieldreturnnull; } } voidOnDrawGizmos(){ Gizmos.DrawLine(thisTransform.position,thisTransform.forward.normalized*5f); } } 协同程序工作方式与常规函数不同,IEnumerator返回类型可视为其特征,并至少包含一条yield语句.在程序重新执行后,协同程序可与其调用处理过程并行运行,这一点类似于线程或背景线程,即多任务机制,可与其他处理共同运行. 对动画而言,当其他处理过程运行时,可以实现动画效果并改变对象的属性. 3.6材质和贴图动画 需要通过编程方式调整或修改一段时间内网格顶点间的UV坐标,进而移动表面纹理.过程中不改变纹理内的像素,且映射至表面上的像素可实现动画效果.水流,岩浆,云朵,魔幻隧道的效果等等.
推荐阅读:
发表评论