关于Unity粒子系统碰撞的几个坑
關(guān)于Unity粒子系統(tǒng)碰撞的幾個(gè)坑
最近公司的項(xiàng)目正好要用到粒子系統(tǒng)的碰撞,所以特意研究了一下。在實(shí)踐中遇到了很多問(wèn)題,所以借此文記錄一下學(xué)習(xí)的過(guò)程。而且學(xué)習(xí)過(guò)程中發(fā)現(xiàn)網(wǎng)上這方面文章極少,所以也算借這篇文章填補(bǔ)一下行業(yè)漏洞,順道給自己和后來(lái)者一個(gè)參考。本人接觸Unity時(shí)間也不算太長(zhǎng),如果下面哪里說(shuō)的不對(duì),歡迎各位大神糾正。
大量圖片預(yù)警
粒子與碰撞器的碰撞
這一部分官方用戶手冊(cè)有很明確的說(shuō)明,首先找到手冊(cè)下圖這一層級(jí)目錄 Collision Module,點(diǎn)進(jìn)去就能看到關(guān)于面板所有參數(shù)的介紹了:
這里我用的是Unity5.6.4的用戶手冊(cè),是本地文件,所以就不貼鏈接了,而且我相信愿意看這篇文章的人,應(yīng)該不至于找不到用戶手冊(cè)吧……
這篇手冊(cè)已經(jīng)講得詳細(xì)了,所以我們只討論一些文章里沒(méi)有提到的東西和提到了但是說(shuō)得比較模糊的東西。點(diǎn)進(jìn)去之后拉到文章最后你會(huì)看到這樣一段關(guān)于粒子碰撞的介紹:
簡(jiǎn)單的說(shuō)就是告訴你怎么用碰撞檢測(cè)腳本,但是請(qǐng)注意它說(shuō)的是 the object with the particle system, or the one with the Collider, or both 也就是說(shuō)只有帶有粒子系統(tǒng)或者帶有碰撞器的物體之間可以碰撞,而且經(jīng)過(guò)我的實(shí)踐發(fā)現(xiàn):只有一個(gè)帶有碰撞器組件的物體和一個(gè)帶有粒子系統(tǒng)并開(kāi)啟了粒子碰撞的物體之間碰撞才會(huì)觸發(fā)碰撞事件,其他任何情況都無(wú)法觸發(fā)粒子碰撞事件,如果您不信可以繼續(xù)看下去。
我們先來(lái)看一下簡(jiǎn)單的一種情況,也就是官方提供的這種情況,同時(shí)也是網(wǎng)上在我寫(xiě)這篇文章之前能搜到的最多的一種情況。所以我盡量用最短的篇幅介紹,如果您除了這種情況不會(huì)用到其他情況,那看完這一小節(jié)后下面的就不用看了。
我們打開(kāi)Unity直接實(shí)踐:
新建一個(gè)場(chǎng)景,創(chuàng)建一個(gè)平面當(dāng)?shù)孛?#xff0c;刪掉原有攝像機(jī)(我們會(huì)用FPS控制器,自帶相機(jī)),拖上來(lái)一個(gè)粒子(這里你隨意拖一個(gè)粒子就好,我用的是一個(gè)火焰粒子),開(kāi)啟粒子碰撞,我的設(shè)置如下,其中 Radius Scale 和 Colliders With 要根據(jù)你的實(shí)際粒子來(lái)設(shè)置,前者為碰撞器大小,后者為需要碰撞的層。
然后我為了節(jié)省時(shí)間是把標(biāo)準(zhǔn)資源中的FPS控制器拖進(jìn)來(lái)了,如果你有時(shí)間可以自己寫(xiě)一個(gè)FPS控制器……然后將控制器的標(biāo)簽和層都改成 “Player” ,如果沒(méi)有可以自己添加,只要記得添加好后把 Colliders With 也相應(yīng)改好就行。現(xiàn)在你選中粒子應(yīng)該可以在Scene視圖下看到粒子碰撞器了:
然后開(kāi)始寫(xiě)腳本吧,我就用最簡(jiǎn)單的代碼測(cè)試一下,代碼如下,腳本拖到粒子身上:
接下來(lái)運(yùn)行游戲即可,走到火焰上就會(huì)看到打印,說(shuō)明碰撞檢測(cè)生效。你應(yīng)該會(huì)注意到不但打印了而且打印了很多次,這說(shuō)明每一個(gè)粒子的碰撞都會(huì)單獨(dú)觸發(fā)。
截至到此,如果您不需要用到其他的碰撞(只是粒子和帶碰撞器組件的物體之間的碰撞),您可以不用往下看了。
粒子與射線的碰撞
接下來(lái)我們看一下射線與粒子的碰撞。這是我在做項(xiàng)目的時(shí)候,項(xiàng)目需要做一個(gè)準(zhǔn)星檢測(cè)前方區(qū)域是否有粒子然后變色的功能,自然得就想到要用射線檢測(cè)。還用剛才的場(chǎng)景,為了加強(qiáng)說(shuō)服力,我把 Colliders With 改成“Everything”,也就是可以和一切有碰撞的物體碰撞,然后寫(xiě)發(fā)射射線腳本,代碼如下,掛在FPS控制器身上。
using System.Collections; using System.Collections.Generic; using UnityEngine;public class ShootTest : MonoBehaviour {void Update (){RaycastHit hit;Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);if (Physics.Raycast(ray, out hit)){Debug.Log(hit.collider);if (hit.collider.gameObject.tag == "Fire"){Debug.Log("前方有火");}}} }同時(shí)為了加強(qiáng)說(shuō)服力我們把火焰粒子物體的標(biāo)簽改為“Fire”,并把層設(shè)置為“Player”,然后修改其身上的腳本如下,運(yùn)行游戲
sing System.Collections; using System.Collections.Generic; using UnityEngine;public class FireTest : MonoBehaviour {private void OnParticleCollision(GameObject other){Debug.Log("粒子發(fā)生碰撞");if (other.tag == "Player"){Debug.Log("一個(gè)玩家已死亡");}} }運(yùn)行后我們,當(dāng)我們把鏡頭轉(zhuǎn)向火時(shí)只打印了地面,無(wú)論怎么改變鏡頭朝向都沒(méi)有其他打印
經(jīng)過(guò)這個(gè)例子,我想大家已經(jīng)明白吧,首先射線不含有碰撞器組件,所以無(wú)法被粒子檢測(cè)到,其次,粒子碰撞只是粒子組件的一個(gè)屬性,所以也不能算成是碰撞器組件,而射線其實(shí)能夠檢測(cè)的也只有帶有碰撞器組件的物體。
為了驗(yàn)證我的射線代碼沒(méi)有問(wèn)題,我在場(chǎng)景中放了一個(gè)Cube,將其標(biāo)簽設(shè)置為“Fire”,如下:
這時(shí)運(yùn)行游戲可以看到如下打印,說(shuō)明我的射線代碼也沒(méi)有問(wèn)題:
綜上所述,得出結(jié)論 射線與粒子的碰撞器是無(wú)法發(fā)生碰撞 的。這是Unity這個(gè)引擎的問(wèn)題,不是我們用代碼可以解決的。
粒子與粒子的碰撞
最后讓我們看一下粒子和粒子之間的碰撞,這個(gè)也是我在項(xiàng)目中實(shí)踐發(fā)現(xiàn)的問(wèn)題,因?yàn)槲覀兊捻?xiàng)目需要做一個(gè)水粒子撲滅火粒子的功能,所以也是自然就像到粒子之間是否會(huì)發(fā)生碰撞。
廢話不多說(shuō),還是用實(shí)踐來(lái)檢驗(yàn):
還用剛才的場(chǎng)景,不過(guò)這次不必用FPS控制器,所以刪掉它,加一個(gè)攝像機(jī),調(diào)好角度能看到火焰粒子就好。然后加入一個(gè)水的粒子(這個(gè)粒子您也可以隨便加,只要保證粒子有初始速度,并且往火粒子那邊發(fā)射就好),水粒子也同樣要開(kāi)啟碰撞,設(shè)置同上,把 Colliders With 設(shè)置為“Everything”來(lái)增強(qiáng)說(shuō)服力,調(diào)節(jié)好碰撞器大小,不要勾選 Play On Awake 因?yàn)槲覀円么a控制粒子播放 ,接下來(lái)寫(xiě)腳本,代碼如下,腳本拖到水粒子身上。
運(yùn)行游戲,運(yùn)行后按下Q鍵,可以看到水粒子落下,但是沒(méi)有任何打印:
綜上所述,得出結(jié)論 粒子與粒子之間無(wú)法發(fā)生碰撞 。
對(duì)于以上問(wèn)題的我的解決方案
根據(jù)以上我們得出的結(jié)論,我們知道了 粒子的碰撞器只能和帶有碰撞器組件的物體發(fā)生碰撞并觸發(fā)事件 ,由于射線和粒子本身都不帶有碰撞器組件,所以是無(wú)法發(fā)生碰撞的,那么這兩種情況我們要怎么實(shí)現(xiàn)呢,以下僅是我個(gè)人能夠想到的解決方案,但不一定是最好的,如果有大神有更好的解決方案 歡迎提出:
對(duì)于射線無(wú)法檢測(cè)的解決方案
我能想到三種解決方法:
1、直接給需要檢測(cè)的粒子物體加觸發(fā)器,觸發(fā)器區(qū)域要比粒子碰撞器能到達(dá)的最遠(yuǎn)區(qū)域大,從而在玩家即將進(jìn)入粒子區(qū)域時(shí)通過(guò) On Trigger Enter 通知玩家,該方法無(wú)法在玩家離粒子較遠(yuǎn)時(shí)使用,并且也不會(huì)隨著玩家視野旋轉(zhuǎn)而產(chǎn)生不同的通知(例如煙區(qū)域和火區(qū)域的區(qū)分);
2、給粒子物體加一個(gè)空子物體,在子物體上加碰撞器,給子物體設(shè)置一個(gè)單獨(dú)的層,使該層的碰撞器不會(huì)碰到玩家,從而不會(huì)影響玩家移動(dòng),在下圖窗口中有碰撞矩陣的設(shè)置,可以修改各層之間的碰撞。然后還是玩家發(fā)射射線,來(lái)檢測(cè)子物體的碰撞器,該方法可能會(huì)影響到粒子的碰撞,不是很推薦,但是效果最好。
3、讓粒子系統(tǒng)所在物體向自身所在環(huán)形區(qū)域發(fā)射射線,檢測(cè)玩家后修改玩家身上記錄區(qū)域的變量,此方法彌補(bǔ)了前兩種方法的不足,但是最費(fèi)性能,不推薦在手機(jī)游戲種使用。
對(duì)于粒子之間無(wú)法檢測(cè)的解決方案
由于粒子的特殊性,暫時(shí)只能想到一種解決方法:
給其中一個(gè)粒子加一個(gè)碰撞器或者給其子物體加碰撞器。
但是請(qǐng)不要給粒子系統(tǒng)所在物體加剛體,我試過(guò),會(huì)發(fā)生奇怪的現(xiàn)象,暫時(shí)還沒(méi)有搞清楚這個(gè)現(xiàn)象的原因:粒子會(huì)掉在地上,彈跳幾下,然后迅速飛走…………
可以給加了碰撞器的子物體加剛體,然后在粒子播放時(shí)觸發(fā)剛體,從而到達(dá)和水粒子一起碰到火粒子的效果
以上內(nèi)容,都為我個(gè)人看法和實(shí)踐得出結(jié)論,如果說(shuō)的不妥當(dāng)處還望前輩高人指點(diǎn),完結(jié)撒花……
總結(jié)
以上是生活随笔為你收集整理的关于Unity粒子系统碰撞的几个坑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python3+OpenCV批处理图片
- 下一篇: Luogu P2615 神奇的幻方