Unity3D使用Timeline实现过场动画
学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为2477字,预计阅读6分钟
前言
在《Unity3D使用Cinemachine配合Timeline实现运镜效果》一篇中我们已经实现了简单的运镜效果,这一篇还是利用TimeLine做动画,然后通过事件触发,实现一个过场动画的效果。
实现效果
从上图中我们可以看到,利用TimeLine做了两个动画效果,一个是进门的动画,一个是出门的动画,其中除了门打开,人物跑动进入和出去,还有Cinemachine实现的镜头切换。
创建项目
微卡智享
01
创建项目
新建了一个Unity3D的项目,我们直接在资源商店下载了两个免费资源Anime Character : Arisa (Free)和School assets
导入了学校的场景后,再把我们的人物也放入到场景之中,如上图显示。
02
设置触发事件的门
上图中我们找到要触发事件的门,然后在门上加了一个Text的显示,在门中找到对应的Cube后看其本身就是一个MeshCollider,在这个Cube上我们调整旋转中Y的值,改90或是-90就可以令门进行打开或是关闭,这样我们在做TimeLine时通过调整这个Cube的Y轴旋转即可实现开关门的效果了。
03
设置Cinemachine
新建一个空物体改名为Camera,然后在上面创建两个Cinemachine虚拟摄像机,其中CMPlayer绑定在人物下面的MainCamera中,并且设置为3rd Person Follow第三人称跟随。
CMMath的虚拟摄像机设置在进门后教室的位置,镜头的朝着门的方向看。
04
设置TimeLine动画
打开窗口里时间轴的界面,界面中创建一个空物体起名为TimeLine,然后在其下面再创建两个空物体分别是MathIn和MathOut,用于创建进门和出门的两个动画。
点击MathIn后在时间轴内点Create后,设置对应的保存目录及文件名,左边的时间轴就可以开始进行编辑了。
在MathIn里面开始编辑动画,上图中可以看到,我们先设置了Cinemathine的两个摄像机切换,然后Player的下面有两个动画,一个是人物的动作(分为平常动画和跑动动画),另一个是人物的位置移动。最后下面黄色框中说明的是我们的Cube_10也就是门的动画,这里就是通过修改其Y轴的旋转,实现开门和关门的效果。
完成这些动画的时间最关键的是上图中蓝框中关键帧的位置,也就是说是时间线,大概在多少帧做什么动作,每个动画前面的红色圆点点击后就是录制的功能,点开后设置其关键帧的位置后,设置对应的当前相关参数。
上面动图中可以看到设置Timeline的整个流程,这样我们就是把两个动画通过这样的方式完成了,时间轴上有一个播放按钮,如果开头的实现效果中的动画那样,在每次设置时都可以进行播放看看效果。
05
脚本编辑
上面的动画已经完成后,我们就可考虑到下一步怎么实现触发动画了,现在只做了一个门的触发,后面需要加上不能的教室播放不同的效果,所以这里播放动画的脚本应该挂载到人物身上,通过人物碰撞检测,用于判断播放哪个动画,进门和出门的动画因为不同,所以也要考虑到现在的状态是进门还是出门,用来判断播放不同的动画。
在Scripts脚本下创建了两个C#的脚本,一个是DoorController脚本控制碰撞时播放的动画,另一个PlayerStatus脚本用于处理判断人物进入的哪个门的状态。
PlayerStatus
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerStatus
{
public Dictionary<string, bool> classroom;
public PlayerStatus()
{
classroom = new Dictionary<string, bool>();
classroom.Add("Math", false);
}
}
里面加入一个为Dictionary<string, bool>的属性,在实例化时加入了数学Math的类,后面的bool值用于判断现在是在教室里还是教室外。
DoorController
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Playables;
public class DoorController : MonoBehaviour
{
private PlayerStatus status = null;
public List<Transform> timelines;
// Start is called before the first frame update
void Start()
{
status = new PlayerStatus();
//获取TimeLine下所有设置好的动画
GameObject go = GameObject.Find("TimeLine");
timelines = go.GetComponentsInChildren<Transform>(true).ToList();
}
private void OnCollisionEnter(Collision collision)
{
//获取到碰撞体的标签值
string tagname = collision.gameObject.tag;
string playname = string.Empty;
switch (tagname)
{
//当标签是数学,根据是否在教室内判断播放的动画
case "Math":
playname = status.classroom[tagname] ? "MathOut" : "MathIn";
break;
}
//判断是否可以播放TimeLine
if (!string.IsNullOrEmpty(playname))
{
StartCoroutine(PlayTimeLine(playname, tagname));
}
}
IEnumerator PlayTimeLine(string name,string tagname)
{
PlayableDirector director = timelines.Find(t => t.name == name).GetComponent<PlayableDirector>();
director.Play();
yield return new WaitForSeconds(2f);
//播放完后修改进屋状态
status.classroom[tagname] = !status.classroom[tagname];
}
}
DoorController中我们实例化了PlayerStatus,然后在Start()中把TimeLine中下面的PlayableDirctor都加载进来,在OnCollisionEnter事件中通过判断碰撞体的标签,对应PlayerStatus中的值来判断当前应该播放的动画,然后使用协程的方式进行在加载好的PlayableDirctor列表中找到对应的播放动画进行播放。播放完后再修改PlayerStatus的状态。
06
绑定脚本及触发
把我们编辑好的DoorController脚本添加到人物组件中。
然后在门的Cube_10的组件中标签页添加一个Math的标签,这个值和PlayerStatus类中的stirng值要一样,如果这里不设置的话,当人物碰撞到门的时候会什么也不触发。
这样就可以实现TimeLine过场动画的效果了,下面的实例操作视频。
完
扫描二维码
获取更多精彩
微卡智享
「 往期文章 」
Unity3D网络通讯(六)-- UnityWebRequest实现WebService通讯
- .Net中DES加密的细节问题
- 分布式监控系统Zabbix--完整安装记录 -添加web页面监控
- .Net中使用带UI的OCX的方法
- 2017数据科学领域15大热门GitHub项目
- 简单分页的性能优化
- Flash/Flex学习笔记(42):坐标旋转
- 分布式监控系统Zabbix-完整安装记录 -添加端口监控
- Flash/Flex学习笔记(40):弹性运动续--弹簧
- 表格样式—粗边框细表格线
- 分布式监控系统Zabbix--完整安装记录 -添加apache监控
- Flash/Flex学习笔记(38):缓动动画
- 把EmEditor改造成简单的Word
- centos7下FFmpeg环境部署记录
- Mac下使用rz、sz远程上传下载文件的配置记录
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- C++核心准则CP.111:如果真的需要好双重检查锁,使用惯用模式
- C++核心准则CP.200:使用volatile只能表明该变量是非C++内存
- C++核心准则E.2:通过抛出异常来表明函数无法执行指定的任务
- C++核心准则E.3:异常应该只用于错误处理
- [Go] GO语言实战-gin框架项目实现中英文切换
- [Go] Go语言实战-基于websocket浏览器通知的实现
- 快10年的老前端了,我还分不清 slice 和 splice,这到底是谁的锅
- 第4章 Jenkins系统用户认证配置管理
- 回答公众号留言的2个关于相关性分析的问题
- css 透明度和百分比对应值
- Qt项目DeskGirl开发
- 三日php之路 -- 第二,三天(php知识要点)
- GitLabRunner和流水线的数据采集与监控
- FPGA开源工具链
- 电脑软件(例如 Adobe、Autodesk)为什么那么容易被破解?