查看: 1122|回复: 2
打印 上一主题 下一主题

[经验分享] Unity3D碰撞检测中OnTriggerXXX和OnCollisionXXX的功能解析

[复制链接]

0

主题

1

听众

65

积分

设计初学者

Rank: 1

纳金币
6
精华
0

活跃会员 灌水之王

跳转到指定楼层
楼主
发表于 2014-9-19 22:11:45 |只看该作者 |倒序浏览

OnTriggerXXX指的是OnTriggerEnter、OnTriggerExit和OnTriggerStay这三个消息,OnCollisionXXX指的是OnCollisionEnter、OnCollisionExit和OnCollisionStay这三个消息,它们都是用来处理不同物体在不同状态下消息的反馈,对它们的使用说明如下。

设现有A、B两个物体,且A物体正向B移动,B物体保持静止状态,如图10-22:

QQ截图20140919221508.png

则:

(1)若A中无Rigidbody组件,则B中无论是否含有Rigidbody组件,A都将穿越B物体,并且A和B脚本中的OnTriggerXXX和OnCollisionXXX方法都不会被调用。

(2)若A中含有Rigidbody组件,则B中无论是否还有Rigidbody组件,只要B中含有Collider类组件,A和B脚本中的OnTriggerXXX方法或OnCollisionXXX方法会被调用,到底调用哪静态方法要看A和B物体中Collider类组件中的IsTrigger是否被选中(参考第(3)、(4)条)。总之,要激活OnTriggerXXX方法或OnCollisionXXX方法必须使得移动的物体中含有Rigidbody组件。

(3)若A中含有Rigidbody组件,B中含有Collider类组件,当A和B物体中Collider类组件的IsTrigger都没有选中时(即在Inspector面板中IsTrigger不要打勾),A和B脚本中的OnCollisionXXX类的方法就会被调用,而OnTriggerXXX静态方法则不会被调用。

(4)若A中含有Rigidbody组件,B中含有Collider类组件,当A和B物体中的Collider类组件的IsTrigger至少有一个被选中时,A和B物体脚本中的OnTriggerXXX静态方法会被调用,而OnCollisionXXX静态方法不会被调用。

(5)当符合OnCollisionXXX静态方法激活条件时,A不可穿越B物体,A会与B发生弹性碰撞。

(6)当符合OnTriggerXXX静态方法激活条件时,A会穿越B物体,即A、B物体的运动行为互不影响,只是反馈了两个物体的接触状态:未接触、开始接触、接触中、互相分离。

(7)OnTriggerEnter或OnCollisionEnter方法会在A刚开始接触B时被调用,且在A、B分离前只被调用一次。

(8)OnTriggerStay或OnCollisionStay方法会在A和B保持接触状态时被调用,且在A、B分离前每帧都会被调用。

(9)OnTriggerExit或OnCollisionExit方法会在A、B刚分离时被调用,且只被调用一次。

实例演示:下面通过实例演示OnTriggerXXX类方法和OnCollisionXXX类方法的使用,在本实例演示中,包括主程序脚本和物体A、B中的脚本。


主程序脚本,用于控制A、B的移动。


[csharp] view plaincopy


  • usingUnityEngine;  
  • usingSystem.Collections;  
  •    
  • public classTriggerOrCollision_ts : MonoBehaviour  
  • {  
  •     public GameObject A, B;  
  •     Vector3 p_a, p_b;  
  •     int which_change = -1;  
  •     //将物体A、B的初始位置赋给p_a和p_b,用于重置物体组件时使用  
  •     void Start()  
  •     {  
  •         p_a = A.transform.position;  
  •         p_b = B.transform.position;  
  •     }  
  •     //控制物体A的移动  
  •     void FixedUpdate()  
  •     {  
  •         if (which_change == 0)  
  •         {  
  •             A.transform.Translate(Vector3.forward *Time.deltaTime);  
  •         }  
  •     }  
  •     void OnGUI()  
  •     {  
  •         //当A物体无Rigidbody组件时  
  •         //无论B是否有Rigidbody都不会激活A和B物体的脚本中的OnCollisionXXX或OnTriggerXXX方法  
  •         if (GUI.Button(newRect(10.0f, 10.0f, 280.0f, 45.0f), "A物体无Rigidbody组件"))  
  •         {  
  •             inists();  
  •             which_change = 0;  
  •             if (A.GetComponent<Rigidbody>())  
  •             {  
  •                 Destroy(A.GetComponent<Rigidbody>());  
  •             }  
  •         }  
  •         //当A物体有Rigidbody组件时  
  •         //一定会激活A和B物体的脚本中的OnCollisionXXX或OnTriggerXXX方法  
  •         if (GUI.Button(newRect(10.0f, 60.0f, 280.0f, 45.0f), "A有Rigidbody组件,B无Rigidbody组件"))  
  •         {  
  •             inists();  
  •             which_change = 1;  
  •             if (!A.GetComponent<Rigidbody>())  
  •             {  
  •                 A.AddComponent<Rigidbody>();  
  •                 A.rigidbody.useGravity = false;  
  •             }  
  •             if (B.GetComponent<Rigidbody>())  
  •             {  
  •                 Destroy(B.GetComponent<Rigidbody>());  
  •             }  
  •             A.rigidbody.velocity = Vector3.forward;  
  •         }  
  •         //当A物体有Rigidbody组件时  
  •         //且A与B物体IsTrigger都未选中时,只会激活A和B物体的脚本中的OnCollisionXXX方法  
  •         if (GUI.Button(newRect(10.0f, 110.0f, 280.0f, 45.0f), "A与B物体IsTrigger都未选中"))  
  •         {  
  •             inists();  
  •             which_change = 2;  
  •             A.GetComponent<Collider>().isTrigger =false;  
  •             B.GetComponent<Collider>().isTrigger =false;  
  •             if (!A.GetComponent<Rigidbody>())  
  •             {  
  •                 A.AddComponent<Rigidbody>();  
  •                 A.rigidbody.useGravity = false;  
  •             }  
  •             A.rigidbody.velocity = Vector3.forward;  
  •         }  
  •         //当A物体有Rigidbody组件时  
  •         //且A与B物体IsTrigger至少有一个被选中时,只会激活A和B物体的脚本中的OnTriggerXXX方法  
  •         if (GUI.Button(newRect(10.0f, 160.0f, 280.0f, 45.0f), "A物体IsTrigger被选中"))  
  •         {  
  •             inists();  
  •             which_change = 3;  
  •             A.GetComponent<Collider>().isTrigger =true;  
  •             if (!A.GetComponent<Rigidbody>())  
  •             {  
  •                 A.AddComponent<Rigidbody>();  
  •                 A.rigidbody.useGravity = false;  
  •             }  
  •             A.rigidbody.velocity = Vector3.forward;  
  •         }  
  •         if (GUI.Button(newRect(10.0f, 210.0f, 280.0f, 45.0f), "重置"))  
  •         {  
  •             inists();  
  •             which_change = 4;  
  •         }  
  •     }  
  •     //初始化数据  
  •     void inists()  
  •     {  
  •         if (A.GetComponent<Rigidbody>())  
  •         {  
  •             A.rigidbody.velocity = Vector3.zero;  
  •            A.rigidbody.angularVelocity = Vector3.zero;  
  •         }  
  •         if (B.GetComponent<Rigidbody>())  
  •         {  
  •             B.rigidbody.velocity = Vector3.zero;  
  •             B.rigidbody.angularVelocity = Vector3.zero;  
  •         }  
  •         A.transform.position = p_a;  
  •         A.transform.rotation = Quaternion.identity;  
  •         B.transform.position = p_b;  
  •         B.transform.rotation = Quaternion.identity;  
  •     }  
  • }  


在这段代码中,首先声明了两个GameObject类型的变量A和B,然后在Start方法中将A、B物体的初始位置赋给p_a和p_b,用于重置物体时使用,最后在OnGUI方法中定义了五个不同功能的Button,用于演示OnTriggerXXX类方法和OnCollisionXXX类方法的不同作用,具体请参考代码中注释。

A物体的脚本(B物体的脚本与此类似,不再赘述。)


[csharp] view plaincopy


  • usingUnityEngine;  
  • usingSystem.Collections;  
  •    
  • public classATorC_ts : MonoBehaviour  
  • {  
  •     //开始接触  
  •     void OnTriggerEnter(Collider other)  
  •     {  
  •         Debug.Log("A物体的OnTriggerEnter被调用,被接触的物体为" + other.name);  
  •     }  
  •     //结束接触  
  •     void OnTriggerExit(Collider other)  
  •     {  
  •         Debug.Log("A物体的OnTriggerExit被调用,被接触的物体为" + other.name);  
  •     }  
  •     //保持接触  
  •     void OnTriggerStay(Collider other)  
  •     {  
  •         Debug.Log("A物体的OnTriggerStay被调用,被接触的物体为" + other.name);  
  •     }  
  •     //开始碰撞  
  •     void OnCollisionEnter(Collision collision)  
  •     {  
  •         Debug.Log("A物体的OnCollisionEnter被调用,被碰撞的物体为" + collision.gameObject.name);  
  •     }  
  •     //退出碰撞  
  •     void OnCollisionExit(Collision collision)  
  •     {  
  •         Debug.Log("A物体的OnCollisionExit被调用,被碰撞的物体为" +collision.gameObject.name);  
  •     }  
  •     //保持碰撞  
  •     void OnCollisionStay(Collision collision)  
  •     {  
  •         Debug.Log("A物体的OnCollisionStay被调用,被碰撞的物体为" + collision.gameObject.name);  
  •     }  
  • }  


在这段代码中,只是在OnTriggerXXX类方法和OnCollisionXXX类方法中打印出A物体被接触或被碰撞后的相应信息,请读者自行运行程序,观察在不同操作条件下的Debug输出结果。


本文章摘自图书《Unity API解析》,源码下载地址:http://www.ituring.com.cn/book/1474


分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏1 支持支持0 反对反对0
回复

使用道具 举报

hyui    

1

主题

2

听众

6671

积分

高级设计师

Rank: 6Rank: 6

纳金币
2715
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2014-9-20 01:31:14 |只看该作者
Good to know !
回复

使用道具 举报

0

主题

2

听众

4092

积分

中级设计师

Rank: 5Rank: 5

纳金币
530
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2014-9-20 07:43:59 |只看该作者
thank you for sharing
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-4 04:44 , Processed in 0.100202 second(s), 34 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部