首先我们需要了解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);
}
}
网友评论