2.5 事件函数 (OnCollisionEnter, OnTriggerEnter, OnMouseDown 等) 二、C# 脚本编程父章节领域 - 2.5 事件函数 (OnCollisionEnter, OnTriggerEnter, OnMouseDown 等) 2.5.1 事件函数概述 事件函数,顾名思义,是在特定事件发生时被 Unity 引擎自动调用的函数。这些事件涵盖了游戏运行的各个方面,例如物理碰撞、触发器交互、鼠标点击、渲染更新等等。使用事件函数,开发者无需手动轮询检测事件是否发生,引擎会在事件发生时主动通知脚本,并执行预先定义好的代码逻辑。这种事件驱动的编程模式极大地简化了游戏逻辑的编写,提高了代码的效率和可读性。
事件函数,顾名思义,是在特定事件发生时被 Unity 引擎自动调用的函数。这些事件涵盖了游戏运行的各个方面,例如物理碰撞、触发器交互、鼠标点击、渲染更新等等。使用事件函数,开发者无需手动轮询检测事件是否发生,引擎会在事件发生时主动通知脚本,并执行预先定义好的代码逻辑。这种事件驱动的编程模式极大地简化了游戏逻辑的编写,提高了代码的效率和可读性。
Unity 提供了丰富的事件函数,它们都以特定的命名规则和参数结构存在。通常,事件函数都以 On 开头,后面跟上事件的名称,例如 OnCollisionEnter 表示碰撞进入事件,OnTriggerEnter 表示触发器进入事件,OnMouseDown 表示鼠标按下事件。
事件函数通常附加在 MonoBehaviour 脚本上,并挂载到 GameObject 上才能生效。当游戏对象所关联的事件发生时,引擎会自动调用脚本中相应的事件函数。
物理碰撞事件函数用于处理游戏对象之间发生物理碰撞的情况。Unity 的物理引擎负责检测和处理碰撞,并在碰撞的不同阶段触发相应的事件函数。
定义: void OnCollisionEnter(Collision collision)
触发时机: 当依附脚本的 GameObject 的 Collider 组件与其他 GameObject 的 Collider 组件开始发生物理碰撞时,OnCollisionEnter 函数会被调用一次。
参数: Collision collision 参数包含了碰撞相关的详细信息,例如:
collision.contacts: 一个 ContactPoint[] 数组,包含了碰撞接触点的详细信息,例如接触点的位置、法线方向等。
collision.collider: 碰撞到的另一个 GameObject 的 Collider 组件。
collision.gameObject: 碰撞到的另一个 GameObject。
collision.rigidbody: 碰撞到的另一个 GameObject 的 Rigidbody 组件 (如果存在)。
collision.transform: 碰撞到的另一个 GameObject 的 Transform 组件。
collision.relativeVelocity: 相对速度。
代码实践:
using UnityEngine; public class CollisionDetection : MonoBehaviour { void OnCollisionEnter(Collision collision) { Debug.Log("碰撞发生!碰撞对象名称: " + collision.gameObject.name); // 获取碰撞点信息 if (collision.contacts.Length > 0) { ContactPoint contact = collision.contacts[0]; Debug.Log("第一个碰撞点位置: " + contact.point); Debug.Log("第一个碰撞点法线方向: " + contact.normal); } // 判断碰撞对象标签 if (collision.gameObject.CompareTag("Enemy")) { Debug.Log("碰撞到敌人!"); // 在这里处理与敌人的碰撞逻辑,例如扣血、触发特效等 } // 获取碰撞对象的Rigidbody并施加力 Rigidbody otherRigidbody = collision.rigidbody; if (otherRigidbody != null) { otherRigidbody.AddForce(Vector3.up * 10f, ForceMode.Impulse); // 向上施加一个冲量 } } }
内容详解:
触发条件: OnCollisionEnter 函数只有在两个 GameObject 的 Collider 组件都启用了碰撞检测,并且至少其中一个 GameObject 带有 Rigidbody 组件时才会被触发。 这是因为物理碰撞需要物理引擎的参与,而 Rigidbody 组件是使 GameObject 参与物理模拟的关键。 如果两个 GameObject 都没有 Rigidbody 组件,即使它们的 Collider 组件相交,也不会触发物理碰撞事件。
参数使用: Collision collision 参数提供了丰富的碰撞信息,可以用于实现各种复杂的碰撞逻辑。 例如,通过 collision.contacts 可以获取精确的碰撞点信息,用于实现粒子特效、碰撞火花等视觉效果。 通过 collision.gameObject 和 collision.collider 可以访问碰撞对象的属性和组件,进行进一步的逻辑判断和操作。 通过 collision.rigidbody 可以获取碰撞对象的刚体组件,并对其施加力、改变速度等。
应用场景: OnCollisionEnter 常用于处理需要精确物理碰撞响应的场景,例如:
子弹击中目标: 检测子弹与敌人或场景物体的碰撞,并根据碰撞信息计算伤害、触发击中特效。
角色与环境交互: 检测角色与地面、墙壁等环境物体的碰撞,用于实现角色移动、跳跃、攀爬等动作。
物体破碎: 检测物体受到足够大的冲击力时,触发破碎效果。
物理推动: 检测物体之间的碰撞,并根据碰撞信息计算物理推动力,实现物体之间的相互作用。
定义: void OnCollisionStay(Collision collision)
触发时机: 当依附脚本的 GameObject 的 Collider 组件与其他 GameObject 的 Collider 组件持续保持物理碰撞状态时,OnCollisionStay 函数会在每个物理引擎更新帧被持续调用。
参数: Collision collision 参数与 OnCollisionEnter 的参数相同,包含碰撞相关的详细信息。
代码实践:
using UnityEngine; public class CollisionStayDetection : MonoBehaviour { void OnCollisionStay(Collision collision) { Debug.Log("持续碰撞中... 碰撞对象名称: " + collision.gameObject.name); // 可以持续获取碰撞信息,例如持续施加力 Rigidbody otherRigidbody = collision.rigidbody; if (otherRigidbody != null) { otherRigidbody.AddForce(Vector3.right * 0.5f); // 持续向右施加力 } } }
内容详解:
触发条件: OnCollisionStay 的触发条件与 OnCollisionEnter 类似,需要两个 GameObject 的 Collider 组件都启用碰撞检测,并且至少其中一个带有 Rigidbody 组件。
持续调用: OnCollisionStay 的关键在于它的持续性,只要碰撞双方的 Collider 仍然保持相交状态,该函数就会在每个物理引擎更新帧被调用。物理引擎更新帧的频率由 Unity 的物理设置决定,通常为每秒多次。
应用场景: OnCollisionStay 适用于需要持续性碰撞响应的场景,例如:
持续伤害区域: 角色进入一个持续伤害区域 (例如毒气区域、火焰区域) 时,OnCollisionStay 可以持续检测角色是否还在区域内,并持续扣血。
摩擦力模拟: 当物体在地面上滑动时,OnCollisionStay 可以持续模拟摩擦力,使物体逐渐减速停止。
物体吸附: 当两个物体碰撞并需要吸附在一起时,OnCollisionStay 可以持续调整物体的位置和方向,保持吸附状态。
定义: void OnCollisionExit(Collision collision)
触发时机: 当依附脚本的 GameObject 的 Collider 组件与其他 GameObject 的 Collider 组件结束物理碰撞时,OnCollisionExit 函数会被调用一次。
参数: Collision collision 参数与 OnCollisionEnter 和 OnCollisionStay 的参数相同,包含碰撞相关的详细信息。
代码实践:
using UnityEngine; public class CollisionExitDetection : MonoBehaviour { void OnCollisionExit(Collision collision) { Debug.Log("碰撞结束!碰撞对象名称: " + collision.gameObject.name); // 在碰撞结束时执行一些清理或重置操作,例如停止持续伤害、移除吸附效果等 } }
内容详解:
触发条件: OnCollisionExit 的触发条件同样需要物理碰撞的基础,即两个 GameObject 的 Collider 组件都启用碰撞检测,并且至少其中一个带有 Rigidbody 组件。
碰撞结束标志: OnCollisionExit 函数标志着物理碰撞的结束。 当两个碰撞的 GameObject 分离,不再发生物理接触时,OnCollisionExit 会被调用。
应用场景: OnCollisionExit 常用于处理碰撞结束后的逻辑,例如:
离开伤害区域: 角色离开持续伤害区域时,停止扣血效果。
解除吸附: 当吸附状态结束时,解除吸附效果,使物体可以自由移动。
统计碰撞次数: 记录碰撞开始和结束的次数,用于统计碰撞事件。
触发音效或特效: 在碰撞结束时播放特定的音效或特效。
| 事件函数 | 触发时机 | 持续性 |
|---|---|---|
OnCollisionEnter |
碰撞开始时 (仅触发一次) | 否 |
OnCollisionStay |
碰撞持续期间 (每物理引擎更新帧触发) | 是 |
OnCollisionExit |
碰撞结束时 (仅触发一次) | 否 |
Graph TD 图示物理碰撞事件流程:
触发器事件函数用于处理 GameObject 的 Collider 组件被设置为 Is Trigger 属性时与其他 Collider 组件发生的交互。触发器与物理碰撞不同,它不会产生物理碰撞响应,而是仅仅用于检测进入、停留和离开触发器区域的事件。
定义: void OnTriggerEnter(Collider other)
触发时机: 当依附脚本的 GameObject 的 Collider 组件(设置为 Is Trigger) 与另一个 GameObject 的 Collider 组件开始发生重叠时,OnTriggerEnter 函数会被调用一次。
参数: Collider other 参数包含了触发到的另一个 GameObject 的 Collider 组件信息。
other: 触发到的另一个 GameObject 的 Collider 组件。
other.gameObject: 触发到的另一个 GameObject。
other.transform: 触发到的另一个 GameObject 的 Transform 组件。
other.attachedRigidbody: 触发到的另一个 GameObject 的 Rigidbody 组件 (如果存在)。
代码实践:
using UnityEngine; public class TriggerDetection : MonoBehaviour { void OnTriggerEnter(Collider other) { Debug.Log("触发器进入!触发对象名称: " + other.gameObject.name); // 判断触发对象标签 if (other.gameObject.CompareTag("Player")) { Debug.Log("玩家进入触发区域!"); // 在这里处理玩家进入触发区域的逻辑,例如打开门、显示提示信息等 } // 获取触发对象的脚本组件并调用方法 PlayerController playerController = other.GetComponent<PlayerController>(); if (playerController != null) { playerController.IncreaseScore(10); // 调用玩家脚本中的加分方法 } } }
内容详解:
触发条件: OnTriggerEnter 函数只有在依附脚本的 GameObject 的 Collider 组件被设置为 Is Trigger 属性时才会被触发。 触发器事件不需要 Rigidbody 组件参与,只要两个 GameObject 的 Collider 组件都启用了碰撞检测 (即使其中一个或两个都没有 Rigidbody ),并且其中一个的 Collider 设置为 Is Trigger, 就可以触发触发器事件。
参数使用: Collider other 参数提供了触发对象的信息,可以用于识别触发对象、访问其组件和属性。 与 Collision collision 参数相比,Collider other 参数的信息相对简单,因为它只关注触发对象本身,而不包含具体的碰撞点和物理碰撞信息。
应用场景: OnTriggerEnter 常用于实现非物理碰撞的触发逻辑,例如:
区域检测: 检测角色是否进入特定区域 (例如传送门区域、奖励区域、剧情触发区域)。
物品拾取: 当角色进入物品的触发器区域时,自动拾取物品。
陷阱触发: 当敌人进入陷阱的触发器区域时,触发陷阱效果。
UI 提示: 当玩家靠近某个交互对象时,显示 UI 提示信息。
定义: void OnTriggerStay(Collider other)
触发时机: 当依附脚本的 GameObject 的 Collider 组件(设置为 Is Trigger) 与另一个 GameObject 的 Collider 组件持续保持重叠状态时,OnTriggerStay 函数会在每个物理引擎更新帧被持续调用。
参数: Collider other 参数与 OnTriggerEnter 的参数相同,包含触发到的另一个 GameObject 的 Collider 组件信息。
代码实践:
using UnityEngine; public class TriggerStayDetection : MonoBehaviour { void OnTriggerStay(Collider other) { Debug.Log("触发器持续停留... 触发对象名称: " + other.gameObject.name); // 可以持续执行触发逻辑,例如持续治疗、持续检测状态等 if (other.gameObject.CompareTag("Player")) { // 持续治疗玩家 PlayerHealth playerHealth = other.GetComponent<PlayerHealth>(); if (playerHealth != null) { playerHealth.Heal(1); // 每帧治疗 1 点生命值 } } } }
内容详解:
触发条件: OnTriggerStay 的触发条件与 OnTriggerEnter 相同,需要依附脚本的 GameObject 的 Collider 组件设置为 Is Trigger 属性。
持续调用: OnTriggerStay 与 OnCollisionStay 类似,它也是一个持续调用的事件函数。 只要触发对象仍然停留在触发器区域内,OnTriggerStay 就会在每个物理引擎更新帧被调用。
应用场景: OnTriggerStay 适用于需要持续性触发响应的场景,例如:
持续治疗区域: 角色停留在治疗区域内时,持续回复生命值。
加速区域: 角色停留在加速区域内时,持续增加移动速度。
持续检测状态: 持续检测触发对象的状态,并根据状态变化执行相应的逻辑。
定义: void OnTriggerExit(Collider other)
触发时机: 当依附脚本的 GameObject 的 Collider 组件(设置为 Is Trigger) 与另一个 GameObject 的 Collider 组件结束重叠时,OnTriggerExit 函数会被调用一次。
参数: Collider other 参数与 OnTriggerEnter 和 OnTriggerStay 的参数相同,包含触发到的另一个 GameObject 的 Collider 组件信息。
代码实践:
using UnityEngine; public class TriggerExitDetection : MonoBehaviour { void OnTriggerExit(Collider other) { Debug.Log("触发器离开!触发对象名称: " + other.gameObject.name); // 在触发器离开时执行一些清理或重置操作,例如关闭门、隐藏提示信息等 if (other.gameObject.CompareTag("Player")) { Debug.Log("玩家离开触发区域!"); // 关闭门或隐藏提示信息 } } }
内容详解:
触发条件: OnTriggerExit 的触发条件与 OnTriggerEnter 和 OnTriggerStay 相同,需要依附脚本的 GameObject 的 Collider 组件设置为 Is Trigger 属性。
触发结束标志: OnTriggerExit 函数标志着触发器交互的结束。 当触发对象离开触发器区域,不再与触发器 Collider 重叠时,OnTriggerExit 会被调用。
应用场景: OnTriggerExit 常用于处理触发器交互结束后的逻辑,例如:
离开区域效果移除: 角色离开加速区域或治疗区域时,移除加速或治疗效果。
关闭门或隐藏提示: 当玩家离开交互区域时,关闭门或隐藏 UI 提示信息。
重置状态: 当敌人离开陷阱区域时,重置陷阱状态。
| 事件函数 | 触发时机 | 持续性 |
|---|---|---|
OnTriggerEnter |
触发器进入时 (仅触发一次) | 否 |
OnTriggerStay |
触发器持续停留期间 (每物理引擎更新帧触发) | 是 |
OnTriggerExit |
触发器离开时 (仅触发一次) | 否 |
Graph TD 图示触发器事件流程:
鼠标事件函数用于处理用户鼠标与 GameObject 交互的情况。Unity 提供了多个鼠标事件函数,涵盖了鼠标按下、抬起、进入、离开、悬停等不同的鼠标动作。
定义: void OnMouseDown()
触发时机: 当鼠标指针在 GameObject 的 Collider 组件上按下鼠标左键时,OnMouseDown 函数会被调用一次。
代码实践:
using UnityEngine; public class MouseClickDetection : MonoBehaviour { void OnMouseDown() { Debug.Log("鼠标左键按下!点击对象名称: " + gameObject.name); // 改变对象的颜色 GetComponent<Renderer>().material.color = Color.red; // 执行其他点击事件逻辑,例如播放音效、触发动画、打开UI界面等 } }
内容详解:
触发条件: OnMouseDown 函数需要依附脚本的 GameObject 具有 Collider 组件。 当鼠标指针位于 GameObject 的 Collider 上,并且按下鼠标左键时,OnMouseDown 函数会被调用。
鼠标左键: OnMouseDown 仅响应鼠标左键的按下事件。 如果需要响应鼠标右键或中键,需要使用其他输入事件检测方法 (例如 Input.GetMouseButtonDown)。
应用场景: OnMouseDown 常用于实现简单的鼠标点击交互,例如:
按钮点击: 模拟 UI 按钮的点击效果。
对象选择: 点击游戏场景中的对象进行选择。
物体交互: 点击物体触发交互事件 (例如打开门、拿起物品)。
游戏控制: 使用鼠标点击进行游戏操作 (例如射击、移动角色)。
除了 OnMouseDown,Unity 还提供了其他常用的鼠标事件函数,用于处理不同的鼠标交互场景:
OnMouseUp(): 鼠标左键在 GameObject 的 Collider 组件上抬起时调用。
OnMouseEnter(): 鼠标指针进入 GameObject 的 Collider 组件时调用 (仅触发一次)。
OnMouseExit(): 鼠标指针离开 GameObject 的 Collider 组件时调用 (仅触发一次)。
OnMouseOver(): 鼠标指针悬停在 GameObject 的 Collider 组件上时,在每个帧被持续调用。
代码实践 (示例 OnMouseEnter 和 OnMouseExit):
using UnityEngine; public class MouseHoverDetection : MonoBehaviour { void OnMouseEnter() { Debug.Log("鼠标进入!对象名称: " + gameObject.name); GetComponent<Renderer>().material.color = Color.yellow; // 鼠标进入时改变颜色 } void OnMouseExit() { Debug.Log("鼠标离开!对象名称: " + gameObject.name); GetComponent<Renderer>().material.color = Color.white; // 鼠标离开时恢复颜色 } }
内容详解:
OnMouseUp(): 通常与 OnMouseDown 配合使用,实现完整的点击交互流程 (按下 -> 执行操作 -> 抬起)。
OnMouseEnter() 和 OnMouseExit(): 用于检测鼠标指针进入和离开 GameObject 的 Collider 区域,可以实现鼠标悬停高亮、显示提示信息等效果。
OnMouseOver(): 与 OnMouseStay 和 OnTriggerStay 类似,OnMouseOver 也是一个持续调用的事件函数。 只要鼠标指针悬停在 GameObject 的 Collider 上,OnMouseOver 就会在每个帧被调用。 可以用于实现持续的鼠标悬停效果,例如持续显示信息、持续改变对象状态等。
| 事件函数 | 触发时机 | 持续性 |
|---|---|---|
OnMouseDown |
鼠标左键按下时 (仅触发一次) | 否 |
OnMouseUp |
鼠标左键抬起时 (仅触发一次) | 否 |
OnMouseEnter |
鼠标指针进入 Collider 时 (仅触发一次) | 否 |
OnMouseExit |
鼠标指针离开 Collider 时 (仅触发一次) | 否 |
OnMouseOver |
鼠标指针悬停在 Collider 上 (每帧持续触发) | 是 |
Graph TD 图示鼠标事件流程 (示例 OnMouseEnter, OnMouseOver, OnMouseExit):
Unity 提供了种类繁多的事件函数,开发者需要根据具体的游戏逻辑需求选择合适的事件函数。
物理碰撞事件函数 (OnCollisionEnter, OnCollisionStay, OnCollisionExit): 适用于需要精确物理碰撞响应的场景,例如子弹击中、角色与环境交互、物体破碎等。 需要确保参与碰撞的 GameObject 具有 Collider 组件,并且至少一个 GameObject 具有 Rigidbody 组件。
触发器事件函数 (OnTriggerEnter, OnTriggerStay, OnTriggerExit): 适用于非物理碰撞的触发逻辑,例如区域检测、物品拾取、陷阱触发、UI 提示等。 需要将 Collider 组件的 Is Trigger 属性设置为 true。
鼠标事件函数 (OnMouseDown, OnMouseUp, OnMouseEnter, OnMouseExit, OnMouseOver): 适用于处理用户鼠标与 GameObject 交互的场景,例如按钮点击、对象选择、物体交互、游戏控制等。 需要确保 GameObject 具有 Collider 组件。
在实际开发中,可以组合使用不同的事件函数,构建更加复杂和丰富的游戏逻辑。 例如,可以使用 OnCollisionEnter 检测子弹击中敌人,使用 OnTriggerEnter 检测角色进入奖励区域,使用 OnMouseDown 实现物体点击交互。