? ? ? ? 在很多實際場景中,我們經(jīng)常需要根據(jù)特定的事件(比如玩家輸入,敵人受到攻擊等)來播放不同的動畫。這需要我們了解一下Animator,Animator Controller和基礎(chǔ)的動畫狀態(tài)機(jī)。
創(chuàng)建一個開門的動畫
? ? ? ? 首先我們來創(chuàng)建一個簡單的開門動畫,示例中的門的模型來自官方教程。其實我們也可以用一個簡單的Cube調(diào)整一下做成門的形狀來做。無論是哪種方式,我們首先需要檢查一下這個游戲物體的pivot point。一個pivot point是物體進(jìn)行移動的基準(zhǔn)點。對于門來說,這個點非常重要。如果pivot點設(shè)置不對,則開門動畫會看起來非常奇怪(比如門沿著自身中軸線旋轉(zhuǎn),當(dāng)然,如果你是要制作旋轉(zhuǎn)門動畫就另說,示例中是一個普通的門)。
? ? ? ? 1. 首先,選中門對應(yīng)的游戲物體。此時Unity編輯器中會出現(xiàn)移動widget,如果這個widget的位置處于游戲物體正中心,如下圖:
? ? ? ? ?2. 我們點擊Toggle Tool Handle Position按鈕(上圖左上角紅框處),將它從Center改為Pivot
? ? ? ? ?3. 在Animation編輯器中,點擊Create按鈕,創(chuàng)建一個新的動畫片段,我們將其命名為Door_Open并保存
? ? ? ? ?4. 在Animation編輯器中,點擊Record,然后點擊Add Property,添加Transform -> Rotation屬性
? ? ? ? ?5. 將Playhead移動到1:00處(第二個關(guān)鍵幀),然后調(diào)整一下門的旋轉(zhuǎn)角度,將門的Inspector里的Transform -> Rotation里的Y改成90
? ? ? ? ?6. 預(yù)覽一下開門動畫,沒問題后再次點擊Record退出Recording模式。
? ? ? ? ?7.? 在工程文件窗口中,找到剛剛創(chuàng)建的Door_Open動畫文件,點擊后,在Inspector窗口中,禁用掉Loop Time。禁用這個選項后動畫只會播放一次,而不是無限循環(huán)。
?Animator Controller
? ? ? ? 再次選擇Door游戲物體,在Inspector中我們可以看到出現(xiàn)了一個新的Animator組件。對于一個選中的游戲物體,當(dāng)我們第一次為其創(chuàng)建動畫片段時,Unity會自動為它創(chuàng)建一個Animator組件。
? ? ? ? ?Animator負(fù)責(zé)為游戲物體分配動畫。但它并不控制實際的動畫片段,這個任務(wù)交給了Animator Controller,這個也是在第一個動畫片段創(chuàng)建時自動創(chuàng)建的。在Animator組件中的Controller這一欄中,可以看到有一個名為Door的Animator Controller(在保存動畫的目錄中,一般為Animations目錄,下面也有一個同樣名字的Door文件)。
? ? ? ? 1. 在工程文件窗口中,選中Door這個文件,將其重命名為Door_Controller
? ? ? ? ?2. 雙擊這個文件,打開Animator窗口
? ? ? ? ?3. 為了方便演示,將Animator窗口拖動到工程窗口處
? ? ? ? ?4. 在場景中選中Door游戲物體,然后點擊Play進(jìn)入游戲模式
? ? ? ? ?當(dāng)場景進(jìn)入Play模式后,可以看到門被打開了,同時,我們會看到Animator窗口中的Door_Open動畫下方有一個藍(lán)色的進(jìn)度條開始慢慢填滿,這表示Door_Open動畫片段的播放過程。Animator窗口中會實時地顯示當(dāng)前正在播放的動畫片段以及動畫片段播放進(jìn)度。
動畫狀態(tài)機(jī)
? ? ? ? Animation Controller運行在一種叫做狀態(tài)機(jī)(State Machine)的特殊系統(tǒng)上。狀態(tài)機(jī)會跟蹤一個物體所能執(zhí)行的所有可能的動作,并且根據(jù)當(dāng)前的情況(狀態(tài),state)選擇合適的動作。對于當(dāng)前狀態(tài)的控制邏輯,一般是通過腳本來控制。狀態(tài)機(jī)處理的從一個動作轉(zhuǎn)到另一個動作的過程,叫做轉(zhuǎn)換(Transition)。
? ? ? ? 為了更好地理解狀態(tài)機(jī)是如何工作的,我們以案例里的門為例子,它可以執(zhí)行的動作有開門和關(guān)門兩種。
? ? ? ? 因此門可能處于的狀態(tài)有:
- ? ? ? ? 正在開門過程中(Currently Opening)
- ? ? ? ? 正在關(guān)門過程中(Currently Closing)
- ? ? ? ? 打開狀態(tài)(Currently Open)
- ? ? ? ? 關(guān)閉狀態(tài)(Currently Close)
? ? ? ? 接下來我們畫出這些狀態(tài)之間的關(guān)系:
? ? ? ? ?門的默認(rèn)狀態(tài)處于關(guān)閉狀態(tài)。當(dāng)玩家足夠靠近門時,狀態(tài)機(jī)會切換到正在開門的狀態(tài),然后會切換到打開狀態(tài)。在玩家離開之前,門會一直處于打開狀態(tài)。玩家離開后,門會進(jìn)入正在關(guān)閉狀態(tài),然后切換到關(guān)閉狀態(tài)。此時狀態(tài)機(jī)又回到了初始狀態(tài)。
? ? ? ? 基于此,我們可以看到有兩種轉(zhuǎn)換(transitions)需要一些邏輯輸入(檢測玩家靠近和遠(yuǎn)離門),有兩種狀態(tài)會自動轉(zhuǎn)換到下一個狀態(tài)(正在開門轉(zhuǎn)換到開門,正在關(guān)門轉(zhuǎn)換到關(guān)門)。
創(chuàng)建默認(rèn)動畫狀態(tài)
? ? ? ? 前面小節(jié)中,我們創(chuàng)建的Door_Open動畫,只要場景開始運行就會自動播放。這不是我們想要的效果,造成這個問題的原因是,當(dāng)前只有這個動畫和門關(guān)聯(lián),在添加這個動畫時,Unity的Animation Controller自動將其設(shè)置為了默認(rèn)狀態(tài)。接下來我們來解決一下這個問題。
? ? ? ? 1. 在Animator的工作區(qū)中(背景是網(wǎng)格,包含了各種狀態(tài)的區(qū)域),點擊右鍵并選擇Create State -> Empty,創(chuàng)建一個空狀態(tài)
? ? ? ? 2. 選擇新創(chuàng)建的節(jié)點,在Inspector面板中,將它的名字從New State改為Closed
? ? ? ? 3. 右鍵點擊Closed狀態(tài),然后選擇“Set as Layer Default State”
?????????我們可以看到,現(xiàn)在Closed狀態(tài)變成了橙色,并且Entry節(jié)點指向了它。Entry節(jié)點和Closed節(jié)點之間的橙色線表示了一個轉(zhuǎn)換(transition)。Entry節(jié)點是狀態(tài)機(jī)開始運行時所處的第一個節(jié)點,在場景開始運行的時候會自動運行Entry節(jié)點。
? ? ? ? 4. 再次點擊運行按鈕,看看門的行為有什么差異。
實現(xiàn)開門狀態(tài)轉(zhuǎn)換
? ? ? ? 下一步,我們來實現(xiàn)檢測玩家并切換到開門動畫的功能。要檢測玩家是否靠近到門,通常的邏輯是通過一個Trigger碰撞器加上腳本來實現(xiàn)。我們先完成狀態(tài)機(jī)部分的設(shè)置,增加腳本要使用的引用變量即可。
? ? ? ? 1. 右鍵點擊Closed節(jié)點,選擇Make Transition。此時有一個白色的箭頭會出現(xiàn)在光標(biāo)處。
? ? ? ? 2. 選擇Door_Open節(jié)點,讓這個箭頭和它連接起來。
? ? ? ? 3. 點擊運行按鈕測試一下效果。
? ? ? ? ? ? ? ? 運行過程中,我們可以看到,在Animation Controller中,首先會經(jīng)過Closed節(jié)點。當(dāng)Closed節(jié)點完成后,會立即調(diào)到Door_Oepn動畫,隨后停在了開門動畫上。為了避免Closed節(jié)點直接調(diào)到開門動畫節(jié)點,我們要在轉(zhuǎn)換條件上附加一些邏輯來做控制。要實現(xiàn)這個控制,我們需要使用狀態(tài)機(jī)參數(shù)(Parameters)參數(shù)是Animator內(nèi)部創(chuàng)建的變量,可以在Animator編輯器的左邊找到Parameters標(biāo)簽頁。
? ? ? ? 4. 選擇Parameters標(biāo)簽頁,在Parameteres列表的頂部,點擊“+”并且選擇Trigger(觸發(fā)器)
? ? ? ? ? ? ?Trigger參數(shù)會在它被腳本所修改時立即變化。
? ? ? ? 5. 將Trigger變量的名字設(shè)置為PlayerProximity,注意后面在腳本里引用這個變量時,名字一定不要搞錯了。
? ? ? ? 6. 選中Closed和Door_Open節(jié)點中間的帶白色箭頭線。然后在其Inspector中找到Conditions。
? ? ? ? 7. 在Condiditons列表底部,選擇“+”。由于目前只有一個參數(shù),PlayerProximity會自動加到列表中。
? ? ? ? 8. 點擊運行按鈕,運行場景。
? ? ? ? 9. 在參數(shù)列表中,點擊PlayerProximity參數(shù)旁邊的單選按鈕,手動觸發(fā)這個變量。
? ? ? ? 我們可以看到,當(dāng)PlayerProximity被修改后,狀態(tài)切換到了Door_Open并開始播放開門動畫。
實現(xiàn)關(guān)門狀態(tài)轉(zhuǎn)換
? ? ? ? 接下來我們用類似的方法實現(xiàn)關(guān)門狀態(tài)。
? ? ? ? 1. 在Animator里選中Door_Open節(jié)點,然后按Ctrl/Command + d復(fù)制一份這個節(jié)點。
? ? ? ? 2. 在Inspector中,將復(fù)制的節(jié)點的名字修改為Door_Close,并且將它的Speed參數(shù)設(shè)置為-1,這樣會讓動畫的幀反向播放。?
? ? ? ? 3. 右鍵點擊Door_Open節(jié)點,選擇Make Transition,然后將Door_Open和Door_Close節(jié)點連接起來。
? ? ? ? 4. 選擇這個新建的轉(zhuǎn)換(transition),在Condiditons列表中點擊“+”。同樣,PlayerProximity會自動出現(xiàn)。
? ? ? ? 5. 點擊運行按鈕,運行場景,同樣我們使用PlayerProximity旁邊的單選按鈕,來測試先開門后關(guān)門的動作是否正常。
? ? ? ? Animator中的Trigger參數(shù)在當(dāng)前轉(zhuǎn)換(從一個狀態(tài)切換到下一個狀態(tài))完成后,會立即失效。因此我們在開門和關(guān)門的時候,可以安全地復(fù)用這個參數(shù)。后面我們會用腳本來操作這個參數(shù)。
復(fù)位狀態(tài)機(jī)
? ? ? ? 到目前為止,我們以及實現(xiàn)了通過Animator參數(shù)來實現(xiàn)開門和關(guān)門的動畫播放和相關(guān)狀態(tài)。但狀態(tài)機(jī)最后會停留在關(guān)門狀態(tài),這個過程只會發(fā)生一次。為了讓動畫每次在PlayerProximity發(fā)生變化時還能正常表現(xiàn),當(dāng)關(guān)門動畫播放完畢時,我們要將動畫狀態(tài)機(jī)復(fù)位到初始狀態(tài)。我們可以通過使用Exit節(jié)點來實現(xiàn)這個功能。當(dāng)狀態(tài)轉(zhuǎn)換到Exit節(jié)點時,狀態(tài)機(jī)會自動地切換到Entry節(jié)點。
? ? ? ? 1. 右鍵點擊Door_Close節(jié)點,選擇Make Transition。
? ? ? ? 2. 點擊Exit節(jié)點,連接Door_Close節(jié)點和Exit節(jié)點。
? ? ? ? 3. 點擊運行按鈕,運行場景
? ? ? ? ? ? 現(xiàn)在我們可以看到,當(dāng)Door_Close播放完成后會自動轉(zhuǎn)換到Exit,然后再回到Closed狀態(tài)。這里我們還會注意到一點,在我們修改了PlayerProximity的值之后到門被打開之間會有點延遲。這是因為默認(rèn)情況下,在一個狀態(tài)節(jié)點執(zhí)行轉(zhuǎn)換之前,要先走完整個動畫播放時間(Animator里狀態(tài)節(jié)點的進(jìn)度條可以直觀感受到這個時間)。我們可以選擇將禁用這個行為,讓切換到Door_Open的轉(zhuǎn)換立即發(fā)生。
? ? ? ? 4. 選擇Closed和Door_Open節(jié)點之間的轉(zhuǎn)換(transition),在Inspector中,禁用掉Has Exit Time。
? ? ? ? 6. 重新運行場景,看看現(xiàn)在的效果。
?添加Trigger檢測碰撞器,用腳本控制PlayerProximity參數(shù)
? ? ? ? 前面我們通過手動點擊PlayerProximity的方式來做狀態(tài)機(jī)的測試。接下來我們用一個Trigger碰撞器和一個腳本來實現(xiàn)對這個參數(shù)的動態(tài)控制。關(guān)于普通的collider和tirgger collider的區(qū)別,本筆記不會討論,請自行參考網(wǎng)上資料。
? ? ? ? 1. 在Hierarchy中,點擊右鍵選擇Create Empty創(chuàng)建一個空游戲物體。
? ? ? ? 2. 將這個游戲物體命名為Door_Trigger。
? ? ? ? 3. 選中Door_Trigger,在Inspector中選擇Add Component,添加一個Box Collider。
? ? ? ? 4. 在Box Collider組件中,啟用“Is Trigger”。
? ? ? ? 5. 調(diào)整Box Collider的大小,讓其能夠覆蓋到門前后一片空間。
? ? ? ? 6. 編寫DoorTrigger腳本,并且將腳本添加到Door_Trigger游戲物體上。
? ? ? ? ? ? ?DoorTrigger腳本代碼如下:
? ? ? ? ? ? ?代碼意思很好懂,OnTriggerEnter/Exit函數(shù)中,檢測到Player進(jìn)入/離開Trigger Collider之后,會去修改PlayerProximity參數(shù)。?
? ? ? ? 7. 在Door_Trigger的Inspector中,將Door游戲物體拖動到Door Trigger腳本里的Anim屬性方框中,這能夠?qū)oor的animator和腳本里的Anim參數(shù)關(guān)聯(lián)到一起(當(dāng)然,也可以直接在腳本里通過GetComponent方法獲取這個Animator)。
文章來源:http://www.zghlxwxcb.cn/news/detail-426774.html
? ? ? ? 8. 運行場景,控制Player進(jìn)入和離開Trigger Collider的區(qū)域,觀察結(jié)果(案例中有一個可用鍵盤控制的人物模型,我們也可以直接在場景中添加一個小球或立方體來代替,通過在Editor中拖動這個物體來實現(xiàn)Trigger Collider的檢測)。文章來源地址http://www.zghlxwxcb.cn/news/detail-426774.html
到了這里,關(guān)于Unity Animation -- 使用Animator控制動畫的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!