《图说VR》——HTC Vive控制器按键事件解耦使用
本文章由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控制器按键事件解耦使用相关推荐
- unity 如何检测vr htc vive 头盔是否佩戴
这取决于Unity版本,并且随着时间的变化而变化.通常是VRDevice.isPresent已在某些版本上重命名的属性.Unity 5.2及更低版本中存在问题,因此VRSettings.loadedD ...
- Unity3D 开发 HTC Vive安装及如何连接电脑详细教程(全程图解)
HTC Vive安装及如何连接电脑详细教程: 在市场上的诸多VR产品当中,htc Vive无疑是体验最佳的设备之一,不过在享受高端硬件带来美妙沉浸感之前,必须要经过一段略微复杂的"手续&qu ...
- HTC VIVE 安装,SteamVR,VRTK插件的使用,HTC VIVE Tracker的使用和外接按键测试
1.Htc Vive安装教程 在把你的头显与控制器连到电脑上之前,我们首先要做的是先安好基站.基站的背面和低端各有一个固定孔,这样你可以把基站钉在墙上或者买支架将其撑起.大三角架安装示意图 Light ...
- HTC VIVE VR眼镜的介绍以及初始化设置
硬件设备介绍 使用的硬件设备:HTC VIVE 或 HTC VIVE Pro 1.认识一下HTC VIVE VR头盔上的主要部件: A 是基站(定位器) x 2(发射激光定位头显与手柄控制器) B 是 ...
- Unity2020使用Steam VR开发HTC VIVE Cosmos
Unity2020使用Steam VR开发HTC VIVE Cosmos 版本 配置手柄输入控制 版本 Unity:2020.2.1 HTC插件:最新版本2.0 配置手柄输入控制 2.0steamvr ...
- 用 Unity 和 HTC Vive 实现高级 VR 机制(1)
原文:Advanced VR Mechanics With Unity and the HTC Vive Part 1 作者:Eric Van de Kerckhove 译者:kmyhy VR 从来没 ...
- #HTC VIVE #进行VR开发的环境
因为一些原因,要求上周的博客缺了一篇,于是在这周补上.好了,让我们开始吧. HTC VIVE 开发中最重要的基石是steamVR,只有充分理解steamVR,才能在开发中得心应手,创造最佳的虚拟现实体 ...
- 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开发基础>发布说明: +++ ...
- Unity HTC VIVE VR一体机基础操作
Unity HTC VIVE VR一体机基础操作 VIVE Focus 触摸板 VIVE Focus 按键操作 VIVE Focus 碰撞触发 VIVE Focus 动态输出 VIVE Focus 指 ...
最新文章
- python入门教程 pdf-Python快速入门PDF高清完整版本下载
- 第二模块_找钱:融资与管理_1
- 【mysql必知必会】第十二章 汇总数据
- 信息奥赛一本通(1180:分数线划定)——插入排序
- 百度EasyDL深度学习实战营,免费教你转型AI工程师!
- 动手实验:继承条件下的构造方法调用
- 《TensorFlow 2.0深度学习算法实战教材》学习笔记(四、TensorFlow 进阶)
- java计算器模拟程序_模拟计算器java程序
- RS法计算Hurst指数
- SpringBoot+smm+Vue前后端分离项目用户模块基本功能设计
- w10桌面计算机图标箭头去除,win10桌面图标有个箭头如何去掉_去掉win10桌面图标箭头的方法-系统城...
- 【网络驱动】GMAC 系统框架
- 如何快准狠地找到相关领域的经典文献?
- 7-12 清点代码库 (25 分)
- 不是运算容错,而是高温降频率,软件劣化老硬件
- MySql数据查重、去重的实现
- 我对社交电商的了解与看法
- Lua系列--pairs和ipairs
- Python转盘游戏
- java计算程序运行时间及时间单位换算