Unity中使用VR手柄射线触发UI事件

这篇具有很好参考价值的文章主要介绍了Unity中使用VR手柄射线触发UI事件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

创建射线检测,确定起点和终点

public class LineController : SingletonMono<LineController>
{
    //属性
    [HideInInspector] public Vector3 pointStartPos, pointEndPos;
    [HideInInspector] public Vector3 lineDirection;
    [HideInInspector] public float lineRealLength;
    public Hand hand;
    public float rayLength = 20.0f;
    public LayerMask layerMask;

    //private UITriggerSystem currentTarget;
    private IEventHandle_VR currentTarget;
    /// <summary>
    /// 当前是否有触发对象
    /// </summary>
    public bool hasTarget
    {
        get { return currentTarget != null; }
    }

    //委托
    public Action OnEnterEvent;
    public Action OnExitEvent;
    public Action OnClickEvent;
    public Action<bool> OnActiveEvent;

    [HideInInspector] public bool active;
    private bool tempLineActive;

    public SteamVR_Action_Boolean menuAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("Menu");
    public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("Teleport");

    private IEventHandle_VR currentObj;
    private IEventHandle_VR pressObj;
    void Start()
    {
        hand = Player.instance.rightHand;
    }

    void Update()
    {
        //判断是否触发圆盘按钮,如果按下就关闭射线检测
        if (teleportAction.GetStateDown(hand.handType))
        {
            tempLineActive = active;
            SetActive(false);
        }
        else if (teleportAction.GetStateUp(hand.handType))
        {
            if (tempLineActive) SetActive(true);
        }

        //按下菜单键,呼出射线
        if (menuAction.GetStateDown(hand.handType))
        {
            SetActive(!active);
        }

        if (!active) return;//未开启射线检测

        pointStartPos = hand.transform.position;
        lineDirection = hand.transform.forward;
        Ray ray = new Ray(pointStartPos, lineDirection);
        if (Physics.Raycast(ray, out RaycastHit hit, rayLength, layerMask))
        {
            if (hit.transform.TryGetComponent(out IEventHandle_VR uiTriggerSystem))
            {
                pointEndPos = hit.point;
                lineRealLength = hit.distance;

                onTrigger(uiTriggerSystem);

                //Debug.DrawLine(pointStartPos, lineDirection * rayLength, Color.green);
            }
            else
            {
                onTrigger(null);

                pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
                lineRealLength = rayLength;
            }
        }
        else
        {
            onTrigger(null);

            //pointEndPos = lineDirection * rayLength * 1000.0f;//有较大的误差,还不知道怎么解决,希望大佬看到可以留言解决,暂时用下面的方法。
            pointEndPos = pointStartPos + (lineDirection * 10000.0f - pointStartPos).normalized * rayLength;
            lineRealLength = rayLength;

            //Debug.DrawLine(pointStartPos, lineDirection * rayLength, Color.magenta);
        }


        if (hand.grabPinchAction.GetStateDown(hand.handType))
        {
            if (currentObj == null) return;
            pressObj = currentObj;
            onClick(pressObj);
            pressObj.OnHandDown(hand);
        }
        if (hand.grabPinchAction.GetStateUp(hand.handType))
        {
            if (pressObj == null) return;
            pressObj.OnHandUp(hand);
            pressObj = null;
        }
        if (hand.grabPinchAction.GetState(hand.handType))
        {
            currentObj?.OnHandStay(hand);
        }
    }

    private void onTrigger(IEventHandle_VR target)
    {
        currentObj = target;
        if (target == null)//离开
        {
            if (currentTarget != null)
            {
                currentTarget.OnHandExit(hand);
                onExit(currentTarget);
                //Debug.Log($"离开{currentTarget}");
            }
            currentTarget = null;
        }
        else
        {
            //第一次
            if (currentTarget == null)
            {
                target.OnHandEnter(hand);
                onEnter(target);
                //Debug.Log($"进入{target}");
                currentTarget = target;
            }
            else if (currentTarget != target)//第n次
            {
                currentTarget.OnHandExit(hand);
                target.OnHandEnter(hand);

                onExit(currentTarget);
                onEnter(target);
                //Debug.Log($"进入{target},离开{currentTarget}");
                currentTarget = target;
            }
        }
    }
    /// <summary>
    /// 射线进入
    /// </summary>
    private void onEnter(IEventHandle_VR target)
    {
        //Debug.Log("进入");
        OnEnterEvent?.Invoke();
    }
    /// <summary>
    /// 射线进入
    /// </summary>
    private void onExit(IEventHandle_VR target)
    {
        //Debug.Log("离开");
        OnExitEvent?.Invoke();
    }
    /// <summary>
    /// 手柄扣动扳机
    /// </summary>
    private void onClick(IEventHandle_VR target)
    {
        //Debug.Log("手柄点击");
        OnClickEvent?.Invoke();
    }
    /// <summary>
    /// 激活或者关闭射线检测
    /// </summary>
    public void SetActive(bool _active)
    {
        OnActiveEvent?.Invoke(_active);
        active = _active;

        if (!_active) onTrigger(null);//当手柄关闭射线检测
    }
}

绘制射线

public class LineRenderer : MonoBehaviour
{
    private LineController lineController;
    public LineRenderer line;
    [SerializeField] GameObject targetPoint;
    void Start()
    {
        lineController = GetComponent<LineController>();

        createLine();
        createTargetPoint();

        lineController.OnEnterEvent += onEnter;
        lineController.OnExitEvent += onExit;
        lineController.OnActiveEvent += onActive;
    }

    // Update is called once per frame
    void Update()
    {
        line.SetPosition(0, lineController.pointStartPos);
        line.SetPosition(1, lineController.pointEndPos);

        targetPoint.SetActive(lineController.hasTarget);
        if (lineController.hasTarget)
        {
            targetPoint.transform.position = lineController.pointEndPos;
        }
    }
    void createLine()
    {
        line = Instantiate(line);
        line.useWorldSpace = true;
        line.startWidth = 0.0035f;
        line.endWidth = 0.0035f;
    }
    void createTargetPoint()
    {
        targetPoint = Instantiate(targetPoint);
    }
    private void onEnter()
    {
        line.material.SetFloat("_CenterIntensity", 10.0f);
    }
    private void onExit()
    {
        line.materials[0].SetFloat("_CenterIntensity", 2.0f);
    }
    private void onActive(bool active)
    {
        line.enabled = active;
    }
}

触发UI控件的各种状态,在手柄射线触发的时候调用

public class UIInputModule_VR : SingletonMono<UIInputModule_VR>
{
    private EventSystem eventSystem;
    private PointerEventData eventData;

    private GameObject currentObj;
    public HandTriggerType handTriggerType;
    void Start()
    {
        eventSystem = GetComponent<EventSystem>();
        eventData = new PointerEventData(eventSystem);
    }
    public void MouseEnter(GameObject obj)
    {
        currentObj = obj;
        eventData.pointerEnter = obj;
        ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerEnterHandler);
    }
    public void MouseExit(GameObject obj)
    {
        currentObj = null;
        ExecuteEvents.Execute(eventData.pointerEnter, eventData, ExecuteEvents.pointerExitHandler);
    }
    public void MouseDown(GameObject obj)
    {
        eventData.pointerPress = obj;
        ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerDownHandler);

        if(handTriggerType == HandTriggerType.Down)
        {
            ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerClickHandler);
        }
    }
    public void MouseUp(GameObject obj)
    {
        ExecuteEvents.Execute(eventData.pointerPress, eventData, ExecuteEvents.pointerUpHandler);
        ExecuteEvents.Execute(eventData.pointerPress, eventData, ExecuteEvents.deselectHandler);

        if (currentObj == eventData.pointerPress && handTriggerType == HandTriggerType.Up)
        {
            ExecuteEvents.Execute(obj, eventData, ExecuteEvents.pointerClickHandler);
        }
    }

    public enum HandTriggerType
    {
        Up, Down
    }
}

public static class UIInputModuleExtension
{
    public static void MouseEnter(this GameObject obj)
    {
        UIInputModule_VR.Instance.MouseEnter(obj);
    }
    public static void MouseExit(this GameObject obj)
    {
        UIInputModule_VR.Instance.MouseExit(obj);
    }
    public static void MouseDown(this GameObject obj)
    {
        UIInputModule_VR.Instance.MouseDown(obj);
    }
    public static void MouseUp(this GameObject obj)
    {
        UIInputModule_VR.Instance.MouseUp(obj);
    }
}

其他一些按钮相关的代码

public class UIComponent_VR : MonoBehaviour, IEventHandle_VR
{
    private CanvasRenderer canvasRenderer;
    private RectTransform rectTransform;
    private BoxCollider boxCollider;
    public bool triggerSizeEveryFrame = false;

    public Action OnHandEnterEvent;
    public Action OnHandExitEvent;

    public Action OnHandDownEvent;
    public Action OnHandStayEvent;
    public Action OnHandUpEvent;
    protected virtual void Start()
    {
        boxCollider = GetComponent<BoxCollider>();
        rectTransform = GetComponent<RectTransform>();
        canvasRenderer = GetComponent<CanvasRenderer>();

        boxCollider.isTrigger = true;
        boxCollider.size = new Vector3(rectTransform.rect.width, rectTransform.rect.height);
    }

    protected virtual void Update()
    {
        if (triggerSizeEveryFrame)
        {
            boxCollider.size = new Vector3(rectTransform.rect.width, rectTransform.rect.height);
        }
    }

    protected virtual void LateUpdate()
    {
        transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -canvasRenderer.absoluteDepth);
    }

    public virtual void OnHandEnter(Hand hand)
    {
        OnHandEnterEvent?.Invoke();
    }

    public virtual void OnHandExit(Hand hand)
    {
        OnHandExitEvent?.Invoke();
    }

    public virtual void OnHandDown(Hand hand)
    {
        OnHandDownEvent?.Invoke();
    }

    public virtual void OnHandStay(Hand hand)
    {
        OnHandStayEvent?.Invoke();
    }

    public virtual void OnHandUp(Hand hand)
    {
        OnHandUpEvent?.Invoke();
    }
}

public interface IEventHandle_VR
{
    /// <summary>
    /// 手柄进入触发
    /// </summary>
    public void OnHandEnter(Hand hand);
    /// <summary>
    /// 手柄离开触发
    /// </summary>
    public void OnHandExit(Hand hand);
    /// <summary>
    /// 手柄按下触发
    /// </summary>
    public void OnHandDown(Hand hand);
    /// <summary>
    /// 手柄停留触发
    /// </summary>
    public void OnHandStay(Hand hand);
    /// <summary>
    /// 手柄抬起触发
    /// </summary>
    public void OnHandUp(Hand hand);
}

Button代码

public class Button_VR : UIComponent_VR
{

    public override void OnHandEnter(Hand hand)
    {
        base.OnHandEnter(hand);

        hand.TriggerHapticPulse(1000);

        gameObject.MouseEnter();
    }
    public override void OnHandExit(Hand hand)
    {
        base.OnHandExit(hand);

        gameObject.MouseExit();
    }

    public override void OnHandDown(Hand hand)
    {
        base.OnHandDown(hand);

        gameObject.MouseDown();
    }

    public override void OnHandUp(Hand hand)
    {
        base.OnHandUp(hand);

        gameObject.MouseUp();
    }
}

文章来源地址https://www.toymoban.com/news/detail-514868.html

到了这里,关于Unity中使用VR手柄射线触发UI事件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【vr】【unity】白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置

    【白马VR课堂系列-VR开发核心基础05-主体设置-手柄对象的引入和设置】 https://www.bilibili.com/video/BV19D4y1N73i/?share_source=copy_webvd_source=7f5c96f5a58b7542fc6b467a9824b04e 上一节引入了XR Origin并进行了初步设置,运行测试时VR场景中的玩家视野已经可以跟随头盔了。 这一节来了解如何将手柄

    2024年02月05日
    浏览(36)
  • 【unity】Pico VR 开发笔记(基础篇)包括射线

    XR Interaction Tooikit 版本 2.3.2 一、环境搭建 其实官方文档已经写的很详细了,这里只是不废话快速搭建,另外有一项官方说明有误的,补充说明一下,在开发工具部分说明 插件安装——安装pico的sdk和XR Interaction Tooikit 环境配置——在场景里添加头显和手柄,并进行配置和项目

    2024年02月04日
    浏览(32)
  • Unity之OpenXR+XR Interaction Toolkit实现 监听VR手柄按键

    当我们接入XR Interaction Toolkit之后,我们可以很方便的做不同VR设备的适配,这在很大程度上提升了我们的开发效率,我们除了通过射线和物体交互之外,偶尔我们也会希望监听手柄上的部分按键的点击事件,今天我们就来实现如何监听VR手柄的按钮事件。 我们需要准备好Uni

    2024年02月05日
    浏览(51)
  • Unity+Pico 响应射线事件

    1、添加组件 为了让场景内的物体能够响应射线的操作,需要在该物体上添加“XR Simple Interactable”组件,并对射线的交互事件编写脚本看,最常用的是“Hover”和“Select”事件。 2、编写脚本 在编写脚本时,需要引入UnityEngine.XR.Interaction.Toolkit命名空间,另外,从步骤1中的截图

    2024年02月12日
    浏览(32)
  • Unity使用SteamVR2.0实现基本功能(瞬移,抓取物品,射线点击,UI交互等)

     把SteamVR的Player预制件拖到一个空场景,删掉场景内原本的相机 新建一个Plane,当做地板 找到SteamVR的人物瞬移控制器  Teleporting ,把它拖到场景里  我们需要在可以移动的区域,也就是碰撞器上,挂 TeleportArea 脚本 这个脚本会自动修改你的材质球 locked 该区域是否可以移动 markerAc

    2024年02月02日
    浏览(36)
  • Unity VR 开发教程 OpenXR+XR Interaction Toolkit(七)射线抓取

    此教程相关的详细教案,文档,思维导图和工程文件会放入 Spatial XR 社区 。这是一个高质量知识星球 XR 社区,博主目前在内担任 XR 开发的讲师。此外,该社区提供教程答疑、及时交流、进阶教程、外包、行业动态等服务。 社区链接: Spatial XR 高级社区(知识星球) Spatial

    2024年02月13日
    浏览(40)
  • Unity VR开发教程 OpenXR+XR Interaction Toolkit(七)射线抓取

    此教程相关的详细教案,文档,思维导图和工程文件会放入 Spatial XR 社区 。这是一个高质量知识星球 XR 社区,博主目前在内担任 XR 开发的讲师。此外,该社区提供教程答疑、及时交流、进阶教程、外包、行业动态等服务。 社区链接: Spatial XR 高级社区(知识星球) Spatial

    2023年04月08日
    浏览(27)
  • Unity UG算法能力可视化UI的PhysicsRaycaster (物理射线检测)组件的介绍及使用

    PhysicsRaycaster是Unity UGUI中的一个组件,用于在UI元素上进行物理射线检测。它可以检测鼠标或触摸事件是否发生在UI元素上,并将事件传递给相应的UI元素。 PhysicsRaycaster通过发射一条射线来检测UI元素。当射线与UI元素相交时,PhysicsRaycaster会将事件传递给相应的UI元素。 Event

    2024年01月20日
    浏览(46)
  • Unity VR:XR Interaction Toolkit 输入系统(Input System):获取手柄的输入

    输入系统是 VR 应用中非常重要的一部分。我们通常需要获取 VR 手柄上某个按键的输入,然后将其作用到应用中,比如按下手柄的 Grip 键进行抓取。在我的其他 Unity XR Interaction Toolkit 的开发教程里,已经有介绍如何去获取手柄的输入。那么这篇教程我将做一个总结,将相关的

    2024年02月12日
    浏览(28)
  • Unity射线穿透UI解决

    unity场景中,射线是可以穿透UI的。我用过很多版本,都有这个问题。 比如我现在用2020版本的unity做了个范例: 我在场景中新建了一个cube名叫:我秦始皇打钱。 点击这个物体就会出现log显示这个物体的名字,代码在下面。 运行之后确实会弹出这个log,这没有什么问题。如下

    2024年02月15日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包