unity

Steam VR2.3.2射线与UGUI交互

2019-08-15  本文已影响0人  WOTTOW
UGUI交互.gif

首先我们需要了解UGUI的交互原理。从表面上看EventSystem控制UGUI的输入、处理、发布等一切UGUI交互的管理者。

EventSysytem是继承BaseInputModule这个基类实现输入、处理、发布事件。

BaseInputModule由此看就是一个输入模块的基类。StandaloneInputModule、TouchInputModule都是继承BaseInputModule从而现实,我们也可以继承BaseInputModule实现自定义的EventSysytem。

BaseInputModule是获取到目标后对UI的处理。那么缺少获取目标点的功能。由此出现BaseRaycaster基类模块 ,这个基类模块一般是看不出来的。

BaseRaycaster模块的功能就是发出射线确定目标点。PhysicsRaycaster, Physics2DRaycaster, GraphicRaycaster都是继承BaseRaycaster。

总的来理解:EventSysytem管理者,BaseInputModule输入,BaseRaycaster射线

这个脚本使用需要禁用StandaloneInputModule;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using Valve.VR;

public class TestB : BaseInputModule
{
    public Transform Root; 
    public Canvas canvas;
    public int LaserNum = 1;

    private Camera UICamera;

    public GameObject[] hitObjects;
    public GameObject[] pressedObjects;
    public PointerEventData[] pointEvents;

    protected override void Start()
    {
        base.Start();
        hitObjects = new GameObject[LaserNum];
        pressedObjects = new GameObject[LaserNum];
        pointEvents = new PointerEventData[LaserNum];
        CreateCamera();
    }

    private void CreateCamera()
    {
        // 用作反射射线
        UICamera = new GameObject("UICamera").AddComponent<Camera>();
        UICamera.transform.SetParent(Root);
        UICamera.transform.localPosition = Vector3.zero; 
        UICamera.fieldOfView = 5;                           
        UICamera.nearClipPlane = 0.01f;                     
        UICamera.stereoTargetEye = StereoTargetEyeMask.None; 
        UICamera.clearFlags = CameraClearFlags.Nothing;   
        UICamera.cullingMask = 0;                          

        canvas.worldCamera = UICamera;
    }

    public override void Process()
    {
        //清除选中的UI
        ClearSelection();

        bool hit = GUIRaycast(0);

        if (hit == false)
        {
            base.HandlePointerExitAndEnter(pointEvents[0], null);
            return;
        }

        //保持命中状态
        hitObjects[0] = pointEvents[0].pointerCurrentRaycast.gameObject;
        base.HandlePointerExitAndEnter(pointEvents[0], hitObjects[0]);

        //如果是按下
        if (IsPressDown())
        {
            pointEvents[0].pressPosition = pointEvents[0].position;
            pointEvents[0].pointerPressRaycast = pointEvents[0].pointerCurrentRaycast;
            pointEvents[0].pointerPress = null;

            //如果是碰撞到UI
            if (hitObjects[0] != null)
            {
                pressedObjects[0] = hitObjects[0];
                GameObject newPressed = ExecuteEvents.ExecuteHierarchy(pressedObjects[0], pointEvents[0], ExecuteEvents.pointerDownHandler);
                if (newPressed == null)
                {
                    newPressed = ExecuteEvents.ExecuteHierarchy(pressedObjects[0], pointEvents[0], ExecuteEvents.pointerClickHandler);
                    pressedObjects[0] = newPressed;

                }
                else
                {
                    pressedObjects[0] = newPressed;
                    ExecuteEvents.Execute(newPressed, pointEvents[0], ExecuteEvents.pointerClickHandler);
                }

                if (newPressed != null)
                {
                    pointEvents[0].pointerPress = newPressed;
                    pressedObjects[0] = newPressed;
                    Select(pressedObjects[0]);
                }
                pointEvents[0].pointerDrag = pressedObjects[0];
            }
        }

        //按下轨道
        if (IsPressUp())
        {
            //发布新闻结束活动
            if (pressedObjects[0])
            {
                ExecuteEvents.Execute(pressedObjects[0], pointEvents[0], ExecuteEvents.pointerUpHandler);
                pointEvents[0].rawPointerPress = null;
                pointEvents[0].pointerPress = null;
                pressedObjects[0] = null;
                hitObjects[0] = null;
            }
        }
    }

    /// <summary>
    /// 创建GUI射线
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    private bool GUIRaycast(int index)
    {
        if (pointEvents[index] == null)
        {
            pointEvents[index] = new PointerEventData(base.eventSystem);
        }
        else
        {
            pointEvents[index].Reset();
        }

        // 创建一个射线点
        pointEvents[index].delta = Vector2.zero;                                          
        pointEvents[index].position = new Vector2(Screen.width / 2, Screen.height / 2);     
        pointEvents[index].scrollDelta = Vector2.zero;                                      

        base.eventSystem.RaycastAll(pointEvents[index], m_RaycastResultCache);
        pointEvents[index].pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
        m_RaycastResultCache.Clear();

        return pointEvents[index].pointerCurrentRaycast.gameObject != null;
    }

    /// <summary>
    /// 清除选择
    /// </summary>
    public void ClearSelection()
    {
        if (base.eventSystem.currentSelectedGameObject)
        {
            base.eventSystem.SetSelectedGameObject(null);
        }
    }

    /// <summary>
    /// 选中
    /// </summary>
    /// <param name="go"></param>
    private void Select(GameObject go)
    {
        ClearSelection();
        if (ExecuteEvents.GetEventHandler<ISelectHandler>(go))
        {
            base.eventSystem.SetSelectedGameObject(go);
        }
    }

    private bool IsPressDown()
    {
        return SteamVR_Actions._default.GrabGrip.GetStateDown(SteamVR_Input_Sources.LeftHand);
    }

    private bool IsPressUp()
    {
        return SteamVR_Actions._default.GrabGrip.GetStateUp(SteamVR_Input_Sources.LeftHand);
    }
}
上一篇下一篇

猜你喜欢

热点阅读