Unity中使用代理器來做碰撞檢測,使一個腳本能控制多個碰撞箱的碰撞事件

問題概述
Unity在做碰撞檢測或觸發(fā)檢測時,由于Mono基類的限制,碰撞與觸發(fā)必須實現(xiàn)特殊函數(shù)、諸如OnCollisionEnter()才能檢測,而且檢測的主體還是與該腳本綁定的碰撞箱物體——一個腳本中只能檢測該腳本附著地同層級的單一碰撞箱所產(chǎn)生的碰撞,所以在處理子物體碰撞、多物體碰撞管理時,使用起來不是很靈活。
我被這狗屎問題困擾了多年,今天終于有了解決方案。
當(dāng)然這個方法只是解決此問題的眾多方法之一,成熟點的方法也許會用到接口與委托,這里我就使用我的方法。
文章作者:bilibili:_Iamsleepingnow
(甲)物理碰撞的條件
在Unity中,達成物理碰撞有如下的條件:
碰撞物體雙方都擁有碰撞箱(Collider抽象類及其子類)
碰撞物體至少有一方擁有剛體(Rigidbody類或CharacterController)
(乙)碰撞及觸發(fā)檢測方法
基礎(chǔ)的碰撞檢測方法如下:
private void OnCollisionEnter(Collision collision)
private void OnCollisionStay(Collision collision)
private void OnCollisionExit(Collision collision)
基礎(chǔ)的觸發(fā)檢測方法如下:
private void OnTriggerEnter(Collider other)
private void OnTriggerStay(Collider other)
private void OnTriggerExit(Collider other)
(丙)代理碰撞器
這里的設(shè)計理念是:使用代理器的方式讓一個中央腳本中的碰撞觸發(fā)檢測方法檢測到許多不同的碰撞箱身上的代理器收集到的碰撞與觸發(fā)信息,然后傳遞回中央腳本。
一、需要一個中央腳本,這個類負責(zé)管理所有的碰撞事件,在此命名為[ObjectManager]
二、需要一個代理碰撞器類,代理碰撞器會代替中央腳本去碰撞,命名[CollisionProxy]
三、代理器中需要加入需要代理的檢測方法,注意代理器與中央腳本都繼承MonoBehaviour
四、代理器里還需要聲明其所代理的中央腳本(基類)以及自身的代理序號。代理序號的作用是,當(dāng)此代理器將其收集到了碰撞信息傳遞給中央腳本時,中央腳本就可以通過序號來區(qū)分不同的代理器的頻道的信息了。
五、然后在中央腳本(基類)里定義與代理器中對應(yīng)的虛擬代理方法,需要在參數(shù)中傳遞碰撞信息與代理器自身。代理方法需要寫成虛擬方法,這樣此基類的子類就能用override重寫。
六、在代理器中調(diào)用中央腳本(基類)的代理方法,將信息傳入。
七、其實現(xiàn)在已經(jīng)做完了,目前可以加入一些測試用的行,僅做測試:(為了方便,我直接就在虛擬代理方法里測試了,但是之后在實際使用時,需要將新類繼承自這個中央腳本,然后重寫中央腳本中的代理方法。)
八、回到Unity中,創(chuàng)建一個球,攜帶碰撞箱,加一個剛體組件Rigidbody,取消使用重力useGravity,勾選應(yīng)用關(guān)節(jié)IsKinematic,這個物體就是需要被檢測的對象。然后再新建一個方體,移除其碰撞箱BoxCollider,并附上ObjectManager中央腳本。在方體的子級里添加三個空物體,并附上碰撞箱組件SphereCollider,并在每一個空物體上附著CollisionProxy代理器組件,將代理器組件中objectManager參數(shù)設(shè)置為其父級中央腳本,并更改每一個代理器中的proxyIndex序號。這里為了測試觸發(fā)方法,所以將代理器中的碰撞箱的IsTrigger勾上了。



九、運行工程,手動移動代理器的位置,中央腳本就會進行輸出:

十、測試成功,中央腳本獲取到了所有觸發(fā)信息(包括觸發(fā)的物體,代理器的信息)。接下來定義一個新腳本來繼承ObjectManager中央腳本,命名為ObjectManagerSon。在其中,重寫代理方法,稍微對測試行進行更改。
十一、將場景中方體身上的ObjectManager類替換成ObjectManagerSon類,并將其賦給三個代理器的objectManager參數(shù)。然后運行,測試如下:

總結(jié)
這個方法最大的問題是,如果一個腳本需要復(fù)雜碰撞檢測,則需要修改其繼承的父類。所以推薦將此方法寫在其原生父類中。如果該腳本無原生父類,即父類為Mono,那可能要考慮考慮將你的工程框架化了。