本章主要介绍通过VIU,实现利用手柄射线射线进入、点击、离开物体,以及射线拾取物体两大部分的内容。
1、前期准备
这里以第二章中的瞬移场景为基础进行讲解。链接如下:
我们将阶梯命名为Stairs,墙命名为Wall,方便我们测试手柄射线进入、点击、离开物体做准备。
2、3D物体检测射线的进入、点击、离开
编写Demo4_RayDetectionTest脚本,同时挂载在阶梯和墙上,触发前提条件:物体上已挂载Collider
using System.Collections.Generic;
using UnityEngine;
using HTC.UnityPlugin.Vive;
using UnityEngine.EventSystems;
public class Demo4_RayDetectionTest : MonoBehaviour,
IPointerEnterHandler,
IPointerExitHandler,
IPointerClickHandler
{
private HashSet<PointerEventData> hovers = new HashSet<PointerEventData>(); //射线Hover哈希表
/// <summary>
/// 射线进入
/// </summary>
/// <param name="eventData"></param>
public void OnPointerEnter(PointerEventData eventData)
{
if (hovers.Add(eventData) && hovers.Count == 1)
{
Debug.Log($"射线进入 {transform.name}");
}
}
/// <summary>
/// 射线离开
/// </summary>
/// <param name="eventData"></param>
public void OnPointerExit(PointerEventData eventData)
{
if (hovers.Remove(eventData) && hovers.Count == 0)
{
Debug.Log($"射线离开 {transform.name}");
}
}
/// <summary>
/// 射线点击
/// </summary>
/// <param name="eventData"></param>
public void OnPointerClick(PointerEventData eventData)
{
VivePointerEventData viveEventData = eventData as VivePointerEventData;
if (viveEventData != null)
{
if (viveEventData.viveButton == ControllerButton.Trigger)
{
Debug.Log($"射线点击 {transform.name}");
}
}
}
}
运行测试,阶梯和墙都会触发射线进入、点击、离开
2、3D物体拖拽
想要实现3D物体射线拾取的功能很简单,直接在物体上挂载Draggable组件即可,拖拽前提条件:物体上已挂载Collider,运行后效果:射线对准阶梯/墙体,扣动扳机键不放可拾取物体,握持键按住不放可拾取物体并移动到距离玩家一定距离,通过触摸板可以控制拾取距离的长短。
3、Draggable组件详解
(1)Init Grab Distance:初始拾取时,物体距玩家距离
(2)Ovveride Max Angular Velociry:覆盖最大角速度
(3)Unblockable Grab:无阻挡拾取
(4)Scrolling Spped:拉伸速率,数值越大,物体距离调调整速率越高
(5)Min Stretch Scale:缩放最小值,两个手柄射线同时拾取时生效
(6)Max Stretch Scale:缩放最大值,两个手柄射线同时拾取时生效
我们在实际开发过程中,更多的是实现功能和交互,如:玩家站在地面,需要把设备安装至天花板。
以上案例,我们除了可以在场景中放个梯子,拖拽设备瞬移到一定高度安装之外,还可以通过Draggable组件的After Grabbed、Befor Release、On Drop事件来通过直接在地面上通过射线拾取与调整距离就可以安装到指定位置。
编写Demo4_RayDrag脚本,同时挂载在阶梯和墙上,触发前提条件:物体上已挂载Collider
using UnityEngine;
public class Demo4_RayDrag : MonoBehaviour
{
private Draggable draggable;
private void Awake()
{
draggable = GetComponent<Draggable>();
}
private void Start()
{
draggable.afterGrabberGrabbed += Draggable_afterGrabberGrabbed;
draggable.beforeGrabberReleased += Draggable_beforeGrabberReleased;
draggable.onGrabberDrop += Draggable_onGrabberDrop;
}
private void Draggable_afterGrabberGrabbed()
{
Debug.Log($"{transform.name} 已被拿起");
}
private void Draggable_beforeGrabberReleased()
{
Debug.Log($"{transform.name} 放下之前");
}
private void Draggable_onGrabberDrop()
{
Debug.Log($"放下 {transform.name}");
}
}
不难看出,通过脚本中的三种状态,对于以上所述案例,解决思路为:
(1)被拿起后,安装位置高亮
(2)放下之前进行碰撞检测,若为安装位置,进行逻辑处理
(3)放下后,安装位置不高亮