当前位置: 首页 > news >正文

Unity3D之Legacy动画系统学习笔记

Unity3D的Mecanim动画系统是非常强大的,而且作为Unity推荐的动画系统,其未来会完全代替老的一套动画系统,即Legacy动画系统。目前的情况是Mecanim与Legacy两套动画系统同时共存,但是并不是说Legacy动画系统就没有任何价值了,作为Unity4.0以前使用的动画系统,我认为还是很有必要去了解和学习的,所以就有了这篇笔记。

Legacy动画系统

http://docs.unity3d.com/Manual/Animations.html

我们可以使用Unity自带的资源来学习老版本的动画系统,新建Unity3D项目,选择菜单“Assets”->“Import Package”->“Character Controller”,导入的资源里的那个小人就是使用Legacy动画系统的模型,我们的学习可以基于他来进行。

模型文件

在骨骼这一项中,我们发现动画类型的设置就是Legacy,说明这个模型使用的动画类型为老版本的动画系统。

我们再看看动画页:

动画页中,我们可以对动画剪辑进行编辑。

控制动画

我们直接将FBX文件拖入场景,Unity会自动帮我们添加Transform和Animation两个组件(注意Mecanim动画系统使用的是Animator组件,Legacy动画系统使用的是Animation组件)。

Animation组件的设置还是比较简单的:

  • Animation:当前播放的动画。
  • Animations:所有可以播放的动画。
  • Play Automatically:是否自动播放。
  • Animate Physics:动画是否和物理世界进行交互。
  • Culling Type:动画在不可见时是否还继续播放,优化选项默认即可。

点击播放按钮就可以看见动画正常播放了。

脚本控制

http://docs.unity3d.com/ScriptReference/Animation.html

下面我们来看看如何使用脚本控制动画的播放,我们将下面的脚本绑定到人物身上即可。

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class AnimationScript : MonoBehaviour
 5 {
 6     private Animation _animation;
 7 
 8     void Start()
 9     {
10         _animation = this.animation;
11     }
12     
13     void OnGUI()
14     {
15         //直接播放动画
16         if(GUI.Button(new Rect(0, 0, 100, 30), "idle"))
17         {
18             _animation.Play("idle");
19         }
20         if(GUI.Button(new Rect(100, 0, 100, 30), "walk"))
21         {
22             _animation.Play("walk");
23         }
24         if(GUI.Button(new Rect(200, 0, 100, 30), "run"))
25         {
26             _animation.Play("run");
27         }
28         if(GUI.Button(new Rect(300, 0, 100, 30), "jump_pose"))
29         {
30             _animation.Play("jump_pose");
31         }
32         //使用融合来播放动画
33         if(GUI.Button(new Rect(0, 30, 100, 30), "idle"))
34         {
35             _animation.CrossFade("idle");
36         }
37         if(GUI.Button(new Rect(100, 30, 100, 30), "walk"))
38         {
39             _animation.CrossFade("walk");
40         }
41         if(GUI.Button(new Rect(200, 30, 100, 30), "run"))
42         {
43             _animation.CrossFade("run");
44         }
45         if(GUI.Button(new Rect(300, 30, 100, 30), "jump_pose"))
46         {
47             _animation.CrossFade("jump_pose");
48         }
49     }
50 }

运行程序,会看见两排按钮,其中第一排按钮使用Play方法来切换动画,而第二排按钮则使用CrossFade来播放动画。

Play与CrossFade的区别

以从跑步切换到站立动画为例来看:

Play:直接切换动画,如果人物之前处于倾斜跑步状态,则会立即变成站立状态,表现上比较不真实,特别是当两个动画姿势差别较大时。

CrossFade:通过动画融合来切换动画,第二个参数可以指定融合的时间,如果人物之前处于倾斜跑步状态,则会在指定的融合时间内逐渐变成站立状态,表现上接近真实的人物动作切换效果。

但是当使用CrossFade播放跳跃动画时会出现问题,主要问题是跳跃动画不是循环播放且其持续时间小于动画融合的时间,我们修改为下面的脚本指定融合时间短一点就可以正常进行跳跃的融合播放了:

_animation.CrossFade("jump_pose", 0.1f);

PlayQueued

该方法可以指定当当前的动画播放完毕后接下来播放的动画,如下:

_animation.PlayQueued("run", QueueMode.CompleteOthers, PlayMode.StopSameLayer);

文件格式和资源加载

我们的模型使用通用的FBX格式,那么动画文件的储存一般有两种情况,一是所有的动画和模型都一起存放到一个文件中,还有一种情况是模型单独一个文件而动画单独一个文件。

模型动画都存放在一个文件中的情况

类似于Unity提供的Character Controller中的资源就是这样的结构,一个FBX文件保存了模型、骨骼和动画:

Resources加载

我们直接加载该资源就可以直接使用,将下面的脚本绑定到摄像机即可,脚本如下:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class AllInOneResourcesLoad : MonoBehaviour
 5 {
 6     private Animation _animation;
 7 
 8     void Start()
 9     {
10         GameObject go = Resources.Load<GameObject>("Standard Assets/Character Controllers/Sources/PrototypeCharacter/Constructor");
11 
12         GameObject man = Instantiate(go) as GameObject;
13         _animation = man.animation;
14     }
15 
16     void OnGUI()
17     {
18         //直接播放动画
19         if(GUI.Button(new Rect(0, 0, 100, 30), "idle"))
20         {
21             _animation.Play("idle");
22         }
23         if(GUI.Button(new Rect(100, 0, 100, 30), "walk"))
24         {
25             _animation.Play("walk");
26         }
27         if(GUI.Button(new Rect(200, 0, 100, 30), "run"))
28         {
29             _animation.Play("run");
30         }
31         if(GUI.Button(new Rect(300, 0, 100, 30), "jump_pose"))
32         {
33             _animation.Play("jump_pose");
34         }
35         //使用融合来播放动画
36         if(GUI.Button(new Rect(0, 30, 100, 30), "idle"))
37         {
38             _animation.CrossFade("idle");
39         }
40         if(GUI.Button(new Rect(100, 30, 100, 30), "walk"))
41         {
42             _animation.CrossFade("walk");
43         }
44         if(GUI.Button(new Rect(200, 30, 100, 30), "run"))
45         {
46             _animation.CrossFade("run");
47         }
48         if(GUI.Button(new Rect(300, 30, 100, 30), "jump_pose"))
49         {
50             _animation.CrossFade("jump_pose", 0.1f);
51         }
52     }
53 }

AssetBundle加载

打包

使用下面的脚本打包:

 1 using UnityEditor;
 2 using UnityEngine;
 3 
 4 public class CreateAllInOneAB
 5 {
 6     [MenuItem("Tool/CreateAllInOneAB")]
 7     private static void Create()
 8     {
 9         BuildPipeline.BuildAssetBundle(null, new[]
10             {
11                 AssetDatabase.LoadAssetAtPath("Assets/Resources/Standard Assets/Character Controllers/Sources/PrototypeCharacter/Constructor.FBX", typeof(GameObject))
12             },
13             Application.streamingAssetsPath + "/AllInOne.assetbundle", 
14             BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.UncompressedAssetBundle, 
15             BuildTarget.StandaloneWindows64);
16     }
17 }

加载

将下面的脚本绑定到摄像机即可:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class AllInOneAssetBundleLoad : MonoBehaviour
 5 {
 6     private Animation _animation;
 7 
 8 
 9     void Start()
10     {
11         AssetBundle assetBundle = AssetBundle.CreateFromFile(Application.streamingAssetsPath + "/AllInOne.assetbundle");
12 
13         GameObject go = assetBundle.Load("Constructor", typeof(GameObject)) as GameObject;
14 
15         GameObject man = Instantiate(go) as GameObject;
16         _animation = man.animation;
17     }
18 
19     void OnGUI()
20     {
21         //直接播放动画
22         if(GUI.Button(new Rect(0, 0, 100, 30), "idle"))
23         {
24             _animation.Play("idle");
25         }
26         if(GUI.Button(new Rect(100, 0, 100, 30), "walk"))
27         {
28             _animation.Play("walk");
29         }
30         if(GUI.Button(new Rect(200, 0, 100, 30), "run"))
31         {
32             _animation.Play("run");
33         }
34         if(GUI.Button(new Rect(300, 0, 100, 30), "jump_pose"))
35         {
36             _animation.Play("jump_pose");
37         }
38         //使用融合来播放动画
39         if(GUI.Button(new Rect(0, 30, 100, 30), "idle"))
40         {
41             _animation.CrossFade("idle");
42         }
43         if(GUI.Button(new Rect(100, 30, 100, 30), "walk"))
44         {
45             _animation.CrossFade("walk");
46         }
47         if(GUI.Button(new Rect(200, 30, 100, 30), "run"))
48         {
49             _animation.CrossFade("run");
50         }
51         if(GUI.Button(new Rect(300, 30, 100, 30), "jump_pose"))
52         {
53             _animation.CrossFade("jump_pose", 0.1f);
54         }
55     }
56 }

模型动画分开存放的情况

还有一种情况是模型和动画是分为多个FBX文件存放的,比如下面是模型文件:

虽然有一个Take 001的动画,但是实际上我们并不使用该动画,而是使用下面仅保存了动画的FBX文件:

Resources加载

首先我们要清楚的是,无论是保存了模型还是保存了动画的FBX文件在Unity看来都是同样的一种类型,即添加了Animation组件的GameObject,下面我们看看如何在Resources中加载并显示这个角色,代码如下,挂载到主摄像机即可:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class ResourcesLoad : MonoBehaviour
 5 {
 6     private Animation _animation;
 7 
 8     void Start()
 9     {
10         GameObject go = Resources.Load<GameObject>("ZombieNurse/Zombienurse_Rig");
11 
12         GameObject man = Instantiate(go) as GameObject;
13         _animation = man.animation;
14 
15         //添加动画剪辑
16         _animation.AddClip(LoadAnimationClip("ZombieNurse/Animation/Zombienurse@attack"), "attack");
17         _animation.AddClip(LoadAnimationClip("ZombieNurse/Animation/Zombienurse@death"), "death");
18         _animation.AddClip(LoadAnimationClip("ZombieNurse/Animation/Zombienurse@idle"), "idle");
19         _animation.AddClip(LoadAnimationClip("ZombieNurse/Animation/Zombienurse@run"), "run");
20 
21         _animation.Play("idle");
22     }
23 
24     private AnimationClip LoadAnimationClip(string path)
25     {
26         GameObject go = Resources.Load<GameObject>(path);
27         return go.animation.clip;
28     }
29 
30     void OnGUI()
31     {
32         if(GUI.Button(new Rect(0, 0, 100, 30), "idle"))
33         {
34             _animation.CrossFade("idle");
35         }
36         if(GUI.Button(new Rect(100, 0, 100, 30), "run"))
37         {
38             _animation.CrossFade("run");
39         }
40         if(GUI.Button(new Rect(200, 0, 100, 30), "attack"))
41         {
42             _animation.CrossFade("attack");
43         }
44         if(GUI.Button(new Rect(300, 0, 100, 30), "death"))
45         {
46             _animation.CrossFade("death");
47         }
48     }
49 }

AssetBundle加载

打包

使用下面的脚本打包:

 1 using UnityEngine;
 2 using UnityEditor;
 3 
 4 public class CreateAB : MonoBehaviour
 5 {
 6     [MenuItem("Tool/CreateAB")]
 7     private static void Create()
 8     {
 9         BuildPipeline.BuildAssetBundle(null, new[]
10             {
11                 AssetDatabase.LoadAssetAtPath("Assets/Resources/ZombieNurse/Zombienurse_Rig.FBX", typeof(GameObject)),
12                 AssetDatabase.LoadAssetAtPath("Assets/Resources/ZombieNurse/Animation/Zombienurse@attack.FBX", typeof(GameObject)),
13                 AssetDatabase.LoadAssetAtPath("Assets/Resources/ZombieNurse/Animation/Zombienurse@death.FBX", typeof(GameObject)),
14                 AssetDatabase.LoadAssetAtPath("Assets/Resources/ZombieNurse/Animation/Zombienurse@idle.FBX", typeof(GameObject)),
15                 AssetDatabase.LoadAssetAtPath("Assets/Resources/ZombieNurse/Animation/Zombienurse@run.FBX", typeof(GameObject))
16             },
17             Application.streamingAssetsPath + "/AB.assetbundle",
18             BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.UncompressedAssetBundle,
19             BuildTarget.StandaloneWindows64);
20     }
21 }

加载

将下面的脚本绑定到摄像机即可:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 public class AssetBundleLoad : MonoBehaviour
 5 {
 6     private Animation _animation;
 7 
 8     void Start()
 9     {
10         AssetBundle assetBundle = AssetBundle.CreateFromFile(Application.streamingAssetsPath + "/AB.assetbundle");
11 
12         GameObject go = assetBundle.Load("Zombienurse_Rig", typeof(GameObject)) as GameObject;
13 
14         GameObject man = Instantiate(go) as GameObject;
15         _animation = man.animation;
16 
17         //添加动画剪辑
18         _animation.AddClip(LoadAnimationClip(assetBundle, "Zombienurse@attack"), "attack");
19         _animation.AddClip(LoadAnimationClip(assetBundle, "Zombienurse@death"), "death");
20         _animation.AddClip(LoadAnimationClip(assetBundle, "Zombienurse@idle"), "idle");
21         _animation.AddClip(LoadAnimationClip(assetBundle, "Zombienurse@run"), "run");
22 
23         _animation.Play("idle");
24     }
25 
26     private AnimationClip LoadAnimationClip(AssetBundle assetBundle, string path)
27     {
28         GameObject go = assetBundle.Load(path, typeof(GameObject)) as GameObject;
29         return go.animation.clip;
30     }
31 
32     void OnGUI()
33     {
34         if(GUI.Button(new Rect(0, 0, 100, 30), "idle"))
35         {
36             _animation.CrossFade("idle");
37         }
38         if(GUI.Button(new Rect(100, 0, 100, 30), "run"))
39         {
40             _animation.CrossFade("run");
41         }
42         if(GUI.Button(new Rect(200, 0, 100, 30), "attack"))
43         {
44             _animation.CrossFade("attack");
45         }
46         if(GUI.Button(new Rect(300, 0, 100, 30), "death"))
47         {
48             _animation.CrossFade("death");
49         }
50     }
51 }

 

相关文章:

  • 联想关键业务服务器 sysytem X3850 X6 4U机架式服务器
  • mysql 字符集乱码及解决方案
  • android搜索框列表布局,流程及主要步骤思维导图
  • gcc介绍及安装
  • java 中获得 资源文件方法
  • IF
  • oracle导出、导入的一次实战
  • hadoop集群管理系统搭建规划说明
  • wsdl自动生成Java代码,根据wsdl生成Java代码
  • 企业上云之机房和BGP带宽篇(三)
  • ios导航栏自定义返回按钮后,多出蓝点bug
  • 云盘关闭,教你用蒲公英搭建私有云
  • 显示MYSQL数据库信息
  • 1024程序员节,想讲下我盾这帮安全技术人的故事
  • (二)斐波那契Fabonacci函数
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • angular组件开发
  • HomeBrew常规使用教程
  • Kibana配置logstash,报表一体化
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • python学习笔记 - ThreadLocal
  • V4L2视频输入框架概述
  • vue-cli3搭建项目
  • webgl (原生)基础入门指南【一】
  • 前端面试之CSS3新特性
  • 前端之Sass/Scss实战笔记
  • 时间复杂度与空间复杂度分析
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • 异常机制详解
  • 走向全栈之MongoDB的使用
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 数据可视化之下发图实践
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • #Z0458. 树的中心2
  • (13)Hive调优——动态分区导致的小文件问题
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • .net Application的目录
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET Framework .NET Core与 .NET 的区别
  • .NET 发展历程
  • .Net 高效开发之不可错过的实用工具
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET 使用配置文件
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .NET企业级应用架构设计系列之应用服务器
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [] 与 [[]], -gt 与 > 的比较
  • [AIGC codze] Kafka 的 rebalance 机制
  • [android]-如何在向服务器发送request时附加已保存的cookie数据
  • [BeginCTF]真龙之力
  • [DM复习]关联规则挖掘(下)