如何在Unity中检测Meta XR可抓取对象的抓取与释放事件?
基于Meta XR Interactions SDK实现抓取/释放状态检测与日志输出
核心思路
Meta XR Interactions SDK的官方可抓取组件(XRGrabInteractable)以及你自定义的GrabInteractible/HandGrabInteractible,都可以通过事件订阅的方式监听抓取、释放状态。以下是具体实现方案:
方案1:基于自定义组件的事件扩展(适配你的GrabInteractible.cs)
如果你的GrabInteractible是基于SDK封装的自定义组件,先在组件内暴露抓取/释放事件:
using System; using UnityEngine; public class GrabInteractible : MonoBehaviour { // 已有抓取逻辑代码... // 定义抓取开始/结束的事件(供外部订阅) public event Action OnGrabStarted; public event Action OnGrabEnded; // 假设你已有触发抓取的方法,在逻辑执行时调用事件 private void TriggerGrab() { // 你的抓取逻辑(比如锁定位置、关联手部) OnGrabStarted?.Invoke(); } // 触发释放的方法 private void TriggerRelease() { // 你的释放逻辑(比如解除锁定、恢复物理状态) OnGrabEnded?.Invoke(); } }
然后创建一个通用的反馈脚本,挂在每个立方体上:
using UnityEngine; public class GrabFeedback : MonoBehaviour { [SerializeField] private GrabInteractible targetGrabComponent; [SerializeField] private string objectDisplayName; // 比如"红色立方体" private void OnEnable() { if (targetGrabComponent != null) { targetGrabComponent.OnGrabStarted += LogGrabEvent; targetGrabComponent.OnGrabEnded += LogReleaseEvent; } } private void OnDisable() { if (targetGrabComponent != null) { targetGrabComponent.OnGrabStarted -= LogGrabEvent; targetGrabComponent.OnGrabEnded -= LogReleaseEvent; } } private void LogGrabEvent() { Debug.Log($"\"{objectDisplayName}被抓取了!\""); } private void LogReleaseEvent() { Debug.Log($"\"{objectDisplayName}被释放了!\""); } }
配置步骤
- 给红、蓝、绿立方体分别挂上
GrabFeedback脚本 - 在Inspector面板中,将每个立方体的
GrabInteractible组件拖入targetGrabComponent字段 - 给
objectDisplayName分别赋值为"红色立方体"、"蓝色立方体"、"绿色立方体"
方案2:直接使用官方XRGrabInteractable组件
如果你的项目直接使用SDK官方的XRGrabInteractable组件,无需自定义事件,直接订阅官方提供的选择事件(抓取属于SDK中的"选择"操作):
using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; public class XRGrabFeedback : MonoBehaviour { [SerializeField] private XRGrabInteractable xrGrabInteractable; [SerializeField] private string objectDisplayName; private void OnEnable() { if (xrGrabInteractable != null) { xrGrabInteractable.selectEntered.AddListener(OnGrabbed); xrGrabInteractable.selectExited.AddListener(OnReleased); } } private void OnDisable() { if (xrGrabInteractable != null) { xrGrabInteractable.selectEntered.RemoveListener(OnGrabbed); xrGrabInteractable.selectExited.RemoveListener(OnReleased); } } private void OnGrabbed(SelectEnterEventArgs args) { Debug.Log($"\"{objectDisplayName}被抓取了!\""); } private void OnReleased(SelectExitEventArgs args) { Debug.Log($"\"{objectDisplayName}被释放了!\""); } }
关键注意事项
- 事件订阅必须在
OnDisable中取消,避免对象销毁后触发空引用异常 - 如果你使用
HandGrabInteractible,只需将上述代码中的GrabInteractible替换为HandGrabInteractible,确保该组件同样暴露了OnGrabStarted/OnGrabEnded事件
内容的提问来源于stack exchange,提问作者Yoav Linder
相关产品推荐
相关产品推荐

