本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/53915229
作者:cartzhang

Unity的 Steam VR插件本身也带有事件处理。但是我还想把事件给解耦出来,这样方便在各个项目中,不用关心硬件的各种处理而只用关心使用的,且可以任意的通过接受事件来触发相应的操作。

项目的参考图片可下载地址:https://github.com/cartzhang/ImgSayVRabc/tree/master/ViveEventDemo/Img

今天我们说谈论的就是下面这个东西:


图1.1

一、所需资源

所需资源,很少。
需要用Steam VR插件 ,可以从Untiy商店下载。当然你可以使用文章后面给出本工程的导出包,文章后面有下载地址:


图0

但是电脑还是需要安装steam的,这个暂时还是需要翻墙的。你懂的,翻墙是一项技能。
安装后:


图4
点击右上角的VR字样,链接你的Vive设备,然后就可以看到他们的状态了。
这里设备的各种设置方法和使用就不逐个说明讲解了。网上搜索下吧,或去官方最正宗的。


图6

当然也可以使用桌面的快捷方式,当然前提是你有:


图5

二、制作Demo

首先,打开Unity 导入插件


图1


图2

然后,可以打开其给点样例来看看:


图3

接着就是,添加代码,给Controller添加控制代码:


图7

再然后就是需要自己写代码。

三、消息解耦

先说下,这个代码来自于其他同事,我基本没太多修改。但是确实很好用,非常感谢!!若有问题,请及时告知。

消息发送机制:


namespace SLQJ
{/// <summary>/// 消息分发,解耦/// </summary>public class NotificationManager{public static NotificationManager Instance { get { return SingletonProvider<NotificationManager>.Instance; } }public delegate void MsgCallback(MessageObject eb);/// <summary>/// 回调队列/// </summary>private Dictionary<string, List<MsgCallback>> registedCallbacks = new Dictionary<string, List<MsgCallback>>();/// <summary>/// 延迟消息队列/// </summary>private readonly List<MessageObject> delayedNotifyMsgs = new List<MessageObject>();/// <summary>/// 主消息队列/// </summary>private readonly List<MessageObject> realCallbacks = new List<MessageObject>();private static bool isInCalling = false;public  void Init(){}public void Update(){lock (this){if (realCallbacks.Count == 0){//主消息隊列處理完時,加入延時消息到主消息列表 foreach (MessageObject eb in delayedNotifyMsgs){realCallbacks.Add(eb);}delayedNotifyMsgs.Clear();return;}//調用主消息處理隊列isInCalling = true;foreach (MessageObject eb in realCallbacks){if (registedCallbacks.ContainsKey(eb.MsgName)){for (int i = 0; i < registedCallbacks[eb.MsgName].Count; i++){MsgCallback ecb = registedCallbacks[eb.MsgName][i];if (ecb == null){continue;}
#if UNITY_EDITORecb(eb);
#elsetry{ecb(eb);}catch (Exception e){Debug.LogError("CallbackError:" + eb.MsgName + " : " + e.ToString());}
#endif}}else{Debug.Log("MSG_ALREADY_DELETED:" + eb.MsgName);}}realCallbacks.Clear();}isInCalling = false;}public void Reset(){Dictionary<string, List<MsgCallback>> systemMsg = new Dictionary<string, List<MsgCallback>>();foreach (KeyValuePair<string, List<MsgCallback>> item in this.registedCallbacks){if (item.Key.StartsWith("_")){systemMsg.Add(item.Key, item.Value);}}this.registedCallbacks = systemMsg;}public void Destroy(){Reset();}/// <summary>/// 订阅消息/// </summary>/// <param name="msgName"></param>/// <param name="msgCallback"></param>public void Subscribe(string msgName, MsgCallback msgCallback){lock (this){if (!registedCallbacks.ContainsKey(msgName)){registedCallbacks.Add(msgName, new List<MsgCallback>());}{//防止重复订阅消息回调List<MsgCallback> list = registedCallbacks[msgName];for (int i = 0; i < list.Count; i++){if (list[i].Equals(msgCallback)){return;}}list.Add(msgCallback);}}}/// <summary>/// 取消订阅/// </summary>/// <param name="msgName"></param>/// <param name="msgCallback"></param>public void UnSubscribe(string msgName, MsgCallback msgCallback){lock (this){if (!registedCallbacks.ContainsKey(msgName)){return;}//Debug.Log(msgName + ":-s-" + registedCallbacks[msgName].Count);registedCallbacks[msgName].Remove(msgCallback);//Debug.Log(msgName + ":-e-" + registedCallbacks[msgName].Count);}}public void PrintMsg(){string content = "";foreach (KeyValuePair<string, List<MsgCallback>> registedCallback in registedCallbacks){int total = registedCallback.Value.Count;if (total > 0){content += registedCallback.Key + ":" + total + "\n";for (int i = 0; i < total; i++){content += "\t" + registedCallback.Value[i].Method.Name + "--" + registedCallback.Value[i].Target + "\n";}}}}/// <summary>/// 派发消息/// </summary>/// <param name="MsgName"></param>/// <param name="MsgParam"></param>public void Notify(string MsgName, params object[] MsgParam){object msgValueParam = null;if (MsgParam != null){if (MsgParam.Length == 1){msgValueParam = MsgParam[0];}else{msgValueParam = MsgParam;}}lock (this){if (!registedCallbacks.ContainsKey(MsgName)){return;}if (isInCalling){delayedNotifyMsgs.Add(new MessageObject(MsgName, msgValueParam));}else{realCallbacks.Add(new MessageObject(MsgName, msgValueParam));}}}}public class MessageObject{public object MsgValue;public string MsgName;public MessageObject(){MsgName = this.GetType().FullName;}public MessageObject(string msgName, object ev){MsgValue = ev;MsgName = msgName;}}
}

你可以看到原著者写的还是很严谨的,使用消息队列来实现的,然后在unity某组件的Update中实现轮询调用。

先看看这个消息机制的启动,特别简单:

public class main : MonoBehaviour {// Use this for initializationvoid Awake (){NotificationManager.Instance.Init();}// Update is called once per framevoid Update (){NotificationManager.Instance.Update();}
}

与上面说的一模一样,初始化,然后update。

至于说机制怎么用,这个在后面会接实战给出。

四、手柄Controller消息触发

手柄的事件很多,我就捡了几个常用的来做个例子来说明问题,若需要,你们自己可以来添加自己的需要。


/// <summary>
/// 可以自定義添加事件,然後實現消息的傳遞。
/// </summary>
// 實現手柄的案件事件功能
public class ViveEvent : MonoBehaviour
{void Start(){var trackedController = GetComponent<SteamVR_TrackedController>();if (trackedController == null){trackedController = gameObject.AddComponent<SteamVR_TrackedController>();}trackedController.TriggerClicked += new ClickedEventHandler(OnTriggerClicked);trackedController.TriggerPressDown += new ClickedEventHandler(OnTriggerPressDn);trackedController.TriggerUnclicked += new ClickedEventHandler(OnTriggerUnclicked);trackedController.PadClicked += new ClickedEventHandler(OnPadClicked);trackedController.PadUnclicked += new ClickedEventHandler(OnPadUnclicked);}void OnTriggerClicked(object sender, ClickedEventArgs e){Debug.Log(e.controllerIndex + "trigger clicked");// 开火NotificationManager.Instance.Notify(NotificationType.Gun_Fire.ToString());}void OnTriggerPressDn(object sender, ClickedEventArgs e){Debug.Log(e.controllerIndex + "trigger press down");// NotificationManager.Instance.Notify(NotificationType.Gathering_Stength.ToString());}void OnTriggerUnclicked(object sender, ClickedEventArgs e){Debug.Log(e.controllerIndex + "trigger  unclicked");NotificationManager.Instance.Notify(NotificationType.Gun_KeyUp.ToString());}void OnPadClicked(object sender, ClickedEventArgs e){// 扔雷NotificationManager.Instance.Notify(NotificationType.Throw_Bomb.ToString());Debug.Log(e.controllerIndex + "pad clicked");}void OnPadUnclicked(object sender, ClickedEventArgs e){Debug.Log(e.controllerIndex + "padd  un clicked");}
}

主要写了按键Trigger 按下,按住和弹起和Pad的按下和弹起事件。

然后是触发事件的接受,这里就体现了解耦事件的好处。这里真的不止于使用在vive按键处理这里。


public class ControlButtonAns : MonoBehaviour
{// Use this for initializationvoid Start(){NotificationManager.Instance.Subscribe(NotificationType.Gun_Fire.ToString(), GunFire);NotificationManager.Instance.Subscribe(NotificationType.Gathering_Stength.ToString(), GatheringStength);NotificationManager.Instance.Subscribe(NotificationType.Throw_Bomb.ToString(), ThrowBomb);NotificationManager.Instance.Subscribe(NotificationType.Gun_KeyUp.ToString(), GunKeyUp);}void GunFire(MessageObject obj){Debug.Log("response gun fire , trigger button click");}void GatheringStength(MessageObject obj){Debug.Log("response gathering stength, trigger button hold");}void GunKeyUp(MessageObject obj){Debug.Log("response key up, trigger button unclicked");}void ThrowBomb(MessageObject obj){Debug.Log("response throw bomb , pad button click");}
}

这个就根据个人的需要来添加自己的代码。这里仅仅是举例说明。

代码写完了,添加吧!!

手柄contorller接受事件:


图7.1

消息触发解耦代码:


图7.2

相应消息脚本:


图7.3

这样基本就搞定了。

五、结果

一图胜千言:


图8

就这样。

六、下载地址

工程下载地址:github

https://github.com/cartzhang/ImgSayVRabc/tree/master/ViveEventDemo

steam 插件工程导出地址:

https://github.com/cartzhang/ImgSayVRabc/blob/master/ViveEventDemo/SteamViveControllerEventDemoCartzhang.unitypackage

2017-01-09更新,给事件添加触发手柄ID。
https://github.com/cartzhang/ImgSayVRabc/blob/master/ViveEventDemo/HTVVive_event_add_controller_inedex%20_Cartzhang.unitypackage

七、参考

[1] http://www.cnblogs.com/czaoth/p/5610883.html

[2] http://www.htc.com/managed-assets/shared/desktop/vive/Vive_PRE_User_Guide.pdf

[3] http://blog.csdn.net/qiaochaoqc/article/details/52086790

《图说VR》——HTC Vive控制器按键事件解耦使用相关推荐

  1. unity 如何检测vr htc vive 头盔是否佩戴

    这取决于Unity版本,并且随着时间的变化而变化.通常是VRDevice.isPresent已在某些版本上重命名的属性.Unity 5.2及更低版本中存在问题,因此VRSettings.loadedD ...

  2. Unity3D 开发 HTC Vive安装及如何连接电脑详细教程(全程图解)

    HTC Vive安装及如何连接电脑详细教程: 在市场上的诸多VR产品当中,htc Vive无疑是体验最佳的设备之一,不过在享受高端硬件带来美妙沉浸感之前,必须要经过一段略微复杂的"手续&qu ...

  3. HTC VIVE 安装,SteamVR,VRTK插件的使用,HTC VIVE Tracker的使用和外接按键测试

    1.Htc Vive安装教程 在把你的头显与控制器连到电脑上之前,我们首先要做的是先安好基站.基站的背面和低端各有一个固定孔,这样你可以把基站钉在墙上或者买支架将其撑起.大三角架安装示意图 Light ...

  4. HTC VIVE VR眼镜的介绍以及初始化设置

    硬件设备介绍 使用的硬件设备:HTC VIVE 或 HTC VIVE Pro 1.认识一下HTC VIVE VR头盔上的主要部件: A 是基站(定位器) x 2(发射激光定位头显与手柄控制器) B 是 ...

  5. Unity2020使用Steam VR开发HTC VIVE Cosmos

    Unity2020使用Steam VR开发HTC VIVE Cosmos 版本 配置手柄输入控制 版本 Unity:2020.2.1 HTC插件:最新版本2.0 配置手柄输入控制 2.0steamvr ...

  6. 用 Unity 和 HTC Vive 实现高级 VR 机制(1)

    原文:Advanced VR Mechanics With Unity and the HTC Vive Part 1 作者:Eric Van de Kerckhove 译者:kmyhy VR 从来没 ...

  7. #HTC VIVE #进行VR开发的环境

    因为一些原因,要求上周的博客缺了一篇,于是在这周补上.好了,让我们开始吧. HTC VIVE 开发中最重要的基石是steamVR,只有充分理解steamVR,才能在开发中得心应手,创造最佳的虚拟现实体 ...

  8. VIVE开发基础(A、快速入门篇)(Yanlz+HTC+VIVE+VR+AR+MR+XR+SteamVR+CameraRig+LightHouse+HeadSet+Teleport+立钻哥哥+)

    <HTC_VIVE开发基础> 版本 作者 参与者 完成日期 备注 HTC_VIVE_V01_1.0 严立钻 2018.08.23 <HTC_VIVE开发基础>发布说明: +++ ...

  9. Unity HTC VIVE VR一体机基础操作

    Unity HTC VIVE VR一体机基础操作 VIVE Focus 触摸板 VIVE Focus 按键操作 VIVE Focus 碰撞触发 VIVE Focus 动态输出 VIVE Focus 指 ...

最新文章

  1. python入门教程 pdf-Python快速入门PDF高清完整版本下载
  2. 第二模块_找钱:融资与管理_1
  3. 【mysql必知必会】第十二章 汇总数据
  4. 信息奥赛一本通(1180:分数线划定)——插入排序
  5. 百度EasyDL深度学习实战营,免费教你转型AI工程师!
  6. 动手实验:继承条件下的构造方法调用
  7. 《TensorFlow 2.0深度学习算法实战教材》学习笔记(四、TensorFlow 进阶)
  8. java计算器模拟程序_模拟计算器java程序
  9. RS法计算Hurst指数
  10. SpringBoot+smm+Vue前后端分离项目用户模块基本功能设计
  11. w10桌面计算机图标箭头去除,win10桌面图标有个箭头如何去掉_去掉win10桌面图标箭头的方法-系统城...
  12. 【网络驱动】GMAC 系统框架
  13. 如何快准狠地找到相关领域的经典文献?
  14. 7-12 清点代码库 (25 分)
  15. 不是运算容错,而是高温降频率,软件劣化老硬件
  16. MySql数据查重、去重的实现
  17. 我对社交电商的了解与看法
  18. Lua系列--pairs和ipairs
  19. Python转盘游戏
  20. java计算程序运行时间及时间单位换算

热门文章

  1. java共享充电宝管理系统ssm框架
  2. winserver搭建smtp_如何在服务器搭建本地smtp邮件服务
  3. 洛可可李建华:在做好产品的道路上,人人都是设计师!
  4. 谈谈CPU/主板/内存该怎么搭配
  5. 实验2.2——VAO,VBO的总结
  6. Python爬虫入门基本代码含注释说明
  7. 在生鲜零售业,DolphinScheduler 还能这么玩!
  8. 二进制转换之命理学习
  9. 华为荣耀6计算机,华为荣耀6怎么开启和打开usb调试模式
  10. java中旋转图片的一种高效率方法