Unity锁定光标时无法触发3D EventTrigger事件的原因咨询
光标锁定时Unity OnPointerEnter事件不触发的解决方法
问题原因
当设置Cursor.lockState = CursorLockMode.Locked时,Unity默认的StandaloneInputModule会停止基于鼠标光标的交互检测——尽管光标确实处于屏幕中心,但系统判定此时鼠标位置不用于UI/物理交互,因此不会触发OnPointerEnter这类指针事件。
解决方法
方法1:自定义输入模块(推荐)
创建一个继承自StandaloneInputModule的自定义输入模块,强制光标锁定时使用屏幕中心作为鼠标位置:
using UnityEngine; using UnityEngine.EventSystems; public class LockedCursorInputModule : StandaloneInputModule { public override Vector2 GetMousePosition() { if (Cursor.lockState == CursorLockMode.Locked) { return new Vector2(Screen.width / 2f, Screen.height / 2f); } return base.GetMousePosition(); } }
使用步骤:
- 移除层级面板中
EventSystem对象上的StandaloneInputModule组件 - 添加上述自定义的
LockedCursorInputModule组件 - 运行后,光标锁定时EventSystem会自动用屏幕中心位置进行射线检测,正常触发
OnPointerEnter事件
方法2:手动模拟射线检测
在相机上挂载脚本,手动从屏幕中心发射射线,触发目标物体的EventTrigger事件:
using UnityEngine; using UnityEngine.EventSystems; public class LockedCursorRaycaster : MonoBehaviour { private EventSystem _eventSystem; private PhysicRaycaster _physicRaycaster; private GameObject _lastHoveredObj; void Awake() { _eventSystem = EventSystem.current; _physicRaycaster = GetComponent<PhysicRaycaster>(); } void Update() { if (Cursor.lockState != CursorLockMode.Locked) return; var centerPos = new Vector2(Screen.width / 2f, Screen.height / 2f); var pointerData = new PointerEventData(_eventSystem) { position = centerPos }; var results = new RaycastResult[1]; _physicRaycaster.Raycast(pointerData, results); if (results.Length > 0 && results[0].gameObject != null) { var currentObj = results[0].gameObject; if (currentObj != _lastHoveredObj) { // 触发OnPointerEnter TriggerEvent(currentObj, EventTriggerType.PointerEnter, pointerData); // 处理上一个物体的OnPointerExit if (_lastHoveredObj != null) { TriggerEvent(_lastHoveredObj, EventTriggerType.PointerExit, pointerData); } _lastHoveredObj = currentObj; } } else if (_lastHoveredObj != null) { TriggerEvent(_lastHoveredObj, EventTriggerType.PointerExit, pointerData); _lastHoveredObj = null; } } private void TriggerEvent(GameObject target, EventTriggerType eventType, BaseEventData eventData) { var trigger = target.GetComponent<EventTrigger>(); if (trigger == null) return; foreach (var entry in trigger.triggers) { if (entry.eventID == eventType) { entry.callback.Invoke(eventData); } } } }
这个脚本会在光标锁定时,持续检测屏幕中心的射线碰撞,手动触发PointerEnter和PointerExit事件,避免重复触发的问题。
内容的提问来源于stack exchange,提问作者Yuna
相关产品推荐
相关产品推荐

