学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为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值要一样,如果这里不设置的话,当人物碰撞到门的时候会什么也不触发。