unity实现3d摇杆 结合leapmotion控制实现VR场景移动
2017-01-27 13:42
661 查看
unity实现3d摇杆 结合leapmotion控制实现VR场景移动
Created by miccall (转载请注明出处 miccall.tech )3D UI设想 解决VR场景移动
开发vr很恼火的就是场景的移动 真实地方本来就小,如果vr里面的场景也小,那还玩个啥,所以虚拟现实的场景是很大的 如何实现小空间对大空间的移动,这也是vr开发要解决的问题之一 。我们老大设想了摇杆操作 我就顺着思路做了一套 先看看基本效果
-当手移动中间的球时候 ,就像触碰摇杆一样 ,可以向四周摇动 。
外面的环是一个指示器 当球触发到环的时候,给一个颜色的变化,让用户知道自己将朝哪一个方向运动 。
下面是一个围棋场地 用来感受自己在环境中的移动。
摄像机 包括controller都在一个游戏物体上面 也很好移植 ,下面就一步步来展示这个的制作过程 。
3d摇杆的基本框架
首先建立一个MianPivot的空物体 它代表着游戏人物 到时候可以自己设定 。
其下呢 ,一个是VR视角 可以选用官方的LMHeadMountedRig 这个预制体 。
另一个就是我门要做的这个摇杆了 。
摇杆分为三部分 BoundaryRing 就是外面的一个指示环 。root是一个中心点 用来归位 sphere是一个移动的球,用手来触碰它 让它在空间中移动,实现摇杆效果 。
实现思路
看过摇杆的自动归位 ,一开始是拿弹簧力来实现,但是弹簧回弹的惯性极其的难掌控 ,来回摆动简直让人抓狂 。于是, 果断放弃了unity的弹簧力 改自己写插值移动 ,让它在手不触碰他的时候,就让它移动到root这个点 。大概一分析就是这么简单的东西了,但是写起来还是比较烦的,bug极其的多,如何判断手的hold 如何判断移动 回弹的触发条件 等等一系列 做出好的效果还是很不容易的。
还有就是状态的类,球是否是移动的状态 手是否是hold的状态 这个也得写个类来管理
那么物体上呢 ,就很简单了 加一个触发器 当触发的时候 改变他们的状态 。
大家自己建立两个球(一个root点 一个移动的球)并把他们放到一个父物体下面,就可以开始写脚本了。
开始写脚本
先在父类上面建立一个Controller脚本 用来管理游戏移动对象, root和sphere 。好 那就先这样写
public class springController : MonoBehaviour { [Tooltip("Navigation Controls the walking game object")] public GameObject player; [Tooltip("Used to move the navigation ball")] public GameObject sphere; [Tooltip("The root node of the navigation (reset point)")] public GameObject root; Vector3 sphereposition; Vector3 rootposition; float speed = 5f; // 导航球复位的速度 // Use this for initialization void Start() { //获取 初始位置 sphereposition = sphere.transform.localPosition; rootposition = root.transform.localPosition; } // Update is called once per frame void Update() { //更新 导航球 的位置 sphereposition = sphere.transform.localPosition; Movecheck(); //判断并控制player的移动 setstop(); //导航球归位 } void setstop() { if (HandState.Handstate == HandState.HandStateRelease) { float step = speed * Time.deltaTime; sphere.GetComponent<Rigidbody>().velocity = Vector3.zero; sphere.transform.localPosition = new Vector3(Mathf.Lerp(sphereposition.x, rootposition.x, step), Mathf.Lerp(sphereposition.y, rootposition.y, step), Mathf.Lerp(sphereposition.z, rootposition.z, step));//插值算法也可以 if (SphereState.Spherestate == SphereState.Spherestateclosed) sphere.transform.localPosition = new Vector3(0, 0, 0); } } void debugshpereposition() { print("sphereposition" + sphereposition); } void Movecheck() { if(HandState.Handstate == HandState.HandStateHold) { startfollow(); } else if(SphereState.Spherestate == SphereState.Spherestateclosed) { Stopfollow(); } } void startfollow() { transform.parent.GetComponent<test>().enabled = true; } void Stopfollow() { transform.parent.GetComponent<test>().enabled = false; } void OnTriggerExit(Collider other) { if (issphere(other)) { HandState.Handstate = HandState.HandStateRelease; setstop(); } } bool issphere(Collider other) { return other.transform.name == "Sphere"; } }
然后就是root和sphere上面 各有一个triiger判断的类
public class rootTrigger : SphereState 4000 { Collider currentcollider; enum currentstate { colse,move } currentstate state; void OnTriggerEnter(Collider collider) { currentcollider = collider; state = currentstate.colse; //spheredebug(collider, "in"); } void OnTriggerExit(Collider collider) { currentcollider = collider; state = currentstate.move; //spheredebug(collider, "out"); } public override bool isclosed() { if (Isphere(currentcollider)) { if (state == currentstate.colse) return true; else return false; } return false; } private bool Isphere(Collider collider) { return collider.transform.name == "Sphere" ; } void spheredebug(Collider collider,string state) { if (Isphere(collider)) { print("Sphere"+" "+ state); } } }
第二个
public class HnadTrigger : HandState { int handcount = 0 ; //public Text handcounttext ; void OnTriggerEnter(Collider other) { if(IShand(other)) { //handdebug(other, "in"); handcount++; } } void OnTriggerExit(Collider other) { if(IShand(other)) { //handdebug(other, "out"); handcount--; } } bool IShand(Collider other) { string Collidername = other.transform.parent.name; if (Collidername == "thumb") return true; else if (Collidername == "index") return true; else if (Collidername == "middle") return true; else if (Collidername == "thumb") return true; else if (Collidername == "RigidRoundHand_L" || Collidername == "RigidRoundHand_R") return true; else return false; } void handdebug(Collider other, string state) { print("hand" + state+" ++++++++++++" + Time.time); } public override bool ishold() { //print(" ishold() child "); //handcounttext.text = " count"+handcount; if (handcount != 0) { //print("is hold"); return true; } return false; } }
这个hold的状态也是搞了我很久 没办法处理判断hold和release两个状态
最后想到的用碰撞器的数量来判断吧 ,当进入trigger就加加 出去就减减 最后数量为0 那么就是松开状态了
仅供参考
状态脚本
public class HandState : MonoBehaviour { public static int HandStateHold = 0 ; public static int HandStateRelease = 1; public static int Handstate = HandStateRelease ; public virtual bool ishold() { return true; } void setvalue() { if (ishold()) { Handstate = HandStateHold; } else StartCoroutine(WaitAndPrint(0.5F)); } IEnumerator WaitAndPrint(float waitTime) { yield return new WaitForSeconds(waitTime); //等待之后执行的动作 Handstate = HandStateRelease; } void Update() { setvalue(); } }
public class SphereState : MonoBehaviour { public static int Spherestateclosed = 0; public static int Spherestatemove = 1; public static int Spherestate = Spherestateclosed; public virtual bool isclosed() { return false; } void setvalue() { if (isclosed()) { Spherestate = Spherestateclosed; } else { Spherestate = Spherestatemove; } } void Update() { setvalue(); } }
这个就比较简单了 也就不多解释了 有想要源码的,可以留言联系我 。
好了 ,今天就将怎么多啦 ,祝自己新年快乐。
相关文章推荐
- unity中结合oculus制作VR场景控制相机的移动的三种方式
- Unity编程笔录--实现AR与3D场景结合效果
- Unity2D - 4. 实现android虚拟摇杆控制人物移动
- 【Unity 3D学习】键盘控制人物在场景中移动
- unity 实现键盘控制物体移动和转向
- Unity3D游戏制作之3D横版场景的角色移动控制
- 自制OculusVR控制(一)——利用Unity的自带方法实现VR的控制输入
- Unity 3d 如何实现点击屏幕,npc自动移动到点击位置
- 通过滑动手势控制摇杆移动并且通过移动的速度控制能量条的增长 Unity
- Unity 立体3D VR的实现
- Unity简单利用屏幕坐标转换实现鼠标控制物体移动
- Unity 3D:控制相机旋转、移动、缩放等功能
- Unity 3D 控制物体上下左右均匀移动脚本
- Unity摇杆控制物体移动c#脚本
- unity之手机端摇杆控制人物移动
- Unity实现在场景中自由移动游览的相机
- Unity中实现在切换场景时控制音乐的同步播放
- 我的Unity(10)一点一滴 利用UI制作摇杆控制物体移动
- liggdx 实现摇杆控制角色移动
- 初学VR (五):控制坦克的移动,实现转向和开火