使用unity如何在低幀率下實現高速穿透子彈?

因為性能原因,不希望物理引擎以較高速度進行刷新。中間以插值填補顯示效果。

比如遊戲物理更新幀率運行在10幀每秒。

現在需求是希望實現一枚可以穿透敵人的子彈,比如英雄聯盟中拉克絲的Q技能(兩個目標限制)或者EZ的大招。

那麼如何讓一發子彈在高速狀態下能夠精確的判斷碰撞點?

嘗試使用CCD來解決,尷尬的地方是,標記為Trigger的物體無法進行CCD(不知道是不是我理解的不對),不標記Trigger的話,CCD會產生位置修正,將子彈最終位置強制定位到碰撞點。這樣的話子彈就無法進行穿透邏輯。於是這種方法的特點是:

1、不穿透的子彈命中點精確。無法實現穿透子彈。

2、非Trigger的子彈會與其他非目標實體發生意外碰撞導致位置修正。比如發射者。

第二個思路是子彈依然為Trigger,不適用CCD,將子彈矩形碰撞盒長度增大,增大到每幀行走的長度。這樣的確解決了隧道效應。但是帶來兩個問題:

1、發生了判定穿牆效果。位於薄牆體後面人會被子彈碰撞盒包圍住。

2、碰撞點不精確,無法精確的定位子彈與物體的碰撞位置。

第三個思路是,用射線來實現子彈,每幀子彈向前進方向發射三條以上的射線,成三字形指向前方。如果射線檢測到物體,並且通過射線掩碼驗證,則根據射線返回物體按距離排序,再遍歷物體組,如果發現有牆體,就忽略後續的物體,如果發現超過有效目標數,則忽略後續物體。這個方案的問題是:

1、貌似沒什麼問題,可以實現想要的效果。

2、當子彈過多時,射線消耗是否過大?

或求前輩經驗,這個問題是否存在更優方案?


推薦射線法或類似的方法來模擬CCD。首先你不是每幀都發射線而是一顆子彈1次(或者說3次),只要不是場景碰撞盒特別複雜的,射線的性能消耗完全可以接受。

trigger不能ccd的問題暫時沒救。

還有個思路是不用trigger,接觸時關collider並人工判定穿透後出來的位置和速度(可通過接觸點和接觸速度算出),然後強制位移和設置速度並開collider。


上一幀子彈位置和當前幀子彈位置連成一條線段,目標物體運動速度不大的話用當前幀位置,碰撞體簡化為Box/Sphere。

問題可以簡化為線段和Box/Sphere的求交問題,只要線段和碰撞體相交了就算擊中。

自己用C#寫個就好,就不用管Tigger不Trigger了。

開銷看碰撞體和子彈數目,自己profile一下,需要優化的話用一些常用的空間分割演算法就可以。


10幀每秒就別做了。

物理判斷頻率至少要25幀才能不影響遊戲體驗。

我不知道你這是啥遊戲。但你好好想想,你物理頻率低,一個角色平移的時候,它的碰撞盒會怎樣?

對,拖在後面(根據不同寫法也可能頂在前面)

玩家的實際感受就是不知道角色碰撞體到底在哪裡,這實在太糟糕了。再加上子彈,兩邊都有偏移,遊戲基本沒法玩。

別聽什麼減少物理頻率優化效率的說法,那些多是紙上談兵,除非你的遊戲碰撞盒就是糊弄人的,對精度一點要求都沒有。

在不能用CCD的情況下用射線,但通常沒機會用。看得見的情況下普通碰撞足夠應付(短子彈延長碰撞箱,這種速度下會有視覺殘留,玩家根本無法分辨),「快得看不見」的時候才需要CCD射線之類。

射線還有一個應用環境是飛機射擊遊戲的自機移動,這個也是「快得看不見」的情況。

不過題主你說的薄牆體因為判定順序問題導致牆後被命中的問題……之前沒考慮過。

這個你在物理事件里只做標記就好了,命中牆就記錄子彈的死亡標誌,命中目標就把命中狀態記錄下,再在下一次fixupate中進行判定。設定已經標記死亡的子彈即使命中目標也無效即可。判定順序都可以用這種辦法解決。

不過又會出現先命中目標再命中牆的問題……按一般的說法就是要判斷子彈方向……

哈哈。

我覺得還是合理控制物理頻率和物體移動速度避免穿透出現比較靠譜,如果要考慮所有極端情況,恐怕所有的行為都需要用嚴格的數學方法計算。

當然,你也可以選擇完全放棄物理引擎,所有內容都自己寫。自己控制每個物體之間的檢測邏輯,這樣就可以使用一些更節約的判定方式,諸如只支持方形碰撞(不支持旋轉角),這樣判定重疊只需要看端點坐標是否重合,效率極高,或許會讓你有勇氣增加物理判定頻率。但假如還要支持旋轉後的方形碰撞箱,哪怕僅僅是圓碰撞箱的話,你自己寫的未必就比物理引擎效率好,尤其是在物品數量較多的情況下。

通常這都不是為了效率的解決方案,而是為了拋棄物理引擎的限制。

題主……關鍵是你這個10幀/秒是怎麼弄出來的。如果性能有問題,我覺得好好優化物理部分更靠譜一點吧,而不是簡單的減少物理間隔。你先嘗試下設置Layer,還有停止不需判定的碰撞箱。


我傾向於射線,按你描述的需求來看,子彈有飛行時間,超過距離的就可以pass掉,根本不需要算完再排序什麼的,可優化空間很大,開銷應該可控


射線檢測。用deltaTime*子彈飛行的速率做範圍


用射線或者spherecast都可以。射線開銷很小


下面的兩種方法都可以嘗試下

A:把子彈設成trigger試試,另外別銷毀子彈,要是還不行就給子彈一個實體和速度後再對子彈不同時刻不同位置之間進行射線檢測

B:這裡的子彈用射線,通過讀取表中是否有穿透屬性這一項,決定是raycast還是raycastall 如果穿透 就返回所有碰撞信息

如果有幫助可以關注一下我們的UNITY遊戲開發專欄


我一般用射線檢測獲取坐標,讓子彈飛l移動到坐標就行了


不用線段跟box/sphere求交也行

在兩幀之間根據位置做一些差值,轉換成多個靜態幀中,box/sphere之間相交的問題

優點是兩個靜止的box或者sphere比有運動軌跡的求交更簡單,缺點就是,仍然會有穿透現象發生。

想減少穿透發生只能取更小的差值步長,當然檢測次數就會增加。

參考閱讀《實時碰撞檢測演算法》


推薦閱讀:

如何評價使用Unity引擎製作的《琪亞娜·極樂凈土》?
蘇打世界和拍拍卡洛琳這種扁平化風格遊戲動畫用什麼軟體做的?
如何自己做一個好的遊戲引擎?需要哪些必備知識?
Unity5中如何寫出好的透明(Transparent)效果shader?
我該如何進入USC遊戲設計專業?

TAG:遊戲設計 | Unity遊戲引擎 | 手機遊戲開發 | 物理引擎 | box2d |