You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 11:14:51