UE4多人FPS遊戲持槍視角旋轉優化
UE4多人FPS遊戲持槍視角旋轉優化
1 問題概述
在傳統多人FPS遊戲中,一般對於玩家操控的角色會有兩個骨骼模型,分別是自己控制的第一人稱以及其他玩家看到的第三人稱模型,同時這兩個模型也有其各自的動畫。常見的第一人稱通常只會保留手臂,其他玩家看到的第三人稱模型的持槍瞄準方向會跟隨第一人稱的攝像機旋轉進行相應的調整,而在第三人稱持槍視角旋轉時,會出現卡頓(不平滑)。以下以虛幻引擎官方的遊戲示例專案Shoot Game為例,可以在虛幻引擎商店中免費獲取完整專案。
2 原理分析
在ShootGame專案中,第三人稱的持槍視角旋轉是使用2D的混合空間(Blende Space)合成的,該資產位於Content/Characters/HeroTPP/HeroTPP_AimOffsets
![image-20211120184746147](https://gitee.com/tanfu2/picgo/raw/master/pic/2021-11-20 18-47-54_image-20211120184746147.png)
在角色的動畫藍圖中,通過每幀獲取攝像機的旋轉對混合空間的Pitch和Yaw進行設定以控制持槍的動作的視角,以下是第三人稱的AnimGraph的部分節點:
![image-20211120191750847](https://gitee.com/tanfu2/picgo/raw/master/pic/2021-11-20
以下是部分藍圖程式節點,這部分程式碼在Event Blueprint Update Animation
中執行:
![image-20211120192129501](https://gitee.com/tanfu2/picgo/raw/master/pic/2021-11-20 19-21-33_image-20211120192129501.png)
GetAimOffsets是ShooterCharacter類的一個函式,用於獲取第三人稱對應第一人稱的視角的數值,其程式碼如下:
FRotator AShooterCharacter::GetAimOffsets() const { const FVector AimDirWS = GetBaseAimRotation().Vector(); const FVector AimDirLS = ActorToWorld().InverseTransformVectorNoScale(AimDirWS); const FRotator AimRotLS = AimDirLS.Rotation(); return AimRotLS; }
上述解決方案理論上能表現地比較良好,但是由於這是多人遊戲,還需要考慮到伺服器的問題。當其他玩家的旋轉視角操作上傳到伺服器時,伺服器將各個玩家的資料同步到所有客戶端,但是由於伺服器效能有限,其更新頻率遠不如客戶端,特別是視角旋轉是一種高頻且在短時間內資料波動較大的操作,其它玩家的攝像機旋轉資訊同步到當前客戶端時就會出現資料的“卡頓”(舉個例子,我在本地操作視角上下勻速抬頭,假設Pitch是從-90漸變到90,由於本地幀數高,資料變化可以理解為-90、-87、84...87、90,這樣自己看起來比較絲滑,但是伺服器同步資料的頻率有限,到其他客戶端可能就變成-90、-60、-30...60、90),所以在其他玩家看來,原本我在本地絲滑的視角旋轉,到其他客戶端觀察到的就是卡頓和閃爍。實際上,角色的移動如果不經過處理同樣也會這樣,但是虛幻引擎強大的GamePlay框架對於這種經典的FPS問題已經有了現成的解決方案,角色移動元件(CharacterMovement)就很好地解決了類似問題。當然上述的視角旋轉觀察不平滑的問題,也是我在研究官方的案例中發現的,我也算是半個強迫症,於是乎就想到去簡單的解決這個問題。
3 解決方案
對於角色移動元件,我沒有對類似問題的解決方法進行深入研究,但是我猜想它可能是對資料進行插值,讓目標資料更加平滑,所以對於視角旋轉的不平滑我設想的解決方法也是如此。其基本思路是讓第三視角旋轉延遲更新,在這部分延遲的時間內對當前旋轉到目標旋轉(也就是第一視角實際的旋轉)進行插值,獲取的值用於控制第三視角的旋轉。以下是實際修改之後藍圖節點程式碼:
![image-20211120212433213](https://gitee.com/tanfu2/picgo/raw/master/pic/2021-11-20 21-24-37_image-20211120212433213.png)
圖中SmoothTime
用於儲存延遲更新的時間,LastAimRotator
用於儲存上一幀第三視角實際的旋轉值,左下方的SmoothTime
上方的綠線連線的是
Event Blueprint Update Animation
事件的Delta Time X
,一般來說延遲時間的具體數值應該保持在一定合理的範圍內,既不能過小(依舊卡頓)也不能過大(延遲太高,視覺誤差過大),通常根據伺服器的更新頻率設定。當然上述解決方案存在優化的空間,並不是十分完美但勝在簡單易懂,上述的插值實際上並不是線性的,由於Alpha數值基本固定,越接近實際旋轉時數值更新地越慢,無限接近實際旋轉的數值。最後實際的動畫表現效果表現良好達到預期。