本篇沒有推薦,純手工.....
目的:測試在多層對象中,碰撞消息的傳遞方式
先附上實驗總結(RigidBody同樣適用):
* b、消息的處理方式如下:遞歸調用接受消息的 RigidBody2D 的處理以及其子對象的處理,
* 直到觸發觸發該碰撞的對象層次(深度優先,只調用觸發碰撞的對象的父對象的處理)
* c、那麼被處理者:爲觸發碰撞的對象(只要是包含Collider即可)
實驗必備腳本有兩個:打印碰撞消息,和鼠標添加碰撞體
// 打印碰撞消息
public class TriggerCollidePrinter : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision)
{
Debug.LogFormat("{0} meet {1}, trigger enter.", gameObject.name , collision.gameObject.name);
}
private void OnTriggerExit2D(Collider2D collision)
{
Debug.LogFormat("{0} through {1}, trigger exit.", gameObject.name, collision.gameObject.name);
}
private void OnCollisionEnter2D(Collision2D collision)
{
Debug.LogFormat("{0} meet {1}, collision enter.", gameObject.name, collision.gameObject.name);
}
private void OnCollisionExit2D(Collision2D collision)
{
Debug.LogFormat("{0} through {1}, collision exit.", gameObject.name, collision.gameObject.name);
}
}
// 鼠標添加碰撞體
public class PrefabCreaterByMouse : MonoBehaviour {
public GameObject prefab; // 碰撞體的預製體,含 ColliderBox2D, RigidBody2D, ColliderPrinter
public int index = 0;
void Update()
{
// 左鍵點擊增加
if(Input.GetMouseButtonDown(0))
{
GameObject go = GameObject.Instantiate(prefab);
go.name = string.Format("ColliderPrinter{0}", index++);
Vector3 pos3 = Camera.main.ScreenToWorldPoint( Input.mousePosition );
pos3.z = go.transform.localPosition.z;
go.transform.localPosition = pos3;
}
// Ctrl + 右鍵點擊刪除全部
else if (Input.GetMouseButtonDown(1) && Input.GetKey(KeyCode.LeftControl))
{
RaycastHit2D[] hits = Physics2D.RaycastAll(
Camera.main.ScreenToWorldPoint(Input.mousePosition),
Vector2.zero,
Mathf.Infinity);
foreach (var hit in hits)
//GameObject.DestroyImmediate(hit.collider.gameObject);
GameObject.Destroy(hit.collider.gameObject);
}
// 右鍵點擊刪除
else if (Input.GetMouseButtonDown(1))
{
RaycastHit2D hit = Physics2D.Raycast(
Camera.main.ScreenToWorldPoint(Input.mousePosition),
Vector2.zero,
Mathf.Infinity);
if (hit.collider != null)
GameObject.Destroy(hit.collider.gameObject);
else
Debug.Log("Right button down, not hit;");
}
}
}
所有碰撞體,均添加到默認層,不存在層之間的屏蔽問題。
1、第一次,僅測試啓動:
對象結構和打印結果如下(由於命名很清楚,就不廢話解釋了,只說明一點:father和Child位置重疊,但是多個 father 之間位置是分開的):
這次實驗說明的問題:
1、啓動時候,是會觸發碰撞消息的
2、father4有Rigid而Child4沒有Rigid,理論上,此時應該向上搜索到father4,
然而father4不能和自己碰撞,因而只有father4處理Child4
3、而father3和child3相互碰撞,均由自己的rigidbody接受消息,並交由printer打印
2、father1/child1:
實驗方法:使用鼠標在father1和Child1重疊的部分左鍵點擊,增加一個ColliderPrinter
結構和打印結果如下:
這次實驗說明的問題:
1、ColliderPrinter和Child1的碰撞爲前三行
ColliderPrinter正常打印(第一行),過
father1的rigid接收到消息後,向下傳遞,father1和child1分別處理colliderPrinter
2、father1和ColliderPrinter相互處理,正常,過
3、father2/child2:
結構和打印結果如下:
這次實驗說明的問題:
1、前兩行是Child2的碰撞處理,與前一次實驗少了Child2的打印,因爲去除了打印的腳本
2、後兩行是father和ColliderPrinter的碰撞,正常,過
4、father3/child3:
結構和打印結果如下:
這次實驗說明的問題:
1、消息上面兩行和下面兩行分別是ColliderPrinter和Child3的相互處理以及ColliderPrinter和father3的相互處理
2、由於Child3自己有Rigid,所以消息自己接受,自己處理,相當於Child3和Father3是兩個無關的東西
5、father4/child4:
結構和打印結果如下:
這次實驗說明的問題:
Child4沒有Printer,消息並不會因此傳遞給father,而是直接截獲掉
6、小結和補充說明:
1、在father/Child重疊的情況下,並不一定都是先處理Child的碰撞再處理father的碰撞,筆者多次試驗過程中也是有順序隨機的現象
2、father1/child1和father2/child2應該是最常用的情況
在ColliderPrinter與Child1碰撞的過程中,一定先調用Child1,再調用father1,遞歸調用是深度優先的
3、在child上掛Rigid的情況,如果只修改father的rigid的velocity來完成運動的話,會造成father和child運動脫節
有兩種方法解決:
a、每個週期給child的位置更新
b、father速度更新的時候,給child的速度同時更新
計時可以解決,一般也都不這麼使用,除非特殊功能需要
4、最後再把結論嘮一遍:
* a、消息的接受者爲 RigidBody2D,如果本層沒有 RigidBody2D,向上(父)尋找
* b、消息的處理方式如下:遞歸調用接受消息的 RigidBody2D 的處理以及其子對象的處理,
* 直到觸發觸發該碰撞的對象層次(深度優先,只調用觸發碰撞的對象的父對象的處理)
* c、那麼被處理者:爲觸發碰撞的對象(只要是包含Collider即可)