前言:FPS玩家和敌人最基本的功能,目前为止都写的差不多了。现在我们来优化一些敌人和玩家效果,本篇给敌人加一些动画控制。
敌人动画控制
Unity动画控制Animation、Animator和Animator controller2D 动画3D 动画
敌人动画控制获取Animation素材Animator controller动画切换Layer设计状态转换设计
添加Animator代码控制
效果
Unity动画控制
Animation、Animator和Animator controller
Unity动画控制关键在于理解Animation、Animator和Animator controller,搞懂三者关系和如何实现,对Unity基本的动画控制就没问题了。
Animation就是一个动画片段,例如说行走、跑步和攻击等动画。 可以通过在不同关键帧播放不同的图片,来实现动画,例如下面idle默认动画。
Animator是游戏中动画控制的一个组件,包含了Animator controller、Avatar、Apply Root Motion、Update Mode和Culling Mode等属性来控制动画。 Avatar:Unity的替身系统,主要是用来3D人体动画的复用,在骨骼、网格、动画、Avatar、材质贴图中有比较具体的介绍。 Apply Root Motion:有些动画会带有位移,勾选了带动画位移。 Update Mode:动画更新模式,Normal表示使用Update进行更新也就是fps同步、Animate Physics表示和fixed unpdate同步(物理检测)、Unscaled Time和Normal一样但是不考虑Time scale(游戏运行速度比例)。 Culling Mode:Cull剔除,也就是在摄像机视野外面的时候会做什么操作,Always Animate进行动画播放的更新、Cull Update Transform停止动画播放但是位置会继续更新、Cull Completely停止动画的所有更新。
其中Animator中比较重要的属性是Animator controller,是用来控制不同的Animation之间切换和叠加。主要有两个功能Layers和Parameters,Layers可以设置多层级动画叠加,Parameters则是设置参数进行转换。它是一个有限状态机,通过一些参数控制能够进行状态的切换。 例如下图中,实现从默认Idle状态切换到Jump状态,可以通过Bool参数ground为false来切换。
2D 动画
很早之前我写的Unity2D系列有提过动画控制,分别是博客为角色添加动画以及动画状态切换。 这两篇博客中有详细的2D动画制作到控制的具体细节。
2D动画可以通过不同帧播放不同的图片来实现,也可以通过骨骼动画来实现。 3D动画就骨骼动画实现了。
3D 动画
FPS系列开篇第一篇的时候,就对3D模型相关的内容做了基础入门讲解,Unity3D学习FPS游戏(1)获取素材、快速了解三维模型素材(骨骼、网格、动画、Avatar、材质贴图)。
通过该篇博客,可以对3D模型相关的预制体结构、骨骼、网格、材质贴图、Avatar还有动画有基本理解。
3D模型动画控制是通过骨骼动画来实现的,打开打开HoverRobot的一个Animation动画,可以发现骨骼动画中记录了每个时间点骨骼的变化。骨骼动画是通过移动模型中骨骼位置来实现的。 前面骨骼动画的原理中,动画和预制体中骨骼名字是一一对应的,但是不同的人做的模型骨骼名字会不同,这就导致动画也无法复用。于是就有了Avatar替身系统,主要针对常见的人形模型,可以把做好的模型骨骼都映射到人形Avatar中,这样不同模型都可以基于Avatar实现名字统一,从而实现动画复用。
敌人动画控制
获取Animation素材
3D模型的Animation通常不是我们程序做的,可以用素材现成提供好的。
在FPS-Animation-HoverBot中可以找到已经提供好的动画素材。 点击其中某一个Animation,右边的inspector可以预览动画的效果。
Animator controller动画切换
Layer设计
为什么需要设计Layer? 我们要先分好动画的Layer层级,该功能主要是用于动画的叠加,也就是有些动画是可以同时发生的。 举例,玩fps时候,可以边走路边持枪,实际上是走路和持枪动画的叠加。这种动画组合,常常会把走路Layer只控制脚,而持枪Layer只控制手臂,做Avatar Mask来防止动作互不干扰。这样美术就可以不用单独出一套动作。
如何设计Layer? 所以我们要区分一些,有些动画是可以叠加的。 想想那些动画是没有前后关联,主要是受伤和别的动作都没有前后关联。前面设计的时候敌人AI的时候,移动和攻击是有关联,攻击玩家时需要先停止移动。 是否受伤和移动攻击都没有关系, 所以我们可以分成两个个Layer,分别是Base以及Damaged(受伤)。
创建Animator controller 在Animation文件夹下,新建一个Animator controller命名为HoverBot_AnimatorController。 建两个个Layer,默认自带Base Layer,再新建一个Damaged Layer。
状态转换设计
分好了Layer,就要设置好每个Layer中动画状态的转换关系。 先确定有多少个状态,然后再去设计状态之间转换控制参数。
Base Layer 有三种状态,不动Idle、移动RunFoward以及攻击Shoot。 把对应的Animation拖到Base Layer中。 创建过渡:右键状态(State)模块,可以拉出过渡(Transition)箭头连接到别的状态模块。 三个状态之间都是可以互相过渡的状态。 添加Parameter进行过渡控制。 设置两个参数变量,进行控制分别是speed(float)和isShoot(bool)。 过渡规则:speed速度如果大于0.001就是跳到RunFoward状态,小于就跳出RunFoward状态;isShoot控制是否跳入Shoot状态。
Damaged Layer 先设置一下Damaged Layer的属性,通常需要设置的是Weight和Blending。 Weight决定该层级动画占多少权重和Blending决定和其它层动画混合模式。 Blending通常可以选择override(覆盖,覆盖上一层级的动画)和additive(添加,和上一层级动画进行融合)。 根据我们的需求,可以设置为Weight为0.7,Blending为additive。 两种状态,受伤Damage以及正常状态(可以用Null表示)。 右键新建一个空状态为Null作为默认的状态,然后再把Hurt动画拖入。 先分析一下需求。 这里和Base Layer最大不同在于,Hurt动画触发播放完就结束了。不会再有过渡控制回到Null,因为回到Null状态不是我们控制的,而是动画是否播放完毕。
创建过渡:
Hurt之后要连接到Exit状态,会自动回到Entry状态的,不用担心动画不会再触发(如果是子状态机的话,就是六边形符号里面的动画状态机Exit是退出了子状态机)Null过渡到Hurt
添加Parameter进行过渡控制。 整个状态机中,Null到Hurt只会触发一次,所以创建一个trigger类型的onHurt变量控制就行。 trigger和bool的区别在于,trigger触发是一次性事件触发,触发完立马回到未触发状态,而bool需要手动切换。
添加Animator
给HovertBot敌人挂载上Animator组件。 然后把HoverBot_AnimatorController拖入到Animator的AnimatorController中。 记得,挂载的是在Mesh模型那一级,不然没法绑定上网格。
代码控制
这里动画控制的逻辑不是很复杂,就放到Enemy Controller和EnemyWeaponController代码中了。但如果动画控制比较复杂,为了项目更好管理,会单独新建一个Script。
添加Animator变量
[Header("动画")]
public Animator anim;
由于Animator是在Controller挂载的代码下面一级的网格中挂载的,所以要用代码获取一下Animator。 Controller代码挂载在Enemy_HoverBot,但是Animator组件挂载在HoverBotMesh中,因为Animator使用了骨骼动画依附于骨骼。 在Awake或者Start代码部分加入下面代码,获取Animator。
anim = this.GetComponentInChildren
animator的控制主要依附控制前面设计三个Parameter,来完成动画之间的过渡。 通常控制的函数有SetFloat、SetInteger、SetBool和SetTrigger,根据变量类型,在有需要的地方使用就好了。
效果
动画状态随着代码控制Parameter进行了切换,并且敌人做出了不同动画。