用Timeline實(shí)現(xiàn)動(dòng)畫(huà)特寫(xiě)(下)

作者:Truly
大渣好。說(shuō)書(shū)人放了無(wú)窮久的鴿子之后又回來(lái)了。

書(shū)接上一回,上一篇介紹了Timeline的部分基礎(chǔ)知識(shí),并實(shí)現(xiàn)了主角的動(dòng)畫(huà)播放,本篇將接著把剩余的功能實(shí)現(xiàn)。本篇主要介紹實(shí)現(xiàn)的方法,具體的手感參數(shù)還需小伙伴們根據(jù)自己的動(dòng)畫(huà)慢慢調(diào)哦(體力活)。與格擋結(jié)合后效果圖如下:

本篇實(shí)現(xiàn)功能:
1.Timeline控制角色位移
2.切換特寫(xiě)鏡頭
3.觸發(fā)鏡頭抖動(dòng)和播放粒子特效
4.子彈時(shí)間
5.動(dòng)態(tài)綁定軌道對(duì)象(Binding)
本文不包含格擋與切割內(nèi)容,有興趣的小伙伴自行參考底部鏈接。
一、Timeline Signals
Unity 2019.1版本推出了Timeline Signals功能,具有“廣播”特點(diǎn),幫助發(fā)送事件。接下來(lái)將通過(guò)實(shí)現(xiàn)部分功能來(lái)熟悉Timeline Signals。
概念速覽:
1.Signal Emitter(信號(hào)發(fā)射器)
信號(hào)發(fā)射器會(huì)放在Timeline上,它包含對(duì)信號(hào)資源的引用。如果當(dāng)前播放時(shí)間點(diǎn)比發(fā)射器所在的時(shí)間點(diǎn)后,發(fā)射器會(huì)把信號(hào)資源發(fā)送到信號(hào)接收器。
(1)添加:對(duì)應(yīng)Track右鍵 -> Add Signal Emitter

(2)Signal Emitter面板簡(jiǎn)介

Retroactive: 開(kāi)始播放時(shí)的進(jìn)度位置在發(fā)射器后也能回溯觸發(fā)。
Emit Once:循環(huán)播放時(shí)只觸發(fā)一次。
Create Signal:新建信號(hào)資源。
Add Signal Receiver:添加信號(hào)接收器。
2.Signal Asset(信號(hào)資源)
信號(hào)資源是發(fā)射器和接收器之間的聯(lián)系。通常信號(hào)資源會(huì)用作標(biāo)識(shí)符。
已有Signal信號(hào)資源時(shí),新建或切換Signal如下圖:

3.Signal Receiver(信號(hào)接收器)
當(dāng)接收器知道信號(hào)已被觸發(fā)時(shí),它會(huì)激活關(guān)聯(lián)到對(duì)應(yīng)信號(hào)資源的反應(yīng)。Signal Receiver會(huì)自動(dòng)添加到綁定對(duì)象(軌道左側(cè))上。添加信號(hào)反應(yīng)操作如下圖:

大概邏輯:播放到信號(hào)發(fā)射器處 -> 發(fā)射信號(hào) -> 對(duì)應(yīng)信號(hào)的接收器激活反應(yīng)
此外,還可以通過(guò)編寫(xiě)Marker腳本自定義標(biāo)記,有興趣的小伙伴自行了解。
二、設(shè)置被擊退位移
上一篇結(jié)尾“組合”出敵人被擊退的動(dòng)畫(huà),現(xiàn)在開(kāi)始通過(guò)Transform Tween Track和Signals設(shè)置擊退的位移。(也可以通過(guò)點(diǎn)擊小紅點(diǎn)錄制實(shí)現(xiàn)位移)
Ps:本文命名只是為了增加辨識(shí)度,無(wú)其他特殊含義。
1.添加Transform Tween Track
(1)添加Track:Timeline編輯器空白處右鍵 >?Transform Tween Track,命名為ETransformTrack。(Inspector窗口可重命名)
(2)添加Clip:右鍵該Track >?Add Transform Tween Clip,命名為BackTransClip。
(3)用Track Group(空白處右鍵)把主角和敵人的軌道分別裝起來(lái),便于整理。

(4)Transform Tween Clip部分屬性簡(jiǎn)介:

Tween Positon:是否轉(zhuǎn)換Position。
Tween Rotation:是否轉(zhuǎn)換Rotation。
Twee Type(轉(zhuǎn)換類型):Linear線性勻速、Deceleration減速、Harmonic(中間最快)、Custiom自定義。
Start Location:Clip起始的Transform。
End Location:Clip結(jié)束的Transform。
(5)給所有軌道左側(cè)綁定框拖進(jìn)對(duì)應(yīng)的對(duì)象。
2.設(shè)置Transform Tween Track
在敵人被攻擊的時(shí)候,通過(guò)給Start Location和End Location賦值來(lái)實(shí)現(xiàn)擊退位移動(dòng)。
(1)方法一(速覽即可):腳本中通過(guò)層層遍歷找到Location,然后為其賦值,有興趣的小伙伴自行研究。 大概思路如下:

(2)方法二(本文粗暴做法):
①在主角里新建一個(gè)空的GameObject,命名為KickEndTrans,作為敵人被擊退位移結(jié)束的Transform參考。
②另外在Hierarchy再建一個(gè)空的GameObject,命名為T(mén)empKickEndTrans,拖進(jìn)BackTransClip的End Location。

③播放BackTransClip(Transform Tween Clip)前通過(guò)Signal調(diào)用方法,把TempKickEndTrans置到KickEndTrans的方位上,達(dá)到設(shè)置End Location的效果。(Start Location也如此設(shè)置)
代碼如下:
? ??/// <summary>????/// 設(shè)置敵人被擊退后的Transform????/// </summary>????public?void?OnSignal_SetKickEndTrans()
????{???????
????????//開(kāi)始時(shí)敵人Transform????????tempTargetTrans.position?=?cPlayer.targetTrans.position;// cPlayer.targetTrans為當(dāng)前敵人Transform????????tempTargetTrans.rotation?=?cPlayer.targetTrans.rotation;
????????//結(jié)束時(shí)敵人Transform????????tempKickEndTrans.rotation?=?kickEndTrans.rotation;
????????tempKickEndTrans.position?=?kickEndTrans.position;
????}
?
④使用Signal調(diào)用方法:
新建一個(gè)Signal Track,在開(kāi)始擊退前的位置添加Signal Emitter,添加信號(hào),命名為Kick。

Hierarchy中新建一個(gè)空對(duì)象,命名為SignalFunctions,拖進(jìn)Signal Track左側(cè)綁定框,在SignalFunctions的Inspector窗口可以看到自動(dòng)添加的Signal Receiver。
在Signal Receiver中選擇對(duì)應(yīng)信號(hào),點(diǎn)擊“+”添加反應(yīng),然后把方法所在對(duì)象拖進(jìn)Reaction里,最后選擇需要調(diào)用的方法。操作如圖:

位移效果:

以上便是用Signal和Transform Tween Track 設(shè)置位移的粗暴做法,其他位移也可以如此設(shè)置,參數(shù)還需小伙伴們根據(jù)自己的動(dòng)畫(huà)具體情況具體分析。
三、鏡頭切換
鏡頭的切換主要是通過(guò)Cinemachine Track與Cinemachine配合完成的。
(1)基本概念
Cinemachine核心組件包括Brain和Virtual Camera(虛擬相機(jī)):
Brain:負(fù)責(zé)相機(jī)的切換。
Virtual Camera(虛擬相機(jī)):負(fù)責(zé)拍攝。
Cinemachine提供了一些預(yù)設(shè)好行為方案,方便我們實(shí)現(xiàn)游戲中的功能。這次工程軌道中主要使用了Target Group Camera?和普通的Virtrual Camera,另外Timeline播放前人物用的是Free Look Camera(非本文主要介紹范圍)。
Target Group Camera:可以在多個(gè)拍攝目標(biāo)之間設(shè)置焦點(diǎn),通過(guò)權(quán)重調(diào)節(jié)焦點(diǎn)偏移。
Virtrual Camera:普通的相機(jī)。
Free Look Camera:允許玩家控制并圍繞目標(biāo)旋轉(zhuǎn)的相機(jī),可以用作第三人稱相機(jī)。

(2)設(shè)置Target Group Camera
腳踢敵人過(guò)程中使用的是Target Group Camera?,以主角和敵人綜合得出拍攝焦點(diǎn)。
①添加Target Group Camera后,Hierarchy窗口會(huì)出現(xiàn)一個(gè)CM vcam和一個(gè)對(duì)應(yīng)的TargetGroup。關(guān)系如下圖:

②調(diào)節(jié)TargetGroup
拍攝焦點(diǎn)通過(guò)目標(biāo)、對(duì)應(yīng)的權(quán)重以及半徑綜合得出。
Target:拍攝目標(biāo),本工程把玩家身上的攝像參考點(diǎn)拖進(jìn)第一個(gè)參數(shù)框,通過(guò)腳本把敵人的Transform放進(jìn)第二個(gè)參數(shù)框。
Weight:權(quán)重,用于調(diào)節(jié)焦點(diǎn)的偏移。
Radius:半徑,用于調(diào)節(jié)相機(jī)距離。

在腳本中把敵人的Transform賦值給Target屬性第二個(gè)參數(shù)框,代碼如下(在播Timeline前調(diào)用),需要using Cinemachine;
? ?using?Cinemachine;
???//...????/// <summary>????/// Timeline開(kāi)始前設(shè)置Trans????/// </summary>????public?void?SetTransBeforeTL()
????{
????????if?(cPlayer.targetTrans)
????????{
????????????//把敵人Trans賦值到Target Group組件里Target的第二個(gè)參數(shù)????????????targetGroup.m_Targets[1].target?=?cPlayer.targetTrans;??
????????????//...????????}
????}
?
(3)設(shè)置Cinemachine Track
①添加Track:Timeline編輯窗口空白處 > 右鍵 > Cinemachine Track。
②把Main Camera拖進(jìn)左側(cè)綁定框。
③添加Clip:把所需的cinemachine拖進(jìn)軌道,按需排序和混合即可,播放時(shí)會(huì)隨著進(jìn)度自動(dòng)切換,重疊處會(huì)自動(dòng)過(guò)渡。

本工程的切換順序(僅供參考):Free Look Camera(起始過(guò)渡) >?Target Group Camera (腳踢過(guò)程)> Virtrual Camera(跳劈時(shí)在頭頂)?> Free Look Camera
四、觸發(fā)鏡頭抖動(dòng)與播放粒子特效
1.屏幕抖動(dòng)
(1)需要用到的組件:
①Cinemachine Impulse Source:發(fā)出抖動(dòng)信號(hào)。
②Cinemachine Impulse Listener:收到信號(hào),則鏡頭抖動(dòng)。
(2)在Main Camera中添加Cinemachine Impulse Source組件:Inspector > Add Component >?Cinemachine Impulse Source。

部分屬性:
Raw Signal:原始信號(hào),可理解為抖動(dòng)類型。使用Unity提供的信號(hào)類型:右側(cè)齒輪 > Persets?> 選擇需要類型。
Amplitude Gain:振幅增益。
Frequency Gain:頻率增益。
Impact Radius:影響半徑。
(3)在需要抖動(dòng)的Virtual Camera中添加Cinemachine Impulse Listener:
Inspector > Cinemachine 組件(底部)>?Add Extension > CinemachineImpulseListener。

2.粒子特效播放方法
在命中敵人的位置添加粒子特效,然后腳本中獲取粒子特效,最后在方法中調(diào)用Play()播放。
? ??public?ParticleSystem?hitRed_Kick;
????/// <summary>????/// Kick特效????/// </summary>????public?void?OnSignal_SetKickEffect()
????{
????????hitRed_Kick.Play();
????}
?
3.在攻擊命中敵人的時(shí)候,通過(guò)Signal Receiver來(lái)觸發(fā)鏡頭抖動(dòng)和調(diào)用特效播放方法。
發(fā)出信號(hào)方法:CinemachineImpulseSource.GenerateImpulse();

五、子彈時(shí)間
本次是通過(guò)調(diào)節(jié)時(shí)間的縮放來(lái)實(shí)現(xiàn)子彈時(shí)間。
1.添加Time Dilation Track。
2.添加Time Dilation Clip。部分屬性:
Time Scale:時(shí)間縮放比例,1為正常時(shí)間,0為靜止。
Blend Curves:混合曲線。

3.調(diào)節(jié)思路
(1)創(chuàng)建兩個(gè)Time Dilation Clip:一個(gè)Time Scale為0,另一個(gè)Time Scale為1。(參數(shù)自行調(diào)節(jié))
(2)把連個(gè)Clip重疊起來(lái),通過(guò)調(diào)節(jié)Clip重疊長(zhǎng)度和混合曲線,達(dá)到自己想要的效果。

六、動(dòng)態(tài)綁定軌道對(duì)象
終結(jié)不同的敵人代表著動(dòng)畫(huà)的執(zhí)行角色不同,因此需要在腳本中為軌道更換綁定的目標(biāo)。
1.添加事件
(1)相關(guān)變量:
using?System.Collections;using?System.Collections.Generic;using?UnityEngine;using?UnityEngine.Playables;using?UnityEngine.Timeline;
public?class?PAnimation?:?MonoBehaviour{
????CPlayer?cPlayer;
????PSlicer?pSlicer;????????????????????????????????????????//切割腳本
????Animator?animator;????????????????????????????????????????????????
????Animator?targetAnimator;
?
????RuntimeAnimatorController?player_AC;????????????????????//記錄玩家AnimatorController????RuntimeAnimatorController?target_AC;????????????????????//記錄目標(biāo)AnimatorController
????public?PlayableDirector?playableDirector;???????????????//TimelineDirector;????public?TimelineAsset?tL_StrikeBack;?????????????????????//反擊的TimelineAsset
????//信號(hào)相關(guān)????SignalFunctions?signalFunctions;????????????????????????//信號(hào)方法腳本????Dictionary<string,?PlayableBinding>?bindingDict;????????//存儲(chǔ)????//...}
?
(2)事件
①PlayableDirector.played:在PlayableDirector 開(kāi)始播放時(shí)調(diào)用。
②PlayableDirector.stopped:在PlayableDirector停止播放時(shí)調(diào)用。
? ??void?Start()
????{
???????// ...????????//添加事件????????playableDirector.played?+=?OnPlayableDirectorStart;?????//開(kāi)播時(shí)執(zhí)行????????playableDirector.stopped?+=?OnPlayableDirectorStopped;??//停播時(shí)執(zhí)行????}
?
2.釋放技能時(shí):
(1)指定播放片段(TimelineAsset)。
? ??public?void?PlayTimeline()
????{
????????//指定TimelineAsset(播放片段)????????playableDirector.playableAsset?=?tL_StrikeBack;?
????????//儲(chǔ)存Binding????????SaveBindings();
????????playableDirector.Play();
????}
?
(2)用字典儲(chǔ)存每個(gè)軌道:PlayableBinding.streamName 獲取軌道名字,作為字典的Key。

代碼如下(需要using UnityEngine.Playables;和using UnityEngine.Timeline;):
using?UnityEngine.Playables;using?UnityEngine.Timeline;//...?//儲(chǔ)存綁定的Track左側(cè),換新TimelineAsset時(shí)調(diào)用????public?void?SaveBindings()
????{
????????foreach?(PlayableBinding?binding?in?playableDirector.playableAsset.outputs)
????????{
????????????if?(!bindingDict.ContainsKey(binding.streamName))
????????????{
????????????????bindingDict.Add(binding.streamName,?binding);
????????????}
????????}??????
????}
?
3.Timeline播放前
(1)置空AnimatorController避免播放TimeLine過(guò)程中執(zhí)行其他狀態(tài)。(也可在動(dòng)畫(huà)狀態(tài)機(jī)中添加表示正在播放Timeline的狀態(tài)來(lái)解決)
(2)通過(guò)檢索字典給軌道綁定對(duì)象:
綁定軌道左側(cè)對(duì)象:PlayableDirector.GetGenericBinding(Object key, Object value);。
Key:可用PlayableBinding.sourceObject獲取。
Value:需要綁定的對(duì)象。
代碼如下(含注釋):
/// <summary>????/// 播放前執(zhí)行????/// </summary>????/// <param name="aDirector"></param>????void?OnPlayableDirectorStart(PlayableDirector?aDirector)
????{
????????cPlayer.characterController.enabled?=?false;????//關(guān)閉CharacterController,不然有沖突 ??????????animator.applyRootMotion?=?true;????????????????//應(yīng)用RootMotion??????
????????//暫存AnimatorController????????player_AC?=?animator.runtimeAnimatorController;
????????//把AnimatorController暫時(shí)置空,避免播Timeline時(shí)動(dòng)畫(huà)狀態(tài)機(jī)還在執(zhí)行其他狀態(tài)。????????animator.runtimeAnimatorController?=?null;
?
????????//敵人AnimatorController暫時(shí)置空,播完置回去。????????targetAnimator?=?cPlayer.targetTrans.GetComponent<Animator>();
????????target_AC?=?targetAnimator.runtimeAnimatorController;
????????targetAnimator.runtimeAnimatorController?=?null;??????
?
????????//把玩家Animator綁進(jìn)軌道????????playableDirector.SetGenericBinding(bindingDict["PlayerAniTrack"].sourceObject,?animator);
????????playableDirector.SetGenericBinding(bindingDict["PTransformTrack"].sourceObject,?animator.transform);
????????//把敵人Animator綁進(jìn)軌道????????playableDirector.SetGenericBinding(bindingDict["EnemyAniTrack"].sourceObject,?cPlayer.targetTrans.GetComponent<Animator>());
????????playableDirector.SetGenericBinding(bindingDict["ETransformTrack"].sourceObject,?cPlayer.targetTrans);
????????//Clip 參考Trans設(shè)置????????signalFunctions.SetTransBeforeTL();
????}
?
4.動(dòng)畫(huà)播放完后,用PlayableDirector.Evaluate()估算Timeline中各對(duì)象,否則會(huì)回到開(kāi)播的位置,然后把播放的TimelineAsset置為null。代碼如下(含注釋):
/// <summary>????/// 播放完執(zhí)行????/// </summary>????/// <param name="aDirector"></param>????void?OnPlayableDirectorStopped(PlayableDirector?aDirector)
????{
????????playableDirector.Evaluate();????????????//評(píng)估對(duì)象所在位置,否則回到播放前位置????????playableDirector.playableAsset?=?null;??//playableDirector里的TimlineAsset置Null
????????//重置玩家播放Timeline前的狀態(tài)????????cPlayer.characterController.enabled?=?true;
????????cPlayer.isStrikingBack?=?false;
????????animator.applyRootMotion?=?false;
????????animator.runtimeAnimatorController?=?player_AC;
???????
????????//重置敵人播放Timeline前的狀態(tài)????????if?(targetAnimator)
????????{
????????????targetAnimator.runtimeAnimatorController?=?target_AC;
????????????//...????????}
????}
?
5.踩過(guò)的坑
(1)角色身上CharacterController在激活狀態(tài),播放Timeline時(shí)角色會(huì)不能位移。
(2)結(jié)束播放時(shí),沒(méi)有執(zhí)行PlayableDirector.Evaluate(),角色回到開(kāi)始播放位置。
(3)播放結(jié)束,沒(méi)有把PlayableDirector.playableAsset置空,非Apply Root Motion時(shí)角色不能移動(dòng)。
結(jié)語(yǔ):本文結(jié)合了Timeline Signals和各種Track實(shí)現(xiàn)了一系列的功能,雖然已花了較長(zhǎng)時(shí)間查詢資料,但是仍存在很多不完善的地方,時(shí)間關(guān)系只好先介紹到這里(自己開(kāi)的坑,頭發(fā)掉滿地也只能含淚勉強(qiáng)填完)。希望對(duì)大家初步了解Timeline有所啟發(fā),如有問(wèn)題歡迎討論。

相關(guān)資料
1.Timeline Signals:https://connect.unity.com/p/shi-yong-unity-2019-1zhong-de-timeline-signals
2.Timeline動(dòng)態(tài)賦值:https://zhuanlan.zhihu.com/p/29585350
3.Ezy-Slice切割教程:https://www.bilibili.com/video/av65373505
4.從SkinnedMeshRenderer獲取正確顯示的普通Mesh:https://blog.csdn.net/Traip/article/details/88095446
5.格擋:https://zhuanlan.zhihu.com/p/83607025
鏈接:https://pan.baidu.com/share/init?surl=K1RX_qmmPfcjQazJHpNBJA
提取碼:stll

咱們的游戲開(kāi)發(fā)交流群也歡迎強(qiáng)勢(shì)插入:869551769
希望參與線下游戲開(kāi)發(fā)學(xué)習(xí)的,歡~~~~~~迎訪問(wèn):http://www.levelpp.com/