目錄
1 幾何體動畫化
1.1 動畫
1.2 動畫同步
1.3 側面移動
2 連接主體
2.1 檢測連接
2.2 連接狀態
2.3 檢測移動
2.4 相對於連接做移動
2.5 旋轉
2.6 複雜的動畫
收起
本文重點內容:
1、創建可以動的平臺
2、保持對連接主體的追蹤
3、嘗試保持相對關係
4、支持軌道連接點
這是有關控制角色移動的教程系列的第七部分。它解決了在運動中的地形上站立和導航的問題。
本教程是CatLikeCoding系列的一部分,原文地址見文章底部。本教程使用Unity 2019.2.21f1編寫。它還使用了ProBuilder包。
(移動的時候,大多數物體仍然保持站立)
1 幾何體動畫化
有很多種方法可以移動幾何體。可以創建一個腳本來調整對象的Transform, 可以使用Unity的動畫系統對其進行動畫處理。還可以編寫自己的playable graph並以此方式創建動畫。或者我們可以依靠PhysX並讓對象響應外力和碰撞而移動。但不管哪種方式,我們都必須確保在運動中的地形和障礙物與PhysX、我們的運動球體以及我們的軌道攝像機可以完美配合。
1.1 動畫
在本教程中,我們將使用Unity的動畫系統在編輯器中創建簡單的動畫。我們通過「Animation」窗口執行此操作,該窗口可以通過「Window/ Animation / Animation」打開。如果選擇的對象還沒有Animator組件,則窗口將顯示一個按鈕,以便讓你添加該組件並立即為其創建新的動畫。
(為 up Down物體創建動畫)
我製作了一個簡單的方形平臺對象,名為Up Down,然後為其創建了一個新的動畫剪輯,名為Up Down Animation。動畫是一個新資產,但是按下「Create」按鈕還會創建另一個資產,我將其重命名為「 Up Down Controller」。這是運行動畫所需的動畫控制器資產。它可以用來創建複雜的混合樹和動畫狀態機,但是如果我們只需要一個動畫剪輯,就不必處理它。我把它們都放在一個新的Animation文件夾中。
(動畫資產)
添加到平臺對象的Animator組件將自動設置為使用新的控制器資產。我們最初可以將其所有其他配置選項保留為默認值。為該對象提供一個啟用了運動功能的剛體組件,因為它是動態PhysX對象。雖然這不是必要的,但可以確保所有交互均按預期進行。
(Animator和剛體組件)
要使動畫剪輯執行某項操作,需要在場景中選擇相關對象。「Animation」窗口將在時間軸控制按鈕下方的左側顯示我們的動畫剪輯。按下錄製按鈕(紅點),然後在右側的時間線欄中選擇所需的時刻。你可以縮放以到達當前不可見的區域。然後,通過其檢查器或在場景視圖中調整對象的Transform。這將創建具有新配置的關鍵幀。
例如,我將兩秒鐘的Y位置從0更改為3,並在四秒鐘將其設置回0。然後關閉錄製。
(帶有關鍵幀的Animation窗口)
現在就可以預覽動畫了。進入播放模式後還會自動以及循環播放。
(在一個動畫的平臺上移動)
默認情況下,Unity通過緩和過渡來平滑動畫。您可以通過「Animation」窗口底部的切換選項從「Dopesheet」切換到「Curves」模式來精確的控制行為。
(動畫曲線,Y坐標為綠色)
為什麼不能移動動畫對象?
如果對象正在播放更改其位置的動畫,則該動畫的位置將覆蓋該對象的配置位置。你可以通過將動畫對象變成另一個對象的子對象,然後將其移動到其他位置。
1.2 動畫同步
當球體被向上推動並隨著平臺的垂直運動而下降時,我們的球體已經可以在平臺上跳躍並隨之移動。但是默認情況下,交互的時間並不正確。當將軌道攝像機的「Focus Radius」設置為零,使其隨球體剛性移動時,這個現象非常明顯。
(正常的動畫模式)
事實證明,向上運動有點抖動,而向下運動則更糟,因為球體反覆下降一小段距離,撞擊平臺,然後再次下降。發生這種情況是因為默認情況下,動畫每幀更新一次,因此運動與PhysX不同步。通過將Animator組件的Update Mode設置為Animate Physics,我們可以設置動畫來更新每個物理步長。
(動畫和物理同步)
現在我們的球體在向下移動的時候可以附著在平臺上。但平臺的運動會像其他運動中的物理物體一樣抖動,如果需要的話,可以通過設置它的剛體來解決。
(插值平臺運動)
1.3 側面移動
解決了垂直運動,我們還需要支持向其他方向運動的平臺。因此,我用自己的動畫剪輯和控制器製作了另一個平臺,該動畫剪輯和控制器沿X軸左右移動。
(側向移動的時候並沒有吸附)
我們的球體可以沿著平臺的表面移動,但是當平臺靜止時,它忽略了平臺的水平移動。其他PhysX對象確實會隨平臺一起拖動,但如果平臺移動得太快的話,它們仍然會左右滑動。因為我們的球體沒有任何抓地力,因此也不會受到拖拽。它的阻力係數為零,不然的話會干擾其他的物體。我們必須針對此問題提出解決方案。
2 連接主體
為了能夠沿著其站立的表面移動,我們的球體首先需要意識到該表面。通常,這意味著球體可以隨時與可能運動的另一個物體進行連接。第一步是跟蹤此主體,我們將其稱為「連接主體」。可能同時存在多個這樣的主體,但是這種情況很少見,因此我們將自己限制為一個單一的主體。因此,如果球體最終與多個物體接觸,我們將使用任意物體,而忽略其他物體。一旦知道了主體,我們就必須檢測其運動並將其以某種方式應用於球體。
2.1 檢測連接
我們不在乎為什麼某物在移動,而只是它是否在移動。這個想法是所有動態對象都有一個剛體組件,因此我們將通過向它添加一個欄位到MovingSphere來跟蹤連接的實體。
如果我們在評估碰撞中檢測到地面接觸,我們可以簡單地將碰撞的剛體屬性分配給我們的欄位。如果另一個對象有一個Rigidbody組件,那麼我們現在有一個對它的引用,否則它被設置為null。請注意,組件不必直接連接到我們碰撞的對象。我們可能會與某個複合對象發生碰撞,該對象的組件位於其層次結構的某個較高位置。
請注意,通過簡單地總是分配連接的物體,我們替換了以前被視為地面的任何接觸點,因此我們最終會跟蹤最後評估的地面物體。這很棒,因為碰撞順序是任意的,但在時間上是穩定的。
但是,我們也有可能會走在斜坡上而不是地面上。在這種情況下,我們還應該跟蹤主體。但是,我們應優先選擇地面而不是斜坡,因此,僅在沒有地面接觸的情況下才分配斜坡主體。
如果沒有連接的物體,是不是不應該總是使用斜坡?
不是,因為地面可能是靜態的,在這種情況下它不會有剛體組件。在這種情況下,我們將站在不動的地面上,而不應該在碰巧也接觸斜坡的時候,受到移動的斜坡的影響。
如果我們在SnapToGround中檢測到地面,也應該跟蹤連接的物體。
最後,在ClearState中將連接的正文重置為null。
2.2 連接狀態
僅僅知道我們在當前物理步長中已連接到主體是不夠的。我們必須能夠弄清楚自上一步以來我們是否仍與同一個主體保持聯繫,因為這表明我們應該與之保持聯繫。因此,我們需要另一個欄位來存儲對先前連接的主體的引用。重置前應將其設置為當前連接的主體。
再將連接速度存儲在一個欄位中。雖然這不是特別有必要,但它會很方便。在ClearState中將其設置為零。
2.3 檢測移動
如果連接的主體是自由移動的物理對象,那麼它將具有速度,但是在運動動畫對象的情況下,其速度將始終為零。因此,我們必須通過跟蹤其位置來自己推斷出連接速度。為此添加一個欄位,並將其設置為新的UpdateConnectionState方法中連接主體的位置,如果我們具有連接主體,則將在UpdateState的末尾調用該方法。
但需要小心,不要粘附在與我們相撞的較輕的物體上,否則我們可能會隨著它們一起自由移動,或者把它們推開,然後把我們自己彈射出去。可以通過更新連接體的連接狀態來避免這種情況,如果連接體是運動的,至少應該和球體本身的質量一樣大。
在更新連接之前,可以通過從連接的當前位置減去我們已經擁有的連接位置,在UpdateConnectionState中找到連接的運動。通過將其運動除以時間增量來找到其速度。
但是,只有噹噹前和先前的連接體相同時,該計算才有意義,因此請檢查一下。否則,連接速度應保持為零。
2.4 相對於連接做移動
至此,我們知道了我們所站的平臺的速度。下一個問題是我們如何將其納入球體的運動中。實際上,當你從正在移動的物體移到靜止的物體(反之亦然)時,需要補償相對運動的突然變化。這很費力,如果變化很大,可能會很困難。如果太大,最終會掉下去。另外,如果你站在可以加速的物體上,則必須做好準備,否則你也會跌倒。最後,應該有可能相對於我們所站立的物體以最大速度移動。請注意,這可能導致世界空間速度超過配置的最大速度,例如在行駛中的火車中行駛。
最簡單的建模方法是使球體加速以匹配其所連接的物體的速度,然後再加速至相對於連接速度的所需速度。我們可以在AdjustVelocity中做到這一點,方法是從球體的速度中減去連接速度,然後使用此相對速度來確定當前的X和Z速度。因此,球體的速度調整變得相對於連接速度,而其他所有條件保持不變。
(在側面移動的平臺上移動)
2.5 旋轉
現在,我們的球體試圖匹配其所站立的物體的速度,但受到其自身加速度的限制。在與平臺的運動匹配之前,球體將會有滑動效果。而且,如果平臺快速加速,球體無法跟上的話,可能會滑落。因此,在快速加速的東西上行走可能很尷尬,這與現實相符。可以通過增加球體的最大加速度來緩解。
(忽略了平臺旋轉)
在旋轉連接的情況下,我們無法跟蹤其位置,因為它不受旋轉的影響。因此需要追蹤被連接物體的局部空間中的連接位置,因為該點有效地繞過了物體的本地原點。
從現在開始,我們將使用球體的位置作為世界空間中的連接位置,而不是連接本身的位置。這是我們一開始跟蹤的點。連接的局部位置是相同的點,但是在連接體的局部空間中,我們通過在連接體的轉換組件上調用InverseTransformPoint來找到它。在UpdateConnectionState的最後執行此操作。
(在旋轉的平臺上行走)
現在,我們的球體會加速以跟上旋轉,但請注意,它不會調整其方向來匹配。由於我們的球體永不旋轉,它會自動重新定向以保持朝相同的方向看。
另請注意,旋轉可能會是高速旋轉。你離旋轉中心越遠,軌道速度就越快。如果旋轉足夠快,你會被甩開,要麼迅速從軌道彈出,要麼緩慢向外盤旋。
2.6 複雜的動畫
因為我們的方法不在乎表面如何移動,所以我們的效果不會局限於簡單的動畫。我們支持所有複雜的動畫和腳本化運動,也支持在不受控制的PhysX對象上運動,但這會有一點點尷尬,就像在現實生活中在不穩定的地面上行走一樣。創建複雜運動的另一種方法是通過構建其中包含多個動畫師的對象層次結構。你也可以在層次結構中放置多個物理對象,但請記住,不要將具有剛體的任何對象作為另一個此類對象的子對象,因為物理幹擾,這會產生奇怪的結果。
(複雜的動畫和平臺)
下一章,介紹攀爬。
本文翻譯自 Jasper Flick的系列教程
原文地址:
https://catlikecoding.com/unity/tutorials