用Unity3D也算是好久了,但是每次做项目总还是能学到新的东西。这次做一个TPS的项目就遇到了这样一个问题,如何同时在上下半身播放不同的动画?解决方法其实是很简单,但由于对于动画资源的了解不足导致问题不断,最后是彻彻底底的研究了一遍Unity3D的动画系统(Legacy),虽然4.0出了新的动画控制系统,使用了一下功能相比原来确实强大不少,但还是将这次对于原先的动画系统的学习总结记录下来,毕竟这些动画的概念与策略是通用的,而且因为4.0在mac上目前貌似还没有破解所以项目还是得在3.5上做。相信对于深入理解新的动画系统也会很有帮助。

一、Unity3D动画系统相关类

1.1 AnimationClip

AnimationClip是Unity3D中播放动画的最基本对象,通过FBX导入的各个动画对象其实就是一个AnimationClip。这个类已关键帧的形式记录了骨骼关节在各个时间节点上的位置、旋转信息,根据帧频率frameRate结合播放模式wrapMode通过插值计算即可播放出连续的骨骼动画。

1.2 AnimationState

每个AnimationState包含了一个AnimationClip,并记录这个动画片段的一些播放控制属性,实际上是一个AnimationClip的包装器。

其中比较重要的参数有layer,weight, enabled, speed, blendMode这几项。这些参数的具体含义将在自定义混合动画控制中详细解释,在简单的动画控制时并不需要对AnimationState进行直接操作。

1.3 Animation

Animation是Unity3D的动画播放控制组件,包含了一系列的AnimationState对象,提供各种动画播放及控制方法。常用方法有Play(), CrossFade(), Stop()。在脚本中通过animation即可直接引用同一物体上的Animation控件。

二、简单动画播放控制

所谓简单动画播放控制就是同一时间只有一个动作,比如Standard Assets中的那个水管工,静止idle,走walk,跑run,跳跃jump,攻击attack这些动作都是全身动作,同一时间只应该做一种动作,只有在动作切换时需要将两种切换动作进行混合以达到平滑过渡的效果,以上的操作使用Animation提供的CrossFade()方法即可达到。无论是CrossFade还是Play理论上都只需要在切换动画时调用一次即可,当然重复的调用并不会影响动画的播放,当Unity3D检测到当前播放的动画与函数调用使用的动画一样后会忽略该次调用。

三、自定义混合动画控制

3.1 多动画同时播放的需求

在大多数情况下简单的动画播放控制已经足够,然而当游戏变得复杂时,单动画播放带来的问题就是美术工作量的急剧增加。

最为典型的就是第三人称射击(动作)游戏,通常来说游戏中的人物会有各种上身动作如瞄准、射击、换子弹等,而下身则对应站立,行走(通常还是四个方向的行走动作)。这时候如果只能播放一个动作的话就需要美工制作大量的动作(站立瞄准、站立射击、跑步瞄准、跑步射击等等),其工作量可想而知。显然,最为效率的方式是美工分别做出上半身以及下半身的动作,然后由程序根据游戏角色的操作将两者动作混合起来同时播放。而这就涉及到了多动画同时播放的需求。此时简单的CrossFade()方法已经不能满足了,我们需要通过AnimationState来对动画播放进行自定义的控制。

3.2 使用AnimationState控制动画播放

Unity3D的动画播放实际上都是通过AnimationState来进行控制的,Animation组件中提供的CrossFade,Play等方法其实就是将一系列对AnimationState参数进行设置的操作进行了封装。

其中主要相关的参数有四个:

layer: 该动画片段(AnimationClip)所在的播放层次。

weight: 该动画片段在动画混合中所占的权重(0~1)

enable: 该动画片段是否进行播放

blendMode: 混合方式,有两种Blend和Additive

默认初始化情况下Animation组件中的全部AnimationState的layer=0,weight=0, enable=false。Animation组件默认播放的AnimationState的layer=0, weight=1, enable=true。

一、Unity3D动画播放策略

Unity3D在进行动画播放时按照下面的策略进行:

1.找到最高一层的全部AnimationState

2.将其中enable为true且weight > 0的AnimationState中的clip加入混合池(虚构的一个概念)

3.如果当前混合池中全部blendMode为Blend的clip的权重相加少于1,则找到下一层的全部AnimationState。重复2.

4.对混合池中的全部clip进行混合操作,生成最终的动作。

在进行最终混合时所有clip的实际权重会进行归一化处理,即相加为1,处理时根据blendMode的不同结果也会有所差异,下面的例子会进一步说明。

二、使用AnimationState控制播放的实例

举几个实际的例子对Unity3D的动画混合策略进行说明。对于AnimationState的设置全部放在Start或Awake中进行。并且注意把Animation组件中的默认播放动画设为None,取消选中Player Automatically,原因正如前文所述,默认播放的AnimationState参数初始值与其他State不同,会对实验造成影响。

1. 同一层动画的混合播放

AnimationState right= animation[“run_right”];

AnimationState idle= animation[“idle”];

right.layer = 1;right.weight = 1; right.enable = true;

idle = 1; idle.weight= 1; idle.enable = true;

运行结果是角色动画介于行走与静止之间,体现两个动画1:1的混合效果

2. 高层动画覆盖下层动画

right.layer = 1; right.weight = 1;right.enable = true;

idle = 0; idle.weight = 1; idle.enable = true;

运行结果是角色行走

3. 高层动画与下层动画混合

right.layer = 1; right.weight = 0.5f; right.enable = true;

idle = 0; idle.weight = 1; idle.enable = true;

运行结果与1相同,idle的实际weight为1 * (1 – 0.5f)

4. 使用Additive混合不同层动画

right.layer = 1; right.weight = 1; right.enable = true;

right.blendMode = BlendMode.Addictive;

idle = 0; idle.weight = 1; idle.enable = true;

运行结果与1相同,idle的实际weight为1/(1+1)

三、其他的动画播放控制参数

speed: 控制动画播放速度,比如调整射击速度就是将该值提高

time: 当前动画所在时间点

warpMode: 动画循环方式,有一次、循环、镜像循环PingPong

3.3 自定义动画过渡

动画过渡实际上就是两种动画混合权重的过渡,前一种动画的权重由1渐变为0,后一种由0变为1,由此实现动画的平滑过渡。在实际操作时,并不需要过渡时在Update()中每帧去调整两种动画AnimationState的权重weight。Animation控件提供了Blend()方法帮助在后台自动计算这种过渡,其使用方法与CrossFade类似,详见Unity3D的script手册。

3.4 Play(), CrossFade()背后的操作

了解这些基本方法背后进行的操作在同时使用AnimationState对动作进行控制时十分有用。

首先是Play(stringanimationName)(Play() = Play(default Animation name))这个方法实际上是将animationName所在层的全部其他AnimationState的weight置为0,enable置为false,将animationName的weight置为1, enable置为true。

CrossFade()与Play()大致相同,只不过他并不直接将其他的AnimationState的weight置为0,而是调用Blend()方法将其向0进行渐变,一旦该AnimationState的weight变为0再将其enable设置为false。

由此可见,当你设置了多层AnimationState后,仅仅调用这两个方法很可能并不能达到你想要的动画控制效果。当然,这两个方法最后有一个默认参数PlayMode来调整执行策略(区别就在于操作对象仅仅在该层还是全部AnimationState对象),总之这一节通过阐述Play与CrossFade背后的操作,希望使我们在使用AnimationState进行混合动画控制编程时能够正确的使用这两个方法以达到期望的效果。

3.5 局部动画

以上所介绍的AnimationState操作只是多动画的手动播放及混合控制,还并没有涉及到如何向开头所讲的上下半身播放不同的动画。要在同一个角色上同时播放两个不同的动作使用局部动画即可。

一、生成局部动画

在Unity3D中有两种方式实现局部动画,一是使用AnimationState的AddMixingTransform方法,该方法传入一个骨骼节点的Transform,调用后该动画片段AnimationClip便只会影响该节点及其子骨骼,而对其他骨骼关节并不再影响。

另一种方法是在动画模型制作时就只对局部的骨骼制作动画,其他骨骼在整个动画片段中都保持不变,这样生成的动画片段AnimationClip中就不会包括对那些不变骨骼的关键帧信息,也就不会对其他骨骼关节进行影响。(这是我根据动画播放的实际控制结果进行的推测,在Unity3D的官方文档中好像并没有直接说明,仍需查证)

了解第二种方法十分重要,虽然还只是推测。因为在与美术沟通前你可能并不知道导入的是一个局部动画,而将其当成全身动画,使得在进行动画混合控制时产生了意想不到的结果。我在一次项目中发现明明角色应该进入idle状态,但是双腿仍然在跑动,为此花了两天时间查证,也是直接促成了这篇文章的诞生,最终发现原来美术给的idle只有上半身有动画,下半身没有,因此虽然idle比跑动高一层,但下半身并不能覆盖。

二、局部动画的混合

局部动画的混合策略与前述Unity3D动画播放策略相同,只不过只是影响局部骨骼。这也就是说,上半身与下半身的动画无论谁所在的层更高,权重多少都不会影响另外半身的动画播放。但是上层的半身动画会覆盖下层的全身动画或与之混合,而全身动画中不包含在半身动画中的骨骼则完全不受影响。

四、射击类游戏应用

参考Unity3.5的官方例子Angry Robot。在这个例子中很好的实现了上下半身的独立旋转,射击动作与跑步动作的半身分离。这一节以此作为样例进行分析。

动作资源:

run_forward,fun_backward, run_left, run_right。四方向的跑动,全身动作,全部置于第1层。

Idle。静止,全身动作,位于第2层。

Attack。攻击,半身动作,位于第4层。混合方式Additive

操作控制:

初始化,全部动作的weight置为1,Attack的enable置为false,其余为true。这样初始状态下Attack不播放,Idle覆盖跑动动作,角色表现为静止站立动作。

移动时将Idle的weight根据速度向0渐变,开放跑动动作。使用CrossFade()在四个跑动动作中选择合适的动作进行播放。停止时再将Idle的weight逐渐置为1,重新覆盖跑动动作。

攻击时将Attack的enable置为true,停止攻击时置为false。由于Attack动作在最高层,且混合模式为Additive,因此站立攻击时Attack动作与行走动作上半身进行混合,跑动攻击时Attack动作与跑动动作上半身进行混合。

在Unity3D中控制动画播放相关推荐

  1. Unity3D 中 Generic 动画导入设置和 Root Motion 之间的关系

    Unity3D 的 Mecanim 动画系统可以直接复用 3DS MAX 中制作的动画文件中的位移,这个就是通过 applyRootMotion 来达成的,我们只需要在使用 Animator 控制动画 ...

  2. unity3d的Animation 动画播放器的基本API

    直接上代码: //动画名称 private const string ANIM_NAME = "Take 001"; //模型对象 private GameObject obj = ...

  3. CSS3中设置动画播放时间

    animation-duration主要用来设置CSS3动画播放时间,其使用方法和transition-duration类似,是用来指定元素播放动画所持续的时间长,也就是完成从0%到100%一次动画所 ...

  4. 【Unity3D】Animator动画播放时卡死在第一帧BUG系列

    常见因素: 1.Animator在Update或其他每帧执行的协程或方法里疯狂被代码调用. 2.Animator动画播放事件会再次调用Animator动画播放. 3.Animator状态机切换问题,A ...

  5. Unity3D总结记录(四) Unity中控制AudioSourse播放多条不同的声音文件

    Unity中,如果需要让播放声音,只需要给游戏对象添加AudioSourse组件即可,但,默认的组件中,仅支持一条音源的播放,如要实现多条音源的播放,可在代码中实现,具体方法如下: 首先在类中申请多个 ...

  6. Unity3D 控制动画播放暂停

    思路 通过记录当前播放位置,来实现动画的暂停播放. void Update(){if (Input.GetKeyUp(KeyCode.Space) && !pause){//Take ...

  7. Unity3d 中Legacy动画系统-剑圣的动画

    LoL中大家应该都玩过剑圣,其实很多技能以及动作都是根据动画截取出来的,今天我们就通过动画来实现剑圣的一些动作. 首先我们在场景中拖入模型,点击一下名字,右边Inspector面板会出来几个几个选项, ...

  8. 在网页中控制wmplayer播放器 (转载)

    详细参数可查询MSDN http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmplay/mmp_sdk/settings ...

  9. flash上制作一个按钮,控制动画播放、暂停

    8.0以前的版本,代码可以写在按钮上或帧上,9.0以上版本不管你用as2.0和3.0,代码只能写在帧上:按钮上的2.0 播放: on (release) {play(); } 暂停: on (rele ...

  10. unity3d 中控制手机前后摄像头切换

    闲话少说,上代码,google上搜来的代码,不过里面有bug,不能顺利切换,下面的代码是已经修改过的,经测试,可以正常运行. <pre class="css" name=&q ...

最新文章

  1. Python爬取京东商品
  2. zookeeper的设计猜想-Leader角色
  3. 微信跳一跳高分系列二:adb shell 中的常用命令
  4. 前端:Element UI 多选框组用法笔记
  5. java无穷大 inf_java – 为什么浮点数无穷大,不像NaN,等于?
  6. 充电速度公式_手机充电效率计算
  7. Attachments in Oracle Form
  8. Redis官方中文翻译系列 - Redis文档
  9. 三个月通过信息系统项目管理师经验帖(2021年11月,新鲜出炉,高项详解)
  10. RepMet: Representative-based metric learning for classification and few-shot object detection
  11. android res文件夹下values对应最全的本地化语言
  12. nagios的安装及nrpe的配置
  13. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day23】—— 算法1
  14. python创建模式对象_【python设计模式-创建型】单例模式
  15. bibtex 格式文件如何导入 Endnote
  16. halfstone 原理_躺在操场看天
  17. 笔试真题:100颗糖果,甲乙轮流从糖果盒中取出糖果,每次可取出2、4或6颗,若取得最后糖果的玩家为最终胜者,若甲先取z则(甲获胜,乙获胜,平局,不确定)
  18. 微信小程序自动化之miniprogram-automator快速上手
  19. 【第108期】技术大牛都在看的10本书,找到了
  20. 40vf什么意思_LED 的基本术语VF

热门文章

  1. 通过IP地址和子网掩码,如何计算出网络地址、广播地址和主机数?
  2. 航空公司客户价值数据的分析
  3. php 扫描条形码,将条形码扫描仪集成到PHP应用程序中?
  4. 99%用户不知道 搜索引擎这样用才有效率
  5. react axios封装
  6. MySQL大表优化方案
  7. Word引用参考文献
  8. 数学建模之Python-支持向量回归(SVM)
  9. 项目经理应该具备的四种能力
  10. android wifi控制手机屏幕,如何将手机屏幕无线投射到电脑 电脑反向控制手机屏幕的详细教程...