Unity射線有時失靈,檢測失效原因及解決辦法

先寫總結,如果看總結能懂就不用往下看了,不懂就再看看吧:

假設要對一個正在移動中的比較小的(注意!!是比較小的,大的看不出來,大的即使晚更新幾幀肉眼也看不出來)物體A進行射線檢測。如果出現射線有時判true,有時判false。可能是以下原因。

首先,只有在FixedUpdate執行完後纔會更新物理,此處說的更新物理是更新碰撞體的意思。

FixedUpdate是固定幀更新,默認1秒執行50次。Update是有多少幀運行多少次。如果在Update中更新物體A位置後再進行射線檢測有可能檢測不到,尤其是幀數比較高的時候。爲什麼?因爲Update可能運行3次,FixedUpdate才運行一次,而在這三幀裏,物體A在渲染中可能已經移動了一定距離,而物體A的碰撞體並沒有更新還是再原來的位置,所以射線在對渲染的物體的位置進行判定,所以會判空。而有時判true又是因爲,在運行三幀後FixedUpdate更新後碰撞體更新到了正確的位置,射線判定正確。

原理就是這麼個原理。

解決辦法:

往下翻查看紅色字體。

 

細節:

在製作槍械跟隨時遇到了槍械抖動的問題,簡單地通過將相機調整爲LateUpdate解決了這個問題。但是在之後製作紅點的時候又遇到了問題,這個問題困擾了我整整四天之久,解決後才發現自己對unity是自己對unity的生命週期和物理更新系統沒有深入理解導致的。

紅點的算法是從相機發出一道指向射擊點的射線,射線擊中紅點鏡時返回擊中信息,將紅點面片位置設置到擊中位置,紅點方向設置爲始終面對相機。

當玩家移動後,帶動作爲相機的子物體移動。相機內部調用搖晃函數是相機模擬視角搖晃並跟新本地位置。更新完成後,槍械開始跟隨相機。當玩家按下鼠標右鍵時進入機瞄狀態。槍械跟隨完成後開始進行紅點的算法,發出射線進行判定。

其中移動是在Update中,相機也是在Update中,槍械跟隨也是在Update中,紅點在強械跟隨同腳本的lateUpdate中,這四個函數按照依次按照順序執行。

但是在實際運行過程中,在移動時,紅點總是有些時候顯示在正確位置,然後滯後正確位置一段不確定距離,持續幾幀,這幾幀裏每一幀都滯後更多,然後又顯示在正確位置,站在原地時則不會。一般出現滯後情況都會考慮到unity的函數執行順序。在這個案例中,每一幀裏先運行移動腳本,然後是相機,此時相機位置已經完全確定,之後是槍械跟隨,當按下鼠標右鍵時,槍械跟隨到相應位置,槍械位置也完全確定。在LateUpdate中更新紅點位置,按理說位置應該完全準確,但是無論如何都不行。

 

 

猜測執行順序有問題,相機位置更新錯誤,使用Debug.Ray檢查,沒有問題。

之後我又Debug了射線,判定射線是否擊中,大約有2/3的輸出是沒有擊中紅點鏡的。

 

猜測了一堆,現在弄懂了之感覺自己之前的猜測都沒道理。。就不寫了。。不過在之前查詢這個問題的時候找了個博客,上面寫着update後就調用渲染,渲染完成後再調用LateUpdate。我當時就信了!!!!!!!!!!!!!注意,這個是錯的。這個博客導致我花了兩天時間來進行胡亂思考。。正確的是LateUpdate後纔開始渲染,我已經聯繫那位博主進行了更改。

又猜測應該將槍械跟隨代碼放到FixedUpdate,紅點算法放在Update或者LateUpdate中問題解決。但是劇烈抖動,因爲相機和移動腳本使用Update,兩者更新頻率不同,然後將相機和移動腳本更換爲FixedUpdate,問題解決。但是遊戲並不流暢,(其實可能對一直用60hz的屏幕的人來說是比較流暢的了,個人用的144Hz的屏幕,看60幀感覺很卡)。這裏先不說爲什麼能解決,因爲這是我第三天偶然試出來的,但是不知道爲什麼。

這幾天查閱了很多資料,一直再查unity生命週期什麼的。。直到最後一天,我開始在google查詢Raycast sometimes miss。。才發現,unity在FixedUpdate後纔會更新物理,這個更新物理是什麼意思,是纔會跟新碰撞體的位置的意思。。也就是說在update中只會跟更新模型位置而不會更新碰撞體位置,因此射線射過來沒有擊中碰撞體,所以紅點在這一幀不會更新位置,在移動後的視野中看起來就像滯後了。這個射線問題在對大型物體進行判定時問題不大,但是在對紅點鏡鏡片這種很小的物體就很容易看出來。

要解決這個問題有兩種辦法:

第一種,上面已經說了,把要擊中的物體的位移寫在FixedUpdate中,這樣移動後纔會連同碰撞體的位置一起更新,射線才能擊中。不過這樣基本要求相應的腳本比如相機都使用FixedUpdate來更新位置來避免抖動。

第二種方法。

對於60Hz的屏幕來說第一種方法已經沒啥問題了其實,FixedUpdate執行50次,和60幀沒多大區別,而且可以調整爲執行60次。但是我是144Hz的屏幕。在一秒裏,屏幕顯示了144幀,但是位移只更新了50次,看起來效果和在60Hz屏幕上沒有區別。難道就這麼浪費144HZ的屏幕?於是又決定不用FixedUpdate。

不用FixedUpdate的話用什麼呢,用Physics.SyncTransforms()。這個函數是手動更新物理系統,在調用時對Transform組件發生了變化的物體的物理系統進行更新,比如某個進行了移動的物體的Collider,Rigibody之類。使用這個就能在Update裏進行更新物理系統,射線就能射在更新後的collider上了。

關於Physics.SyncTransforms

 

但是呢。。這個如果在144次Update裏都執行了,就相當於144次物理更新。。是默認設置的2.88倍。。話雖如此,性能消耗比想象中的要小許多,自己考慮着用吧。然後也可以動態的更改這個刷新次數,比如不開機瞄用80的更新率,開的話用最大之類的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章