Unity.VR.01简单交互
来源:互联网 发布:阿里云服务器的优势 编辑:程序博客网 时间:2024/06/08 03:13
【学习项目为Unity官方的VR Smaples,可以在Asset Store下载】
【参考官方学习教程Unity.learn.Virtual Reality】
VRSmaples中,有一个简单且可扩展的轻量级用户交互框架,包括3个主要脚本,分别是:
VRInput
定义点击、双击、滑动等事件,判定用户从设备的输入,来执行相应的事件。
using System;using UnityEngine;namespace VRStandardAssets.Utils{ // 在其它类中可以注册这些事件,能够满足大部分VR Games的输入需求 // 所有场景中必须使用这个类, 可以挂在摄像机上 public class VRInput : MonoBehaviour { //枚举类型:滑动方向 public enum SwipeDirection { NONE, UP, DOWN, LEFT, RIGHT }; public event ActionOnSwipe; // 滑动 public event Action OnClick; // 单击 public event Action OnDown; // 按下键 public event Action OnUp; // 松开键 public event Action OnDoubleClick; // 双击 public event Action OnCancel; // 取消键 [SerializeField] private float m_DoubleClickTime = 0.3f; //双击的最大时间间隔 [SerializeField] private float m_SwipeWidth = 0.3f; //用来判定是垂直滑动还是水平滑动 private Vector2 m_MouseDownPosition; // Fire1(鼠标左键)点击时的屏幕坐标点 private Vector2 m_MouseUpPosition; // Fire1(鼠标左键)松开时的屏幕坐标点 private float m_LastMouseUpTime; // 上一帧鼠标键松开的时间点 private float m_LastHorizontalValue; // 上一次键盘输入的水平方向移动的值,用来检测是否为有效滑动值 private float m_LastVerticalValue; // 上一次键盘输入的垂直方向移动的值,用来检测是否为有效滑动值 //鼠标双击的时间 public float DoubleClickTime{ get { return m_DoubleClickTime; } } //在Update中检测输入 private void Update() { CheckInput(); } private void CheckInput() { // 滑动枚举类型默认值设为NONE(没有滑动) SwipeDirection swipe = SwipeDirection.NONE; if (Input.GetButtonDown("Fire1")) { // 按下Fire1键时,记下屏幕坐标值(x,y) m_MouseDownPosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y); // 如果OnDown被订阅了,执行OnDown if (OnDown != null) OnDown(); } //这个if语句@是用来在松开Fire1键后,获取点击的坐标值 if (Input.GetButtonUp ("Fire1")) { // 松开Fire1键时,记下屏幕坐标值(x,y) m_MouseUpPosition = new Vector2 (Input.mousePosition.x, Input.mousePosition.y); // 通过DetectSwipe方法进行判定,确定滑动的方向 swipe = DetectSwipe (); } // 如果鼠标没有输入,则启动另一方法,进行键盘输入的滑动方向判定 if (swipe == SwipeDirection.NONE) swipe = DetectKeyboardEmulatedSwipe(); // 如果OnSwipe被订阅了,执行OnSwipe if (OnSwipe != null) OnSwipe(swipe); //这个if语句@是用来在松开Fire1键后,基于之前收集的信息来触发事件 if(Input.GetButtonUp ("Fire1")) { // 如果OnUp被订阅了,执行OnUp if (OnUp != null) OnUp(); //通过两次松开鼠标的时间差来判定双击是否有效 if (Time.time - m_LastMouseUpTime < m_DoubleClickTime) { // 如果OnDoubleClick被订阅了,执行OnDoubleClick if (OnDoubleClick != null) OnDoubleClick(); } else { //双击时间超过0.3秒,则判定为单击 //如果OnClick被订阅了,执行OnClick if (OnClick != null) OnClick(); } //用m_LastMouseUpTime记下这一次松开鼠标键的时间,用来在下一次再松开鼠标时计算时间间隔 m_LastMouseUpTime = Time.time; } //按下Cancel键,如果OnCancel被订阅了,执行OnCancel if (Input.GetButtonDown("Cancel")) { if (OnCancel != null) OnCancel(); } } //通过鼠标的输入判定滑动的方向 private SwipeDirection DetectSwipe () { // 获取鼠标松开时坐标点指向按下时坐标点的向量,进行归一化,得到一个单位向量 Vector2 swipeData = (m_MouseUpPosition - m_MouseDownPosition).normalized; // 这个单位向量的x坐标小于0.3,则进行垂直方向的滑动 bool swipeIsVertical = Mathf.Abs (swipeData.x) < m_SwipeWidth; // 这个单位向量的y坐标小于0.3,则进行水平方向的滑动 bool swipeIsHorizontal = Mathf.Abs(swipeData.y) < m_SwipeWidth; // y大于0,向上滑动 if (swipeData.y > 0f && swipeIsVertical) return SwipeDirection.UP; // y小于0,向下滑动 if (swipeData.y < 0f && swipeIsVertical) return SwipeDirection.DOWN; // x大于0,向右滑动 if (swipeData.x > 0f && swipeIsHorizontal) return SwipeDirection.RIGHT; // x小于0,向左滑动 if (swipeData.x < 0f && swipeIsHorizontal) return SwipeDirection.LEFT; // 以上条件都不满足时,则无滑动 return SwipeDirection.NONE; } //通过键盘的输入判定滑动的方向 private SwipeDirection DetectKeyboardEmulatedSwipe () { // 记下键盘输入的水平轴、垂直轴的移动值 float horizontal = Input.GetAxis ("Horizontal"); float vertical = Input.GetAxis ("Vertical"); // 输入值太小,则不是有效输入 bool noHorizontalInputPreviously = Mathf.Abs (m_LastHorizontalValue) < float.Epsilon; bool noVerticalInputPreviously = Mathf.Abs(m_LastVerticalValue) < float.Epsilon; // 记下这次的输入值,用于在下一次判定上一次的键盘是否进行了有效输入 m_LastHorizontalValue = horizontal; m_LastVerticalValue = vertical; // 垂直输入大于0且上一次没有输入,则向上滑动 if (vertical > 0f && noVerticalInputPreviously) return SwipeDirection.UP; // 垂直输入小于0且上一次没有输入,则向下滑动 if (vertical < 0f && noVerticalInputPreviously) return SwipeDirection.DOWN; // 水平输入大于0且上一次没有输入,则向右滑动 if (horizontal > 0f && noHorizontalInputPreviously) return SwipeDirection.RIGHT; // 水平输入大于0且上一次没有输入,则向左滑动 if (horizontal < 0f && noHorizontalInputPreviously) return SwipeDirection.LEFT; // 没有输入,则不滑动 return SwipeDirection.NONE; } private void OnDestroy() { // 这个对象被摧毁时,务必置空所有事件 OnSwipe = null; OnClick = null; OnDoubleClick = null; OnDown = null; OnUp = null; } }}
VREyeRaycaster
发出一条射线,通过射线获取到一个可交互物体;
编写方法订阅VRInput中的相应事件,对这个可交互物体(InteractiveItem)进行操作,执行该物体脚本(VRInteractiveItem)中的方法。
using System;using UnityEngine;namespace VRStandardAssets.Utils{ //投射一条射线来尝试获取一个可交互的对象并与之进行交互 //这个脚本一般放在摄像机上 public class VREyeRaycaster : MonoBehaviour { public event ActionOnRaycasthit; // 凝视到一个带有碰撞体的对象时进行调用 [SerializeField] private Transform m_Camera; [SerializeField] private LayerMask m_ExclusionLayers; // 排除射线的蒙版层 [SerializeField] private Reticle m_Reticle; // 准心 [SerializeField] private VRInput m_VrInput; // 脚本VRInput [SerializeField] private bool m_ShowDebugRay; // 是否需要调试线 [SerializeField] private float m_DebugRayLength = 5f; // 调试光线长度 [SerializeField] private float m_DebugRayDuration = 1f; // 调试光线显示时间 [SerializeField] private float m_RayLength = 500f; // 光线投射的长度 private VRInteractiveItem m_CurrentInteractible; //当前交互物体 private VRInteractiveItem m_LastInteractible; //上个交互物体 // 使其它类获取当前的交互对象 public VRInteractiveItem CurrentInteractible { get { return m_CurrentInteractible; } } private void OnEnable() { m_VrInput.OnClick += HandleClick; m_VrInput.OnDoubleClick += HandleDoubleClick; m_VrInput.OnUp += HandleUp; m_VrInput.OnDown += HandleDown; } private void OnDisable () { m_VrInput.OnClick -= HandleClick; m_VrInput.OnDoubleClick -= HandleDoubleClick; m_VrInput.OnUp -= HandleUp; m_VrInput.OnDown -= HandleDown; } //不断地投射射线来尝试获取交互对象 private void Update() { EyeRaycast(); } private void EyeRaycast() { // 绘制一条蓝色的调试线 if (m_ShowDebugRay) { Debug.DrawRay(m_Camera.position, m_Camera.forward * m_DebugRayLength, Color.blue, m_DebugRayDuration); } // 生成一条光线,从相机坐标点,射向前方 Ray ray = new Ray(m_Camera.position, m_Camera.forward); RaycastHit hit; // 射线射到任何碰撞器时,判定为真 if (Physics.Raycast(ray, out hit, m_RayLength, ~m_ExclusionLayers)) { VRInteractiveItem interactible = hit.collider.GetComponent (); //从投射点的碰撞器获取到该交互对象 m_CurrentInteractible = interactible; // 射到一个交互物体,且不是上一个射到的交互物体,则调用这个交互物体的Over方法 if (interactible && interactible != m_LastInteractible) interactible.Over(); // 如果射到的交互物体不是上一个射到的交互物体,则调用方法停用上一个交互物体 if (interactible != m_LastInteractible) DeactiveLastInteractible(); m_LastInteractible = interactible; // 有物体被射中,通过Reticle中的SetPosition方法来设定准心坐标 if (m_Reticle) m_Reticle.SetPosition(hit); if (OnRaycasthit != null) OnRaycasthit(hit); } else { // 没有物体被射中时,停用上一个交互物体 DeactiveLastInteractible(); m_CurrentInteractible = null; // 设置准心位置 if (m_Reticle) m_Reticle.SetPosition(); } } private void DeactiveLastInteractible() { if (m_LastInteractible == null) return; m_LastInteractible.Out(); m_LastInteractible = null; } private void HandleUp() { if (m_CurrentInteractible != null) m_CurrentInteractible.Up(); } private void HandleDown() { if (m_CurrentInteractible != null) m_CurrentInteractible.Down(); } private void HandleClick() { if (m_CurrentInteractible != null) m_CurrentInteractible.Click(); } private void HandleDoubleClick() { if (m_CurrentInteractible != null) m_CurrentInteractible.DoubleClick(); } }}
VRInteractiveItem
定义凝视、停止凝视、单击、双击等事件,放入相应的各种方法中等待触发后执行。
using System;using UnityEngine;namespace VRStandardAssets.Utils{ // 这个脚本应该放在需要交互的游戏对象上,用户通过凝视可以激活这个对象 // 定义了各种输入行为的事件,在其它类中可以进行注册,来实现具体的交互行为 public class VRInteractiveItem : MonoBehaviour { public event Action OnOver; // 凝视 public event Action OnOut; // 停止凝视 public event Action OnClick; // 单击 public event Action OnDoubleClick; // 双击 public event Action OnUp; // 松开键 public event Action OnDown; // 按下键 protected bool m_IsOver; public bool IsOver { get { return m_IsOver; } // 当前物体是否被凝视 } //当检测到适当的设备输入时,下面这些方法会被VREyeRaycaster调用 //这些事件只有被订阅了时,才会被调用 public void Over() { m_IsOver = true; if (OnOver != null) OnOver(); } public void Out() { m_IsOver = false; if (OnOut != null) OnOut(); } public void Click() { if (OnClick != null) OnClick(); } public void DoubleClick() { if (OnDoubleClick != null) OnDoubleClick(); } public void Up() { if (OnUp != null) OnUp(); } public void Down() { if (OnDown != null) OnDown(); } }}
总结:
VRInput主要用来检测设备输入并且定义各种按键事件,在检测到适当的输入时执行相应的事件;
VREyeRaycaster用来通过凝视寻找可以交互的对象(VRInteractiveItem),用适当的方法注册VRInput中的按键事件,这些方法用来调用可交互对象中的相应方法;
VRInteractiveItem中各种方法中,都是由该类重新定义的各种相应的事件,这些事件再被其它的类中具体的方法注册,来实现具体的交互方法。
1 0
- Unity.VR.01简单交互
- Unity.VR.04MainMenu场景的交互
- Unity VR游戏开发干货教程:VR中的交互方式
- Unity VR游戏开发干货教程:VR中的交互方式
- Unity Editor VR告诉你,建立VR场景很简单
- Unity VR简单操作原理方法
- Unity.VR.02凝视点(准心)及其交互
- Unity中Oculus VR的UI凝视交互
- 【VR】VR中的交互
- 【VR开发】htc vive+unity 3D 简单保龄球游戏
- VR开发——Unity中导入常用的VR开发插件及简单使用
- Unity 与 Web 的简单交互
- unity与iOS之间的简单交互
- unity与Android之间的简单交互
- VR之Unity 开发Pico测试之UI和Object的交互
- VR交互方式
- Unity VR 优化
- unity VR优化
- 谈谈函数的调用过程,栈帧的创建和销毁。
- 动态规划练习--21(三角形最佳路径问题)
- 进程间通讯之概念
- C#141课的主要内容
- 动态规划―吃糖果
- Unity.VR.01简单交互
- Targeted Topic Modeling for Focused Analysis(TTM的理解)
- java 基于UDP的Socket网络通信
- BZOJ 3316: JC loves Mkk
- 转-WPF之Binding深入探讨
- Ada and Cycle SPOJ
- PS 滤镜算法原理 ——马赛克
- C#中实现并发的几种方法的性能测试
- Ceilometr: 7、Gnocchi命令行使用