《SteamVR2.2.0官方教程》 |
版本 |
作者 |
参与者 |
完成日期 |
备注 |
SteamVR2.2.0_Tutorials_V01_1.0 |
严立钻 |
|
2019.05.06 |
|
|
|
|
|
|
++++“SteamVR2.2.0官方教程”:是对“SteamVR2.2.0”的官方教程(Tutorials)梳理总结;(2019年度的重点技术突破点确立为:“SteamVR”)(前面已经有了一个“V2.0”和“V2.2.0”开发指南了:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187,https://blog.csdn.net/VRunSoftYanlz/article/details/88784527;快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579;交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778;这个“官方教程”是基于前面几篇操作指南和快速入门的一个拓展,所以可以先粗略查阅一下这几篇博文;这里重点说明一下:实战是关键,所以官方教程是重中之重,后期还会基于熟悉官方示例的基础上拓展应用到现实应用中,敬请期待!
++++“SteamVR2.2.0官方教程”:定位在熟悉SteamVR框架;
++++SteamVR2.2.0教程(一):https://blog.csdn.net/VRunSoftYanlz/article/details/89324067
++++SteamVR2.2.0教程(二):https://blog.csdn.net/VRunSoftYanlz/article/details/89894097
#第一篇:v2.2.0快速入门 |
#第一篇:v2.2.0快速入门
++++立钻哥哥:在“Valve”发布了“The Lab”之后,SteamVR也采用了该项目的经验,创建了一个“交互系统(Interaction System)”,该系统提供了一些常用的交互应用,包括:“与Unity UI元素的交互(Interaction with Unity UI elements)”,“拾起,放下,扔出去(Pickup, Drop, and Throw)”,“投掷速度的多种变化(Multiple variations on throwing velocites)”,“弓箭(Bow and Arrow)”,“轮交互(Wheel interactions)”,“邻近按钮(Proximity button)”,“各种骨骼输入示例(Variety of Skeleton Input example)”,“传送(Teleporting)”,“使用抓握对象(Using held objects)”,“使用手持物体的手的骨架输入(Using Skeleton Input to from a hand around a held object)”等,这些都是非常好的应用案例,后期立钻哥哥将一一剖析拓展,敬请期待(关注“SteamVR”分类:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642)!
++++SteamVR2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187
++++SteamVR2.2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/88784527
++++SteamVR2.2.0快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579
++++SteamVR2.2.0交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778
++++A.1、快速入门(Getting started)
++++A.2、示例场景(Sample scene)
##A.1、快速入门(Getting started) |
##A.1、快速入门(Getting started)
++++立钻哥哥:交互系统(Interaction System)是游戏的核心,一般是交互系统先行设计开发,基于交互系统再进行游戏交互的设计和情景设计;那我们就从“交互系统”出发,快速入门吧!
++++关于SteamVR的快速入门,可查阅这个链接:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579
++++获取更多关于SteamVR技术知识,可查阅这个分类:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642
++++A.1.1、交互系统(Interaction System)的认知
++++A.1.2、入门指南(Getting started)
###A.1.1、交互系统(Interaction System)的认知 |
++++立钻哥哥:在Valve发布“The Lab”之后,SteamVR也创建了一个“交互系统”,我们可以在自己的项目中使用这些例子,该系统也更新使用了“SteamVR Input”和新的“SteamVR Skeleton Input”系统;
++++[Interaction with Unity UI elements]:与Unity UI元素的交互;
++++[Pickup, Drop, and Throw]:拾起,放下,扔出去;
++++[Multiple variations on throwing velocities]:投掷速度的多种变化;
++++[Bow and Arrow]:弓箭;
++++[Wheel interactions]:轮交互;
++++[Proximity button]:邻近按钮;
++++[Variety of Skeleton Input example]:各种骨骼输入示例;
++++[Teleporting]:传送;
++++[Using held objects]:使用抓握对象;
++++[Using Skeleton Input to from a hand around a held object]:使用手持物体的手的骨骼输入;
++++立钻哥哥:“交互系统(Interacion System)”是一系列脚本、预制体和其他资源,是“The Lab”中所有迷你游戏和其他场景的基础,这个系统最初被设计成轻量级和灵活的,这样他就可以支持我们当时正在进行的所有实验;
++++Steam平台上的“The Lab”链接:https://store.steampowered.com/app/450390/The_Lab/
###A.1.2、入门指南(Getting Started) |
++++立钻哥哥:要获取示例,可查看“Assets/SteamVR/InteractionSystem/Samples/Scenes”中的“Interactions_Example”场景;
++立钻哥哥推荐的热门分类:
++++SteamVR:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642
++++XR技术企业内训:https://blog.csdn.net/vrunsoftyanlz/article/category/8037810
++++5G+云计算+雾计算:https://blog.csdn.net/vrunsoftyanlz/article/category/8741272
++++框架编程:https://blog.csdn.net/vrunsoftyanlz/article/category/7570175
++++SteamVR2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187
++++SteamVR2.2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/88784527
++++SteamVR2.2.0快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579
++++SteamVR2.2.0交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778
++++SteamVR2.2.0传送机制:https://blog.csdn.net/VRunSoftYanlz/article/details/89390866
++++SteamVR2.2.0教程(一):https://blog.csdn.net/VRunSoftYanlz/article/details/89324067
++++SteamVR2.2.0教程(二):https://blog.csdn.net/VRunSoftYanlz/article/details/89894097
++++立钻哥哥:新建场景;当然,那需要先导入“SteamVR插件”;
++++SteamVR的Unity资源商店链接:https://assetstore.unity.com/packages/tools/integration/steamvr-plugin-32647
++++SteamVR在Github上的Release:https://github.com/ValveSoftware/steamvr_unity_plugin/releases
++++新建工程后,导入SteamVR插件,那就可以开始新建一个测试场景了:
++++立钻哥哥:删除“主摄像机(Main Camera)”;
++++如果需要做一款VR游戏,需要把摄像机调成VR视角;
++++[方法1]:使用预制的VR摄像机;
++++[方法2]:将普通的摄像机修改成VR摄像机;
++++Tips:比较详细的描述可参考“SteamVR简介”:https://blog.csdn.net/VRunSoftYanlz/article/details/86484254
++++立钻哥哥:将“Assets/SteamVR/InteractionSystem/Core/Prefabs/”下的“Player.prefab”预制体拖到场景中;这个预制体设置了主要的玩家和手,它还挂钩到所有相关的“SteamVR Input”需要的动作;
++++立钻哥哥:现在我们就可以戴上头盔观察一下场景吧,里面有什么呢?估计是一个空白的场景,很可能有控制器呀!
++++立钻哥哥:如果我们的控制器是支持“Skeleton Input”的,操作时会看到双手触摸并按下控制器上的按钮;
++++立钻哥哥:将“Interactable”组件添加到场景中的任何对象中,该对象上的所有其他组件将开始从玩家手中接收相关信息了;
//Purpose: Demonstrates how to create a simple interactable object.(立钻哥哥:目的:演示如何创建一个简单的可交互对象.) using UnityEngine; using System.Collections; namespace Valve.VR.InteractionSystem.Sample{ [RequireComponent(typeof(Interactable))] public class InteractableExample : MonoBehaviour{ private TextMesh generalText; private TextMesh hoveringText; private Vector3 oldPosition; private Quaternion oldRotation;
private float attachTime;
private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags & (~Hand.AttachmentFlags.SnapOnAttach) & (~Hand.AttachmentFlags.DetachOthers) & (~Hand.AttachmentFlags.VelocityMovement);
private Interactable interactable; ... ...} //立钻哥哥:public class InteractableExample:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem.Sample{} |
//立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Purpose: The hands used by the player in the vr interaction system.(立钻哥哥:用途:玩家在vr交互系统中使用的手) using UnityEngine; using System.Threading;
namespace Valve.VR.InteractionSystem{ //Links with an appropriate SteamVR controller and facilitates interactions with objects in the virtual world.(立钻哥哥:链接到适当的SteamVR控制器,并方便与虚拟世界中的对象进行交互.) public class Hand : MonoBehaviour{ ++++L170: _hoveringInteractable.SendMessage(“OnHandHoverEnd”, this, SendMessageOptions.DontRequireReceiver); ++++L185: _hoveringInteractable.SendMessage(“OnHandHoverBegin”, this, SendMessageOptions.DontRequireReceiver); ++++L384: currentAttachedObject.SendMessage(“OnHandFocusLost”, this, SendMessageOptions.DontRequireReceiver); ++++L560: objectToAttach.SendMessage(“OnAttachedToHand”, this, SendMessageOptions.DontRequireReceiver); ++++L656: attachedObjects[index].attachedObject.SendMessage(“OnDetachedFromHand”, this, SendMessageOptions.DontRequireReceiver); ++++L672: newTopObject.SendMessage(“OnHandFocusAcquired”, this, SendMessageOptions.DontRequireReceiver); ++++L1083: attachedObject.SendMessage(“HandAttachedUpdate”, this, SendMessageOptions.DontRequireReceiver); ++++L1088: hoveringInteractable.SendMessage(“HandHoverUpdate”, this, SendMessageOptions.DontRequireReceiver); ++++L1202: attachedInfo.interactable.gameObject.SendMessage(“OnThrowableAttachEaseInCompleted”, this, SendMessageOptions.DontRequireReceiver); } //立钻哥哥:public class Hand:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{}
|
//立钻哥哥:SendMessageOptions using System; namespace UnityEngine{ public enum SendMessageOptions{ RequireReceiver, DontRequireReceiver } //立钻哥哥:public enum SendMessageOptions{} } //立钻哥哥:namespace UnityEngine{}
|
//立钻哥哥:GameObject.SendMessage()发送消息 void SendMessage(string methodName, object value=null, SendMessageOptions options=SendMessageOptions.RequireReceiver); ++++[methodName]: 调用的方法名; ++++[value]:可选参数,被调用的方法传递的值; ++++[options]:如果目标对象方法不存在,是否引发错误; ++++[描述]:在此游戏对象所有MonoBehaviour上调用名称为methodName的方法;接收消息的方法可以通过不要参数的方法来选择忽略参数;当选项被设置为[SendMessageOptions.RequireReceiver]时,如果消息没有被任何一个组件处理,则会打印一个错误; ++++[注意]:消息不会发送到非激活的对象上(如,那些在编辑器或者通过SetActive已经关闭的对象);
using UnityEngine; using System.Collections; public class YanlzExampleClass : MonoBehaviour{ void YanlzApplyDamage(float damage){ Debug.Log(“立钻哥哥:受到的攻击” + damage); }
void MyExampleFunc(){ gameObject.SendMessage(“YanlzApplyDamage”, 5.0f); } } //立钻哥哥:public class YanlzExampleClass:MonoBehaviour{} |
//立钻哥哥:参考“InteractableExample.cs”编写一个脚本“YanlzVRDemoInteractable190416.cs” //目的:能把那个风骚的Cube拿起来! using UnityEngine; using System.Collections;
namespace YanlzXR.VR.InteractionSystem.Sample{ [RequireComponent(typeof(Interactable))] public class YanlzVRDemoInteractable190416 : MonoBehaviour{ private Vector3 oldPosition; private Quaternion oldRotation;
private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags & (~Hand.AttachmentFlags.SnapOnAttach) & (~Hand.AttachmentFlags.DetachOthers) & (~Hand.AttachmentFlags.VelocityMovement);
private Interactable interactable;
void Awake(){ Debug.Log(“立钻哥哥:----YanlzVRDemoInteractable190416----[Awake()]----IN----”); interactable = this.GetComponent<Interactable>(); }
//Called every Update() while a Hand is hovering over this object.(立钻哥哥:当一只手悬停在此对象上时每个Update()都调用.) private void HandHoverUpdate(Hand hand){ GrabTypes startingGrabType = hand.GetGrabStarting(); bool isGrabEnding = hand.IsGrabEnding(this.gameObject);
if(interactable.attachedToHand == null && startingGrabType != GrabTypes.None){ //Save our position/rotation so that we can restore it when we detach.(立钻哥哥:保存我们的位置/旋转,以便我们可以在分离时恢复它.) oldPosition = transform.position; oldRotation = transform.rotation;
//Call this to continue receiving HandHoverUpdate message, and prevent the hand from hovering over anything else.(立钻哥哥:调用此函数可以继续接收HandHoverUpdate消息,并防止手悬停在任何其他位置.) hand.HoverLock(interactable);
//Attach this object to the hand.(立钻哥哥:把这个物体系在手上.) hand.AttachObject(gameObject, startingGrabType, attachmentFlags);
}else if(isGrabEnding){ //Detach this object from the hand.(立钻哥哥:将此对象从手中分离出来.) hand.DetachObject(gameObject);
//Call this to undo HoverLock.(立钻哥哥:调用此命令可以撤销HoverLock) hand.HoverUnlock(interactable);
//Restore position/rotation.(立钻哥哥:恢复旋转/位置) transform.position = oldPosition; transform.rotation = oldRotation; }
} //立钻哥哥:private void HandHoverUpdate(Hand hand){} } //立钻哥哥:public class YanlzVRDemoInteractable190416:MonoBehaviour{} } //立钻哥哥:namespace YanlzXR.VR.InteractionSystem.Sample{}
|
|
++知识点01:Hand.AttachmentFlags ++++立钻哥哥:The flags used to determine how an object is attached to the hand.(用于确定对象如何附加到手的标志。) ++++public const AttachmentFlags defaultAttachmentFlags = AttachmentFlags.ParentToHand | AttachmentFlags.DetachOthers | AttachmentFlags.DetachFromOtherHand | AttachmentFlags.TurnOnKinematic | AttachmentFlags.SnapOnAttach; ++++[Flags] public enum AttachmentFlags{ SnapOnAttach = 1 << 0, DetachOthers = 1 << 1, DetachFromOtherHand = 1 << 2; ParentToHand = 1 << 3, VelocityMovement = 1 << 4, TurnOnKinematic = 1 << 5, TurnOffGravity = 1 << 6, AllowSidegrade = 1 << 7, }; ++++[SnapOnAttach]:The object should snap to the position of the specified attachment point on the hand.(立钻哥哥:[SnapOnAttach]: 将物体附着在手的指定位置。) ++++[DetachOthers]:Other objects attached to this hand will be detached.(立钻哥哥:[DetachOthers]:其他对象附加到这只手会分离.) ++++[DetachFromOtherHand]:This object will be detached from the other hand.(立钻哥哥:[DetachFromOtherHand]:这个对象将从另一只手脱离。) ++++[ParentToHand]:The object will be parented to the hand.(立钻哥哥:[ParentToHand]:对象将作为手的子物体。) ++++[VelocityMovement]:The object will attempt to move to match the position and rotation of the hand.(立钻哥哥:[VelocityMovement]:对象将尝试移动到位置和旋转都匹配的手上。) ++++[TurnOnKinematic]:The object will not respond to external physics.(立钻哥哥:[TurnOnKinematic]: 对象不响应外部物理属性。) ++++[TurnOffGravity]:The object will not respond to external physics.(立钻哥哥:[TurnOffGravity]:外部物理对象不会回应。) ++++[AllowDidegrade]:The object is able to switch from a pinch grab to a grip grab. Decreases likelyhood of a good throw but also decreases likelyhood of accidental drop.(立钻哥哥:AllowDidegrade]:对象可以切换从一个捏抓到握抓。减少一个好的投掷的可能性,但也减少意外掉落的可能性)
|
++知识点02:HandHoverUpdate ++++立钻哥哥:private void HandHoverUpdate(Hand hand){} ++++我们来加个断点来调试跟踪一下,这个接口是从哪里调用过来的:
++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //立钻哥哥:L1076(void Valve.VR.InteractionSystem.Hand:Update()) protected virtual void Update(){ UpdateNoSteamVRFallback();
GameObject attachedObject = currentAttachedObject; if(attachedObject != null){ attachedObject.SendMessage(“HandAttachedUpdate”, this, SendMessageOptions.DontRequireReceiver); }
if(hoveringInteractable){ //立钻哥哥:void YanlzXR.VR.InteractionSystem.Sample.YanlzVRDemoInteractable190416:HandHoverUpdate(Hand) ==>private void HandHoverUpdate(Hand hand){} hoveringInteractable.SendMessage(“HandHoverUpdate”, this, SendMessageOptions.DontRequireReceiver); } } //立钻哥哥:protected virtual void Update(){}
|
++知识点03:hand.GetGrabStarting() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs public GrabType GetGrabStarting(GrabTypes explicitType=GrabType.None){ }
|
++知识点04:hand.IsGrabEnding() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs public bool IsGrabEnding(GameObject attachedObject){ }
|
++知识点05:hand.HoverLock() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Continue to hover over this object indefinitely, whether or not the Hand moves out of its interaction trigger volume.(立钻哥哥:无论手是否移出交互触发范围,都将无限期地悬停在该对象上) public void HoverLock(Interactable interactable){ }
|
++知识点06:hand.AttachObject() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Attach a GameObject to this GameObject.(立钻哥哥:将GameObject(游戏物体)附加到这个GameObject(游戏物体)上。) //[objectToAttach]: The GameObject to attach.(立钻哥哥:[objectToAttach]:要附加的GameObject) //[flags]: The flags to use for attaching the object.(立钻哥哥:[flags]:用于附加对象的标志.) //[attachmentPoint]: Name of the GameObject in the hierarchy of this Hand which should act as the attachment point for this GameObject.(立钻哥哥:[attachmentPoint]:这只手的层次结构中GameObject的名称,它应该作为这个GameObject的连接点.) public void AttachObject(GameObject objectToAttach, GrabTypes grabbedWithType, AttachmentFlags flags=defaultAttachmentFlags, Transform attachmentOffset=null){ } //立钻哥哥:public void AttachObject{}
|
++知识点07:hand.DetachObject() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Detache this GameObject from the attached object stack of this Hand.(立钻哥哥:从这只手的附加对象堆栈中分离这个GameObject.) //[objectToDetach]: The GameObject to detach from this Hand.(立钻哥哥:[objectToDetach]:要从这只手分离的GameObject.) public void DetachObject(GameObject objectToDetach, bool restoreOriginalParent=true){ }
|
++知识点08:hand.HoverUnlock() ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Stop hovering over this object indefinitely.(立钻哥哥:停止无限期地悬停在这个物体上.) //[interactable]: The hover-locked Interactable to stop hovering over indefinitely.(立钻哥哥:[可交互]:锁定物体的可交互,以停止无限期地悬停) public void HoverUnlock(Interactable interactable){ }
|
++立钻哥哥:“Hand”类为“交互系统(Interaction System)”做了大部分繁重的工作;“Hand”检查它所悬停的对象(Interactables),并根据当前悬停状态向它们发送消息;一只手一次只能悬停在一个物体上;物体可以附着在手上,也可以从手上分离出来,只有一个对象可以是手的焦点对象,但同时可以将多个对象附加到手;一旦一个对象与手分离,那么与手相连的前一个对象(如果它仍然与手相连)就成为手的焦点对象;当没有任何东西附着在手上时,它总是会显示控制器;所附加的对象可以设置AttachmentFlags,该标记确定手和对象在被附加后的行为;根据不同的情况,可以将手锁定在悬停在其他物体或任何物体上;
|
++“Hand”手发送给正在与之交互的对象的消息: ++++立钻哥哥、OnHandHoverBegin、HandHoverUpdate、OnHandHoverEnd、OnAttachedToHand、HandAttachedUpdate、OnDetachedFromHand、OnHandFocusLost、OnHandFocusAcquired; ++++[OnHandHoverBegin]:当手第一次开始悬停在对象上时发送; ++++[HandHoverUpdate]:发送手悬停在对象上的每一帧; ++++[OnHandHoverEnd]:当手离开悬停物体上时发送; ++++[OnAttachedToHand]:当对象附加到hand上时发送; ++++[HandAttachedUpdate]:当对象附在手上时,发送每一帧; ++++[OnDetachedFromHand]:当对象脱离手时发送; ++++[OnHandFocusLost]:当一个附加对象因为其他对象被附加到手上而失去焦点时发送; ++++[OnHandFocusAcquired]:当一个附加对象获得焦点时发送,因为之前的焦点对象已经与手分离; +++++++++++++++++++++ //立钻哥哥:我们这里的【6、添加“Interactable”可交互组件】中就应用到了“HandHoverUpdate(Hand hand)” private void HandHoverUpdate(Hand hand){ GrabTypes startingGrabType = hand.GetGrabStarting(); bool isGrabEnding = hand.IsGrabEnding(this.gameObject);
if(interactable.attachedToHand == null && startingGrabType != GrabTypes.None){ oldPosition = transform.position; oldRotation = transform.rotation; hand.HoverLock(interactable); hand.AttachObject(gameObject, startingGrabType, attachmentFlags); }else if(isGrabEnding){ hand.DetachObject(gameObject); hand.HoverUnlock(interactable); transform.position = oldPosition; transform.rotation = oldRotation; } } //立钻哥哥:private void HandHoverUpdate(Hand hand){}
|
++“Hand”手发送给它的子对象的消息 ++++立钻哥哥:OnHandInitialized、OnParentHandHoverBegin、OnParentHandHoverEnd、OnParentHandInputFocusAcquired、OnParentHandInputFocusLost; ++++[OnHandInitialized]:通过将自己与“SteamVR”跟踪控制器的设备ID相关联,首次初始化手时发送; ++++[OnParentHandHoverBegin]:当手开始悬停在某物上时发送; ++++[OnParentHandHoverEnd]:当手离开悬停在某物上时发送; ++++[OnParentHandInputFocusAcquired]:当游戏窗口获得输入焦点时发送; ++++[OnParentHandInputFocusLost]:当游戏窗口失去输入焦点时发送;
|
++“Hand”类中处理连接和分离的成员 ++++立钻哥哥:AttachObject、DetachObject、currentAttachedObject; ++++[AttachObject]:使用传递的AttachmentFlags从手上附加对象; ++++[DetachObject]:从手中分离对象,并可选地将其还原到其原始父对象; ++++[currentAttachedObject]:这将返回手上的“in-focus”附加对象(如果有的话);
|
++“Hand”类中用来定制其行为的有用的属性和功能 ++++立钻哥哥:otherHand、hoverSphereTransform、hoverSphereRadius、hoverLayerMask、hoverUpdateInterval、HoverLock、HoverUnlock、GetGrabStarting、GetGrabEnding; ++++[public Hand otherHand;]:这是Player上的另一只手,这对于需要双手交互的对象(如长弓)非常有用; ++++[public Transform hoverSphereTransform; public float hoverSphereRadius=0.05f;]:可用于自定义手的悬停范围; ++++[public LayerMask hoverLayerMask=-1;]:这可以改变,使手只悬停在某些层的对象上; ++++[public float hoverUpdateInterval=0.1f;]:可以根据游戏的需求定义悬停检查的频率; ++++[public void HoverLock(Interactable interactable){}; public void HoverUnlock(Interactable interactable){};]:这是用来让手只悬停在一个特定的物体上;传递null将使手在悬停锁定时不悬停在其他物体上;此技术用于使手在传送弧处于活动状态时不悬停在物体上; ++++[public GrabTypes GetGrabStarting(GrabTypes explicitType=GrabTypes.None){}; public GrabTypes GetGrabEnding(GrabTypes explicitType=GrabTypes.None){};]:这些用于确定布尔抓取操作是否在那个时候被触发;抓握有两种类型:抓取和捏抓;这些通常与手柄按钮和触发器按钮相关联,但在“Knuckles控制器”上具有特殊功能;
|
++Interactable(可交互的) ++++立钻哥哥:Interactable类更像是一个标识符,它向“手”标识该对象是可交互的; ++++任何具有此“Interactable”组件的对象都将从“Hand”接收相关信息; ++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Interactable.cs(立钻哥哥:此对象将获得悬停事件,并可以附加到手上)
|
|
++++立钻哥哥:“将Throwable组件添加到对象中,将允许玩家拾取并抛出该物体”,“Throwable”是最基本的交互对象之一;当一只手悬停在这个物体上并按下其中一个抓取按钮(通常是扳机或手柄)时,玩家可以拿起这个物体;当按下按钮时,该对象被附在手上并保持在那里;当按钮被释放时,手中的任何速度都被赋予抛出的物体;这让我们可以创建可以拾取和抛出的基本对象;
//Purpose: Basic throwable object.(立钻哥哥:用途:基本抛掷物.) using UnityEngine; using UnityEngine.Events; using System.Collections;
namespace Valve.VR.InteractionSystem{ [RequireComponent(typeof(Interactable))] [RequireComponent(typeof(Rigidbody))] [RequireComponent(typeof(VelocityEstimator))] public class Throwable : MonoBehaviour{ [EnumFlags] [Tooltip(“The flags used to attach this object to the hand.(立钻哥哥:用于将此对象附加到手的标志.)”)] public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.TurnOnKinematic;
[Tooltip(“The local point which acts as a positional and rotational offset to use while held.(立钻哥哥:局部点,在保持时起位置偏移和旋转偏移的作用.)”)] public Transform attachmentOffset;
[Tooltip(“How fast must this object be moving to attach due to a trigger hold instead of a trigger press?(-1 to disable.)(立钻哥哥:由于触发器保持而不是触发器按下,该对象移动到附加时的速度必须有多快?(-1禁用).)”)] public float catchingSpeedThreshold = -1;
public ReleaseStyle releaseVelocityStyle = ReleaseStyle.GetFromHand;
[Tooltip(“This time offset used when releasing the object with the RawFromHand option.(立钻哥哥:使用RawFromHand选项释放对象时使用的时间偏移量.)”)] public float releaseVelocityTimeOffset = -0.011f;
public float scaleReleaseVelocity = 1.1f;
[Tooltip(“When detaching the object, should it return to its original parent?(立钻哥哥:当分离对象时,它应该返回到原来的父对象吗?)”)] public bool restoreOriginalParent = flase;
protected VelocityEstimator velocityEstimator; protected bool attached = false; protected float attachTime; protected Vector3 attachPosition; protected Quaternion attachRotation; protected Transform attachEaseInTransform;
public UnityEvent onPickUp; public UnityEvent onDetachFromHand; public UnityEvent<Hand> onHeldUpdate;
protected RigidbodyInterpolation handInterpolation = RigidbodyInterpolation.None; protected new Rigidbody rigidbody;
[HideInInspector] public Interactable interactable;
protected virtual void Awake(){ velocityEstimator = GetComponent<VelocityEstimator>(); interactable = GetComponent<Interactable>();
rigidbody = GetComponent<Rigidbody>(); rigidbody.maxAngularVelocity = 50.0f;
if(attachmentOffset != null){ //remove? //interactable.handFollowTransform = attachmentOffset; } } //立钻哥哥:protected virtual void Awake(){}
protected virtual void OnHandHoverBegin(Hand hand){ bool showHint = false;
//”Catch” the throwable by holding down the interaction button instead of pressing it. Only do this if the throwable is moving faster than the prescribed threshold speed, and if it isn’t attached to another hand.(立钻哥哥:按下交互按钮,而不是按下按钮,就可以“捕捉”可扔物品。只有当投掷物的移动速度超过规定的阈值速度,并且没有附在另一只手上时才这样做.) if(!attached && catchingSpeedThreshold != -1){ float catchingThreshold = catchingSpeedThreshold * SteamVR_Utils.GetLossyScale(Player.instance.trackingOriginTransform); GrabTypes bestGrabType = hand.GetBestGrabbingType();
if(bestGrabType != GrabTypes.None){ if(rigidbody.velocity.magnitude >= catchingThreshold){ hand.AttachObject(gameObject, bestGrabType, attachmentFlags); showHint = false; } } }
if(showHint){ hand.ShowGrabHint(); } } //立钻哥哥:protected virtual void OnHandHoverBegin(Hand hand){}
protected virtual void OnHandHoverEnd(Hand hand){ hand.HideGrabHint(); }
protected virtual void HandHoverUpdate(Hand hand){ GrabTypes startingGrabType = hand.GetGrabStarting(); if(startingGrabType != GrabTypes.None){ hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset); hand.HideGrabHint(); } } //立钻哥哥:protected virtual void HandHoverUpdate(Hand hand){}
protected virtual void OnAttachedToHand(Hand hand){ //Debug.Log(“[SteamVR Interaction] Pickup: ” + hand.GetGrabStarting().ToString()); hadInterpolation = this.rigidbody.interpolation; attached = true; onPickUp.Invoke(); hand.HoverLock(null); rigidbody.interpolation = RigidbodyInterpolation.None; velocityEstimator.BeginEstimatingVelocity();
attachTime = Time.time; attachPosition = transform.position; attachRotation = transform.rotation; } //立钻哥哥:protected virtual void OnAttachedToHand(Hand hand){}
protected virtual void OnDetachedFromHand(Hand hand){ attached = false; onDetachFromHand.Invoke(); hand.HoverUnlock(null); rigidbody.interpolation = hadInterpolation;
Vector3 velocity; Vector3 angularVelocity; GetReleaseVelocities(hand, out velocity, out angularVelocity);
rigidbody.velocity = velocity; rigidbody.angularVelocity = angularVelocity; } //立钻哥哥:protected virtual void OnDetachedFromHand(Hand hand){}
public virtual void GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity){ if(hand.noSteamVRFallbackCamera && releaseVelocityStyle != ReleaseStyle.NoChange){ //only type that works with fallback hand is short estimation.(立钻哥哥:只有使用备用手的类型是short estimate.) releaseVelocityStyle = ReleaseStyle.ShortEstimation; }
switch(releaseVelocityStyle){ case ReleaseStyle.ShortEstimation: velocityEstimator.FinishEstimatingVelocity(); velocity = velocityEstimator.GetVelocityEstimate(); angularVelocity = velocityEstimator.GetAngularVelocityEstimate(); break; case ReleaseStyle.AdvancedEstimation: hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity); break; case ReleaseStyle.GetFromHand: velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset); angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset); break; default: case ReleaseStyle.NoChange: velocity = rigidbody.velocity; angularVelocity = rigidbody.angularVelocity; break; } //立钻哥哥:switch(releaseVelocityStyle){}
if(releaseVelocityStyle != ReleaseStyle.NoChange){ velocity *= scaleReleaseVelocity; } } //立钻哥哥:public virtual void GetReleaseVelocities(){}
protected virtual void HandAttachedUpdate(Hand hand){ if(hand.IsGrabEnding(this.gameObject)){ hand.DetachObject(gameObject, restoreOriginalParent);
//Uncomment to detach ourselves late in the frame. This is so that any vehicles the player is attached to have a chance to finish updating themselves. If we detach now, our position could be behind what it will be at the end of the frame, and the object may appear to teleport behind the hand when the player releases it.(立钻哥哥:取消注释,以便在稍后的帧中分离我们自己。这样玩家所连接的任何物体都有机会完成自我更新。如果我们现在分离,我们的位置可能在帧后调用,当玩家释放这个物体时,它可能会出现在手的后面.) //StartCoroutine(LateDetach(hand)); //立钻哥哥:稍后分离 }
if(onHeldUpdate != null){ onHeldUpdate.Invoke(hand); } } //立钻哥哥:protected virtual void HandAttachedUpdate(Hand hand){}
protected virtual IEnumerator LateDetach(Hand hand){ yield return new WaitForEndOfFrame();
hand.DetachObject(gameObject, restoreOriginalParent); } //立钻哥哥:protected virtual IEnumerator LateDetach(Hand hand){}
protected virtual void OnHandFocusAcquired(Hand hand){ gameObject.SetActive(true); velocityEstimator.BeginEstimatingVelocity(); } //立钻哥哥:protected virtual void OnHandFocusAcquired(Hand hand){}
protected virtual void OnHandFocusLost(Hand hand){ gameObject.SetActive(false); velocityEstimator.FinishEstimatingVelocity(); } //立钻哥哥:protected virtual void OnHandFocusLost(Hand hand){} } //立钻哥哥:public class Throwable:MonoBehaviour{}
public enum ReleaseStyle{ NoChange, GetFromHand, ShortEstimation, AdvancedEstimation, } //立钻哥哥:public enum ReleaseStyle{}
} //立钻哥哥:namespace Valve.VR.InteractionSystem{}
|
|
++知识点01:ReleaseStyle ++++立钻哥哥:public ReleaseStyle releaseVelocityStyle = ReleaseStyle.GetFromHand; public enum ReleaseStyle{ NoChange, GetFromHand, ShortEstimation, AdvancedEstimation, }
|
|
++知识点02:VelocityEstimator ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs //Purpose: Estimates the velocity of an object based on change in position.(立钻哥哥:目的:根据物体位置的变化来估计物体的速度.) using UnityEngine; using System.Collections; namespace Valve.VR.InteractionSystem{ public class VelocityEstimator : MonoBehaviour{ public int velocityAverageFrames = 5; public int angularVelocityAverageFrames = 11; public bool estimateOnAwake = false; private Coroutine routine; private int sampleCount; private Vector3[] velocitySamples; private Vector3[] angularVelocitySamples;
public void BeginEstimatingVelocity(){} public void FinishEstimatingVelocity(){} public Vector3 GetVelocityEstimate(){} public Vector3 GetAngularVelocityEstimate(){} public Vector3 GetAccelerationEstimate(){}
void Awake(){} private IEnumerator EstimateVelocityCoroutine(){} } //立钻哥哥:public class VelocityEstimator:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} ++++[RequireComponent(typeof(VelocityEstimator))] ++++protected VelocityEstimator velocityEstimator; ++++velocityEstimator = GetComponent<VelocityEstimator>(); ++++velocityEstimator.BeginEstimatingVelocity(); ++++velocityEstimator.FinishEstimatingVelocity(); ++++velocity = velocityEstimator.GetVelocityEstimate(); ++++angularVelocity = velocityEstimator.GetAngularVelocityEstimate(); ++++velocityEstimator.BeginEstimatingVelocity(); ++++velocityEstimator.FinishEstimatingVelocity();
|
|
++知识点02:Hand ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs //Purpose: The hands used byt the player in the vr interaction system.(立钻哥哥:用途:VR交互系统中玩家使用的手.) using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using UnityEngine.Events; using System.Threading;
namespace Valve.VR.InteractionSystem{ //Links with an appropriate SteamVR controller and facilitates interactions with objects in the virtual world.(立钻哥哥:链接到适当的SteamVR控制器,并方便与虚拟世界中的对象进行交互.) public class Hand : MonoBehaviour{ //The flags used to determine how an object is attached to the hand.(立钻哥哥:用于确定对象如何附加到手的标志.) [Flags] public enum AttachmentFlags{}
public const AttachmentFlags defaultAttachmentFlags = AttachmentFlags.ParentToHand | AttachmentFlags.DetachOthers | AttachmentFlags.DetachFromOtherHand | AttachmentFlags.TurnOnKinematic | AttachmentFlags.SnapOnAttach; public Hand otherHand; public SteamVR_Input_Sources handType; public SteamVR_Behaviour_Pose trackedObject; public SteamVR_Action_Boolean grabPinchAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(“GrabPinch”); public SteamVR_Action_Boolean grabGripAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(“GrabGrip”); public SteamVR_Action_Vibration hapticAction = SteamVR_Input.GetAction<SteamVR_Action_Vibration>(“Haptic”); public SteamVR_Action_Boolean uiInteractAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(“InteractUI”); ... ... } //立钻哥哥: public class Hand:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} ++++public Hand.AttachmentFlags attachmentFlags = Hand.AttachmentFlags.ParentToHand | Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.TurnOnKinematic; ++++public UnityEvent<Hand> onHeldUpdate; ++++protected virtual void OnHandHoverBegin(Hand hand){} ++++GrabTypes bestGrabType = hand.GetBestGrabbingType(); ++++hand.AttachObject(gameObject, bestGrabType, attachmentFlags); ++++hand.ShowGrabHint(); ++++protected virtual void OnHandHoverEnd(Hand hand){} ++++hand.HideGrabHint(); ++++protected virtual void HandHoverUpdate(Hand hand){} ++++GrabTypes startingGrabType = hand.GetGrabStarting(); ++++hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset); ++++protected virtual void OnAttachedToHand(Hand hand){} ++++hand.HoverLock(null); ++++protected virtual void OnDetachedFromHand(Hand hand){} ++++hand.HoverUnlock(null); ++++GetReleaseVelocities(hand, out velocity, out angularVelocity); ++++public virtual void GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity){} ++++if(hand.noSteamVRFallbackCamera && releaseVelocityStyle!=ReleaseStyle.NoChange){} ++++hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity); ++++velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset); ++++angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset); ++++protected virtual void HandAttachedUpdate(Hand hand){} ++++if(hand.IsGrabEnding(this.gameObject)){} ++++hand.DetachObject(gameObject, restoreOriginalParent); ++++onHeldUpdate.Invoke(hand); ++++protected virtual IEnumerator LateDetach(Hand hand){} ++++hand.DetachObject(gameObject, restoreOriginalParent); ++++protected virtual void OnHandFocusAcquired(Hand hand){} ++++protected virtual void OnHandFocusLost(Hand hand){}
|
|
++知识点03:UnityEvent ++++立钻哥哥:C:\Users\unity\AppData\Local\Temp\MetadataAsSource\4d44249b313b4410af4d2d6d08747e70\af4587a0fa6c4928911d2554e9cffda8\UnityEvent.cs //程序集 UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null //E:\E_ProgramFiles_02\UnitySetup64-2018.3.0f2\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll using System.Reflection; using UnityEngine.Scripting; namespace UnityEngine.Events{ //A zero argument persistent callback that can be saved with the Scene.(立钻哥哥:可以与场景一起保存的零参数持久回调.) public class UnityEvent : UnityEventBase{ [RquiredByNativeCode] public UnityEvent(); public void AddListener(UnityAction call); public void Invoke(); public void RemoveListener(UnityAction call);
protected override MethodInfo FindMethod_Impl(string name, object targetObj); } //立钻哥哥:public class UnityEvent:UnityEventBase{} } //立钻哥哥:namespace UnitEngine.Events{} ++++public UnityEvent onPickUp; ++++public UnityEvent onDetachFromHand; ++++public UnityEvent<Hand> onHeldUpdate;
|
|
++知识点04:RigidbodyInterpolation ++++立钻哥哥:C:\Users\unity\AppData\Local\Temp\MetadataAsSource\4d44249b313b4410af4d2d6d08747e70\7c712a196dab48d19d50417cc6836298\RigidbodyInterpolation.cs //程序集 UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null //E:\E_ProgramFiles_02\UnitySetup64-2018.3.0f2\Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll namespace UnityEngine{ //Rigidbody interpolation mode.(立钻哥哥:Rigidbody插值模式.) public enum RigidbodyInterpolation{ None = 0, Interpolate = 1, Extrapolate = 2 } //立钻哥哥:public enum RigidbodyInterpolation{} } //立钻哥哥:namespace UnityEngine{} ++++protected RigidbodyInterpolation hadInterpolation = RigidbodyInterpolation.None; ++++rigidbody.interpolation = RigidbodyInterpolation.None;
|
|
++知识点05:SteamVR_Utils.GetLossyScale ++++立钻哥哥:\Assets\SteamVR\Scripts\SteamVR_Utils.cs
++++float catchingThreshold = catchingSpeedThreshold * SteamVR_Utils.GetLossyScale(Player.instance.trackingOriginTransform);
|
|
++知识点06:hand.GetBestGrabbingType ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++GrabTypes bestGrabType = hand.GetBestGrabbingType();
|
|
++知识点07:GrabTypes ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\GrabTypes.cs
++++GrabTypes bestGrabType = hand.GetBestGrabbingType(); ++++if(bestGrabType != GrabType.None){} ++++GrabTypes startingGrabType = hand.GetGrabStarting(); ++++if(startingGrabType != GrabType.None){}
|
|
++知识点08:hand.AttachObject ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.AttachObject(gameObject, bestGrabType, attachmentFlags); ++++hand.AttachObject(gameObject, startingGrabType, attachmentFlags, attachmentOffset);
|
|
++知识点09:hand.ShowGrabHint ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.ShowGrabHint();
|
|
++知识点10:hand.HideGrabHint ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.HideGrabHint();
|
|
++知识点11:hand.HoverLock ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.HoverLock(null);
|
|
++知识点12:velocityEstimator.BeginEstimatingVelocity ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs
++++velocityEstimator.BeginEstimatingVelocity();
|
|
++知识点13:hand.HoverUnlock ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.HoverUnlock(null);
|
|
++知识点14:velocityEstimator.FinishEstimatingVelocity ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs
++++velocityEstimator.FinishEstimatingVelocity();
|
|
++知识点15:velocityEstimator.GetVelocityEstimate ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs
++++velocity = velocityEstimator.GetVelocityEstimate();
|
|
++知识点16:velocityEstimator.GetAngularVelocityEstimate ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs
++++angularVelocity = velocityEstimator.GetAngularVelocityEstimate();
|
|
++知识点17:hand.GetEstimatedPeakVelocites ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.GetEstimatedPeakVelocities(out velocity, out angularVelocity);
|
|
++知识点18:hand.GetTrackedObjectVelocity ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\VelocityEstimator.cs
++++velocity = hand.GetTrackedObjectVelocity(releaseVelocityTimeOffset);
|
|
++知识点19:hand.GetTrackedObjectAngularVelocity ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++angularVelocity = hand.GetTrackedObjectAngularVelocity(releaseVelocityTimeOffset);
|
|
++知识点20:hand.IsGrabEnding ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++if(hand.IsGrabEnding(this.gameObject)){}
|
|
++知识点21:hand.DetachObject ++++立钻哥哥:\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++hand.DetachObject(gameObject, restoreOriginalParent);
|
|
|
++++立钻哥哥:将“SteamVR_Skeleton_Poser”组件添加到带有“Interactable”的GameObject(游戏物体)中,并在与之交互时摆出我们想要的手的样子;
++++[Skeleton Poser(骨骼姿态)]:“SteamVR_Skeleton_Poser”组件脚本被设计成独立于“SteamVR交互系统”运行,并且可以添加到我们自己的系统中;这个组件将在后面补充比较详细的描述,请继续往下查阅吧!(官方Demo链接:https://valvesoftware.github.io/steamvr_unity_plugin/tutorials/Skeleton-Poser.html)
using System; using System.Collections; using UnityEngine; using Valve.VR; using System.Collectons.Generic; using System.Linq;
namespace Valve.VR{ public class SteamVR_Skeleton_Poser : MonoBehaviour{ public GameObject previewLeftHandPrefab; public GameObject previewRightHandPrefab;
public SteamVR_Skeleton_Pose skeletonMainPose; public List<SteamVR_Skeleton_Pose> skeletonAdditionalPose = new List<SteamVR_Skeleton_Pose>();
[SerializeField] protected bool showLeftPreview = false; protected bool showRightPreview = true; protected GameObejct previewLeftInstance; protected GameObject previewRightInstance; protected int previewPoseSelection = 0;
public int blendPoseCount{}
public List<PoseBlendingBehaviour> blendingBehaviours = new List<PoseBlendingBehaviour>(); public SteamVR_Skeleton_PoseSnapshot blendedSnapShotL; public SteamVR_Skeleton_PoseSnapshot blendedSnapShortR; private SkeletonBlendablePose[] blendPoses; private int boneCount; private bool poseUpdateThisFrame; public float scale;
protected void Awake(){}
//Set the blending value of a blendingBehaviour. Works best on Manual type behaviours.(立钻哥哥:设置混合行为的混合值。最适用于手动类型的行为.) public void SetBlendingBehaviourValue(string behaviourName, float value){}
//Get the blending value of a blendingBehaviour.(立钻哥哥:获取混合行为的混合值) public float GetBlendingBehaviourValue(string behaviourName){}
//Enable or disable a blending behaviour.(立钻哥哥:启用或禁用混合行为.) public void SetBlendingBehaviourEnabled(string behaviourName, bool value){}
//Check if a blending behaviour is enabled.(立钻哥哥:检查是否启用了混合行为) public bool GetBlendingBehaviourEnabled(string behaviourName){}
//Get a blending behaviour by name.(立钻哥哥:通过名称获得混合行为) public PoseBlendingBehaviour GetBlendingBehaviour(string behaviourName){}
public SteamVR_Skeleton_Pose GetPoseByIndex(int index){} private SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Source inputSource){}
//Retrieve the final animated pose, to be applied to a hand skeleton.(立钻哥哥:检索要应用于手部骨骼的最终动画姿势.) public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources handType){} public SteamVR_Skeleton_PoseSnapshot GetBlendedPose(SteamVR_Behaviour_Skeleton skeletonBehaviour){}
//Updates all pose animation and blending. Can be called from different places without performance concerns, as it will only let itself run once per frame.(立钻哥哥:更新所有的姿态动画和混合。可以从不同的地方调用,而不需要考虑性能问题,因为它只允许自己在每帧中运行一次.) public void UpdatePose(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource){}
protected void ApplyBlenderBehaviours(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource, SteamVR_Skeleton_PoseSnapshot snapshot){}
protected void LateUpdate(){}
//Weighted average of n vector2s.(立钻哥哥:n个向量的加权平均) public Vector3 BlendVectors(Vector3[] vectors, float[] weights){}
//Weighted average of n quaternions.(立钻哥哥:n个四元数的加权平均) protected Quaternion BlendQuaternions(Quaternion[] quaternions, float[] weights){}
//A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.(立钻哥哥:SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动.) public class SkeletonBlendablePose{ public SteamVR_Skeleton_Pose pose; public SteamVR_Skeleton_PoseSnapshot snapshotR; public SteamVR_Skeleton_PoseSnapshot snapshotL;
//Get the snapshot of this pose with effects such as additive finger animation applied.(立钻哥哥:使用添加手指动画等效果获取此姿态的快照.) public SteamVR_Skeleton_PoseSnapshot GetHandSnapshot(SteamVR_Input_Sources inputSource){}
public void UpdateAdditiveAnimation(SteamVR_Action_Skeleton skeletonAction, SteamVR_Input_Sources inputSource){}
//Init based on an existing Skeleton_Pose.(立钻哥哥:初始化基于一个现有的骨架姿态.) public SkeletonBlendablePose(SteamVR_Skeleton_Pose p){}
//Copy tht base pose into the snapshots.(立钻哥哥:将基本姿势复制到快照中) public void PoseToSnapshots(){}
public SkeletonBlendablePose(){}
} //立钻哥哥:public class SkeletonBlendablePose{}
//A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.(立钻哥哥:用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面.) [System.Serializable] public class PoseBlendingBehaviour{ public string name; public bool enabled = true; public float influence = 1; public int pose = 1; public float value = 0; public SteamVR_Action_Single action_single; public SteamVR_Action_Boolean action_bool; public float smoothingSpeed = 0; public BlenderTypes type; public bool useMask; public SteamVR_Skeleton_HandMask mask = new SteamVR_Skeleton_HandMask(); public bool previewEnabled;
//Performs smoothing based on deltaTime parameter.(立钻哥哥:基于deltaTime参数执行平滑.) public void Update(){}
//Apply blending this behaviour’s pose to an existing snapshot.(立钻哥哥:将此行为的姿态混合应用于现有快照.) public void ApplyBlending(SteamVR_Skeleton_PoseSnapshot snapshot, SkeletonBlendablePose[] blendPose, SteamVR_Input_Sources inputSource){}
public PoseBlendingBehaviour(){}
public enum BlenderTypes{ Manual, AnalogAction, BooleanAction } //立钻哥哥:public enum BlenderTypes{}
} //立钻哥哥:public class PoseBlendingBehaviour{}
} //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}
//PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.(立钻哥哥:PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势.) public class SteamVR_Skeleton_PoseSnapshot{ public Vector3 position; public Quaternion rotation; public Vector3[] bonePositions; public Quaternion[] boneRotations;
public SteamVR_Skeleton_PoseSnapshot(int boneCount, SteamVR_Input_Sources source){}
//Perform a deep copy from one poseSnapshot to another.(立钻哥哥:执行从一个位置到另一个位置的深度复制.) public void CopyFrom(SteamVR_Skeleton_PoseSnapshot source){}
} //立钻哥哥:public class SteamVR_Skeleton_PoseSnapshot{}
//Simple mask for fingers.(立钻哥哥:简单的手指遮罩) [System.Serializable] public class SteamVR_Skeleton_HandMask{ public bool palm; public bool thumb; public bool index; public bool middle; public bool ring; public bool pinky; public boo[] values = new bool[6];
public void SetFinger(int i, bool value){} public bool GetFinger(int i){}
public SteamVR_Skeleton_HandMask(){}
//All elements on.(立钻哥哥:所有的元素.) public void Reset(){}
protected void Apply(){}
public static readonly SteamVR_Skeleton_HandMask fullMask = new SteamVR_Skeleton_HandMask();
} //立钻哥哥:public class SteamVR_Skeleton_HandMask{}
} //立钻哥哥:namespace Valve.VR{}
|
||||
++SteamVR_Skeleton_Poser相关的类 ++++立钻哥哥:“SteamVR_Skeleton_Poser”相关的平级类有:“public class SteamVR_Skeleton_PoseSnapshot{}”和“public class SteamVR_Skeleton_HandMask{}”,注意:这两个类没有继承MonoBehaviour,应该是一个数据类; ++++“public class SteamVR_Skeleton_Poser:MonoBehaviour{}”内嵌的类有:“public class SkeletonBlendablePose{}”和“public class PoseBlendingBehaviour{}”,注意:这没有继承MonoBehaviour,应该是一个数据类; namespace Valve.VR{ public class SteamVR_Skeleton_Poser : MonoBehaviour{ //A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.(立钻哥哥:SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动.) public class SkeletonBlendablePose{ } //立钻哥哥:public class SkeletonBlendablePose{}
//A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.(立钻哥哥:用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面.) [System.Serializable] public class PoseBlendingBehaviour{ } //立钻哥哥:public class PoseBlendingBehaviour{}
} //立钻哥哥:public class SteamVR_Skeleton_Poser:MonoBehaviour{}
//PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.(立钻哥哥:PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势.) public class SteamVR_Skeleton_PoseSnapshot{ } //立钻哥哥:public class SteamVR_Skeleton_PoseSnapshot{}
//Simple mask for fingers.(立钻哥哥:简单的手指遮罩) [System.Serializable] public class SteamVR_Skeleton_HandMask{ } //立钻哥哥:public class SteamVR_Skeleton_HandMask{}
} //立钻哥哥:namespace Valve.VR{}
|
||||
++知识点01:SteamVR_Skeleton_Poser ++++立钻哥哥:“SteamVR_Skeleton_Poser”组件是在“v2.2RC1”版本中增加的,简化了创建姿势,很容易与“SteamVR骨骼系统”兼容,例如,检查“交互系统”场景中的对象,或者将组件添加到“Interactable”中; ++++“SteamVR_Skeleton_Poser”脚本被设计成独立于“SteamVR交互系统”,并且可以添加到我们自己的系统中; ++++我们可以将“SteamVR_Skeleton_Poser”组件添加到带有“Interactable”的GameObject(游戏物体)中,并在与之交互时摆出我们想要的手的样子;(You can then add the “SteamVR_Skeleton_Poser” component to a GameObject with an “Interactable” and pose how you want the hand to look when interacting with it.)
++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Interactable.cs
++++-\Assets\SteamVR\Input\SteamVR_Behaviour_Skeleton.cs
++++\Assets\SteamVR\Input\Editor\SteamVR_Skeleton_PoserEditor.cs
++++public class SteamVR_Skeleton_Poser:MonoBehaviour{}
|
||||
++知识点02:SKeletonBlendablePose ++++立钻哥哥:A SkeletonBlendablePose holds a reference to a Skeleton_Pose scriptableObject, and also contains some helper functions. Also handles pose-specific animation like additive finger motion.(SkeletonBlendablePose持有对Skeleton_Pose脚本对象的引用,并且还包含一些帮助函数。还处理特定位置的动画,如添加手指运动)
++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs
++++public class SkeletonBlendablePose{}
|
||||
++知识点03:PoseBlendingBehaviour ++++立钻哥哥:A filter applied to the base pose. Blends to a secondary pose by a certain weight. Can be masked per-finger.(用于基本位姿的滤波器。通过一定的重量调整到第二个姿势。每个手指都可以蒙面。)
++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs
++++\Assets\SteamVR\Input\Editor\SteamVR_Skeleton_PoserEditor.cs
++++public class PoseBlendingBehaviour{}
|
||||
++知识点04:SteamVR_Skeleton_PoseSnapshot ++++立钻哥哥:PoseSnapshots hold a skeleton pose for one hand, as well as storing which hand they contain. They have several functions for combining BlendablePoses.(PoseSnapshots为一只手保留一个骨架的姿势,同时也保存了它们包含的那只手。他们有几个功能,以结合可调和的姿势)
++++\Assets\SteamVR\Input\SteamVR_Behaviour_Skeleton.cs
++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs
++++\Assets\SteamVR\InteractionSystem\Core\Scripts\Hand.cs
++++public class SteamVR_Skeleton_PoseSnapshot{}
|
||||
++知识点05:SteamVR_Skeleton_HandMask ++++立钻哥哥:Simple mask for fingers.(简单的手指遮罩)
++++\Assets\SteamVR\Input\SteamVR_Skeleton_Poser.cs
++++public class SteamVR_Skeleton_HandMask{}
|
||||
|
----尝试1:直接在一个Cube上挂载“SteamVR_Skeleton_Poser”组件,没有能拿起来!
----尝试2:那我们就添加一个“Throwable”组件吧,因为这个组件会自动加载“Interactable”组件;其实我们需要的是验证“SkeletonPoser和Interactable”之间的配合关系呢!(立钻哥哥:还是没有手势呢!!)
----尝试3:参考官方Demo示例,挂载缺失的脚本,看看能不能有奇迹出现呢?(比对后缺少脚本:“InteractableHoverEvents.cs”、“TargetHitEffect.cs”):挂载了这两个脚本,运行后还是没有出现手呢!?运行前倒是有一只手了?仅在运行前能显示出来,运行后就没有了!
++++立钻哥哥:经过第一轮的各种尝试,还没有成功,暂且跳过这个环节,后期会推出对于“SteamVR_Skeleton_Poser”组件的专题,请在“SteamVR”分类中查阅:
https://blog.csdn.net/vrunsoftyanlz/article/category/8582642
+++++立钻哥哥:官网也有关于“Skeleton Poser”的教程,后期会根据这个教程整理一个专题:
https://valvesoftware.github.io/steamvr_unity_plugin/tutorials/Skeleton-Poser.html
++++SteamVR_Skeleton_Poser:https://blog.csdn.net/VRunSoftYanlz/article/details/89931725
++++立钻哥哥:To add teleporting to your scene drag in the “Teleporting” prefab from “Teleport/Prefabs” into your scene. This will set up all the teleport logic.(要在场景中添加“远程传送”功能,请将“远程传送”预制件从“Teleport/Prefabs”拖动到场景中,这将设置所有的传送逻辑。)
++++关于“传送机制”有一篇专门的博客:https://blog.csdn.net/VRunSoftYanlz/article/details/89390866
++++“The Lab(Valve的实验室)”的传送系统支持传送到特定的传送点或更通用的传送区;重要的类是“Teleport”、“TeleportPoint”、“TeleportArea”;
++++“Teleport/Prefabs”下的预制体“Teleporting”包括了传送系统运作的所有逻辑;向场景中添加“TeleportPoints”或“TeleportAreas”,可以添加玩家可以传送到的点;
++++“Teleport.cs”这个类处理“Teleporting传送”的大部分逻辑;当触摸板被按下时,传送指针就会出现,当指针指向一个有效的点,松开即可传送玩家;(我们也可以按下键盘上的“T”,在2D备份模式下,可以打开传送指针),“Teleport.cs”该类跟踪场景中的所有传送端口标记,并根据传送端口指针的状态通知它们淡入/淡出;
++++在某些情况下,在地板上使用不同于传送网格的网格是很有用的,在这种情况下,传送系统将追踪它击中传送网的位置,并试图将其放置在地板网孔上,这样做的目的是尝试将场景中的视觉地板与玩家游戏区域中的物理地板匹配起来;
----[tracerLayerMask]:这是传送指针将尝试命中的所有层;
----[floorFixupMask]:地板所在的层;
----[floorFixupMaximumTraceDistance]:查找地板的最大跟踪距离;
----[ShowPlayAreaMarker]:这将切换是否显示传送时玩家游戏区域的矩形,这可以帮助玩家在他们的物理空间中找到方向;
----[arcDistance]:传送弧应该走多远,增加这个数字将允许玩家在场景中传送得更远,这个值可能需要为每个场景进行调整;
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\Teleport.cs //Purpose: Handles all the teleport logic.(立钻哥哥:用途:处理所有的传送逻辑.) using UnityEngine; using UnityEngine.Events; using System.Collections;
namespace Valve.VR.InteractionSystem{ public class Teleport : MonoBehaviour{ public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteaVR_Action_Boolean>(“Teleport”);
private Hand pointerHand = null; private Player player = null; private TeleportArc teleportArc = null;
private static Teleport _instance; public static Teleport instance{}
void Awake(){ instance = this; }
private void UpdatePointer(){} private void TeleportPlayer(){} } //立钻哥哥:public class Teleport:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{}
|
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportMarkerBase.cs //Purpose: Base class for all the objects that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的所有对象的基类.) using UnityEngine;
namespace Valve.VR.InteractionSystem{ public abstract class TeleportMarkerBase : MonoBehaviour{ public bool locked = false; public bool markerActive = false;
public virtual bool showReticle{} public void SetLocked(bool locked){} public virtual void TeleportPlayer(Vector3 pointedAtPosition){} public abstract void UpdateVisuals(); public abstract void Highlight(bool highlight); public abstract void SetAlpha(float tintAlpha, float alphaPercent); public abstract bool ShouldActivate(Vector3 playerPosition); public abstract bool ShouldMovePlayer(); } //立钻哥哥:public abstract class TeleportMarkerBase:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportArea.cs //Purpose: An area that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的区域.) using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif
namespace Valve.VR.InteractionSystem{ public class TeleportArea : TeleportMarkerBase{ public Bounds meshBounds{} private MeshRenderer areaMesh;
public void Awake(){ areaMesh = GetComponent<MeshRenderer>(); tintColorId = Shader.PropertyToID(“_TintColor”); CalculateBounds(); }
public void Start(){}
public override bool ShouldActivate(Vector3 playerPosition){} public override bool ShouldMovePlayer(){} public override void Highlight(bool highlight){} public override void SetAlpha(float tintAlpha, float alphaPercent){} public override void UpdateVisuals(){} private bool CalculateBounds(){} private Color GetTintColor(){} } //立钻哥哥:public class TeleportArea:TeleportMarkerBase{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{}
|
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportPoint.cs //Purpose: Single location that the player can teleport to.(立钻哥哥:用途:单一的位置,玩家可以传送到.) using UnityEngine; using UnityEngine.UI; #if UNITY_EDITOR using UnityEditor; #endif
namespace Valve.VR.InteractionSystem{ public class TeleportPoint : TeleportMarkerBase{ public enum TeleportPointType{ MoveToLocation, SwitchToNewScene };
public TeleportPointType teleportType = TeleportPointType.MoveToLocation;
public override bool showReticle{} void Awake(){} void Start(){} void Update(){} public override bool ShouldActivate(Vector3 playerPosition){} public override bool ShouldMovePlayer(){} public override void Highlight(bool highlight){} public override void UpdateVisuals(){} public override void SetAlpha(float tintAlpha, float alphaPercent){} public void SetMeshMaterials(Material material, Color textColor){} public void TeleportToScene(){} public void GetRelevantComponents(){} public void ReleaseRelevantComponents(){} public void UpdateVisualsInEditor(){} } //立钻哥哥:public class TeleportPoint:TeleportMarkerBase{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportArc.cs //Purpose: Displays the arc lines for teleporting and does the traces.(立钻哥哥:用途:显示用于远程传送的弧线并进行跟踪.) using UnityEngine;
namespace Valve.VR.InteractionSystem{ public class TeleportArc : MonoBehaviour{ public int segmentColor = 60; public float thickness = 0.01f;
void Start(){} void Update(){} private void CreateLineRendererObjects(){} public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle){} public void Show(){} public void Hide(){} public bool DrawArc(out RaycastHit hitInfo){} private void DrawArcSegment(int index, float startTime, float endTime){} public void SetColor(Color color){} private float FindProjectileCollison(out RaycastHit hitInfo){} public Vector3 GetArcPositionAtTime(float time){} private void HideLineSegments(int startSegment, int endSegment){} } //立钻哥哥:public class TeleportArc:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\AllowTeleportWhileAttachedToHand.cs //Purpose: Adding this component to an object will allow the player to initiate teleporting while that object is attached to their hand.(立钻哥哥:目的:将这个组件添加到一个对象将允许玩家在该对象与他们的手连接时启动传送) using UnityEngine; namespace Valve.VR.InteractionSystem{ public class AllowTeleportWhileAttachedToHand : MonoBehaviour{ public bool teleportAllowed = true; public bool overrideHoverLock = true; } //立钻哥哥:public class AllowTeleportWhileAttachedToHand:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\IgnoreTeleportTrace.cs //Purpose: Allows the teleport arc trace to pass through any colliders on this object.(立钻哥哥:目的:允许传送弧跟踪通过该对象上的任何碰撞器) using UnityEngine; using System.Collections; namespace Valve.VR.InteractionSystem{ public class IgnoreTeleportTrace : MonoBehaviour{ } //立钻哥哥:public class IgnoreTeleportTrace:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
----首先,我们直接拖一个预制体(\Assets\SteamVR\InteractionSystem\Teleport\Prefabs\Teleporting.prefab)到场景中,运行一下看看效果吧;
----运行很顺利,而且效果也还不错,没有什么明显的bug,可以直接拿来用的,如果想实现传送功能,还需要继续往下操作“10、添加TeleportPoint传送点预制体”和“11、添加TeleportArea传送区域预制体”;
++++立钻哥哥:经过上面的操练,这个“Teleporting”预制体还是比较顺利的运行了,那我们就来看看这个预制体中的核心代码吧!(核心代码就两个:“Teleport.cs”和“TeleportArc.cs”)
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\Teleport.cs //Purpose: Handles all the teleport logic.(立钻哥哥:用途:处理所有的传送逻辑.) using UnityEngine; using UnityEngine.Events; using System.Collections;
namespace Valve.VR.InteractionSystem{ public class Teleport : MonoBehaviour{ public SteamVR_Action_Boolean teleportAction = SteamVR_Input.GetAction<SteamVR_Action_Boolean>(“Teleport”);
public LayerMask traceLayerMask; public LayerMask floorFixupTraceLayerMask; public float floorFixupMaximumTraceDistance = 1.0f; public Material areaVisibleMaterial; public Material areaLockedMaterial; public Material areaHighlightedMaterial; public Material pointVisibleMaterial; public Material pointLockedMaterial; public Material pointHighlightedMaterial; public Transform destinationReticleTransform; public Transform invalidReticleTransform; public GameObject playAreaPreviewCorner; public GameObject playAreaPreviewSide; public Color pointerValidColor; public Color pointerInvalidColor; public Color pointerLockedColor; public bool showPlayAreaMarker = true;
public float teleportFadeTime = 0.1f; public float meshFadeTime = 0.2f; public float arcDistance = 10.0f;
[Header(“Effects(立钻哥哥:效果)”)] public Transform onActivateObjectTransform; public Transform onDeactivateObjectTransform; public float activateObjectTime = 1.0f; public float deactivateObjectTime = 1.0f;
[Header(“Audio Sources(立钻哥哥:声音来源)”)] public AudioSource pointerAudioSource; public AudioSource loopingAudioSource; public AudioSource headAudioSource; public AudioSource reticleAudioSource;
[Header(“Sounds(立钻哥哥:音效)”)] public AudioClip teleportSound; public AudioClip pointerStartSound; public AudioClip pointerLoopSound; public AudioClip pointerStopSound; public AudioClip goodHighlightSound; public AudioClip badHighlightSound;
[Header(“Debug(立钻哥哥:调试)”)] public bool debugFloor = false; public bool showOffsetReticle = false; public Transform offsetReticleTransform; public MeshRenderer floorDebugSphere; public LineRenderer floorDebugLine;
private LineRenderer pointerLineRenderer; private GameObject teleportPointerObject; private Transform pointerStartTransform; private Hand pointerHand = null; private Player player = null; private TeleportArc teleportArc = null;
private bool visible = false;
private TeleportMarkerBase[] teleportMarkers; private TeleportMarkerBase pointedAtTeleportMarker; private TeleportMarkerBase teleportingToMarker; private Vector3 pointedAtPosition; private Vector3 prevPointedAtPosition; private bool teleporting = false; private float currentFadeTime = 0.0f;
private float meshAlphaPercent = 1.0f; private float pointerShowStartTime = 0.0f; private float pointerHideStartTime = 0.0f; private bool meshFading = false; private float fullTintAlpha;
private float invalidReticleMinScale = 0.2f; private float invalidReticleMaxScale = 1.0f; private float invalidReticleMinScaleDistance = 0.4f; private float invalidReticleMaxScaleDistance = 2.0f; private Vector3 invalidReticleScale = Vector3.one; private Quaternion invalidReticleTargetRotation = Quaternion.identity;
private Transform playAreaPreviewTransform; private Transform[] playAreaPreviewCorners; private Transform[] playAreaPreviewSides;
private float loopingAudioMaxVolume = 0.0f;
private Coroutine hintCoroutine = null;
private bool originalHoverLockState = false; private Interactable originalHoveringInteractable = null; private AllowTeleportWhileAttachedToHand allowTeleportWhileAttached = null;
private Vector3 startingFeetOffset = Vector3.zero; private bool movedFeetFarEnough = false;
SteamVR_Events.Action chaperoneInfoInitializedAction;
//Events(立钻哥哥:事件) public static SteamVR_Events.Event<float> ChangeState = new SteamVR_Events.Event<float>(); public static SteamVR_Events.Action<float> ChangeSceneAction(UnityAction<float> action){}; public static SteamVR_Events.Event<TeleportMarkderBase> Player = new SteamVR_Events.Event<TeleportMarkerBase>(); public static SteamVR_Events.Action<TeleportMarkerBase> PlayerAction(UnityAction<TeleportMarkerBase> actionsss){} public static SteamVR_Events.Event<TeleportMarkerBase> PlayerPre = new SteamVR_Events.Event<TeleportMarkerBase>(); public static SteamVR_Events.Action<TeleportMarkerBase> PlayerPreAction(UnityAction<TeleportMarkerBase> action){}
private static Teleport _instance; public static Teleport instance{}
void Awake(){ _instance = this; chaperoneInfoInitializedAction = ChaperoneInfo.InitializedAction(OnChaperoneInfoInitialized);
pointerLineRenderer = GetComponentInChildren<LineRenderer>(); teleportPointerObject = pointerLineRenderer.gameObject;
int tintColorID = Shader.PropertyToID(“_TintColor”); fullTintAlpha = pointVisibleMaterial.GetColor(tintColorID).a;
teleportArc = GetComponent<TeleportArc>(); teleportArc.traceLayerMask = traceLayerMask;
loopingAudioMaxVolue = loopingAudioSource.volume;
playAreaPreviewCorner.SetActive(false); playAreaPreviewSide.SetActive(false);
float invalidReticleStartingScale = invalidReticleTransform.localScale.x; invalidReticleMinScale *= invalidReticleStartingScale; invalidReticleMaxScale *= invalidReticleStartingScale; } //立钻哥哥:void Awake(){}
void Start(){ teleportMarkers = GameObject.FindObjectsOfType<TeleportMarkerBase>(); HidePointer(); player = InteractionSystem.Player.instance;
if(player == null){ Debug.LogError(“立钻哥哥:[SteamVR Interaction] Teleport: No Player instance found in map.”); Destroy(this.gameObject); return; }
CheckForSpawnPoint(); Invoke(“ShowTeleportHint”, 5.0f); } //立钻哥哥:void Start(){}
void OnEnable(){ chaperoneInfoInitializedAction.enabled = true; OnChaperoneInfoInitialized(); }
void OnDisable(){ chaperoneInfoInitializedAction.enabled = false; HidePointer(); }
private void CheckForSpawnPoint(){} pubic void HideTeleportPointer(){} void Update(){} private void UpdatePointer(){} void FixedUpdate(){} private void OnChaperoneInfoInitialized(){} private void HidePointer(){} private void ShowPointer(Hand newPointerHand, Hand oldPointerHand){} private void UpdateTeleportColors(){} private void PlayAudioClip(AudioSource source, AudioClip clip){} private void PlayPointerHaptic(bool validLocation){} private void TryTeleportPlayer(){} private void InitiateTeleportFade(){} private void TeleportPlayer(){} private void HighlightSelected(TeleportMarkerBase hitTeleportMarker){} public void ShowTeleportHint(){} public void CancelTeleportHint(){} private IEnumerator TeleportHintCoroutine(){} public bool IsEligibleForTeleport(Hand hand){} private bool ShouldOverrideHoverLock(){} private bool WasTeleportButtonReleased(Hand hand){} private bool IsTeleportButtonDown(Hand hand){} private bool WasTeleportButtonPressed(Hand hand){} private Transform GetPointerStartTransform(Hand hand){} } //立钻哥哥:public class Teleport:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//Purpose: Displays the arc lines for teleporting and does the traces.(立钻哥哥:用途:显示用于远程传送的弧线并进行跟踪) using UnityEngine;
namespace Valve.VR.InteractionSystem{ public class TeleportArc : MonoBehaviour{ public int segmentCount = 60; public float thickness = 0.01f; public float arcDuration = 3.0f; public float segmentBreak = 0.025f; public float arcSpeed = 0.2f; public Material material;
[HideInInspector] public int traceLayerMask = 0;
private LineRenderer[] lineRenderers; private float arcTimeOffset = 0.0f; private float prevThickness = 0.0f; private int prevSegmentCount = 0; private bool showArc = true; private Vector3 startPos; private Vector3 projectileVelocity; private bool useGravity = true; private Transform arcObjectsTransform; private bool arcInvalid = false; private float scale = 1;
void Start(){} void Update(){} private void CreateLineRendererObjects(){} public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle){} public void Show(){} public void Hide(){} public bool DrawArc(out RaycastHit hitInfo){} private void DrawArcSegment(int index, float startTime, float endTime){} public void SetColor(Color color){} private float FindProjectileCollision(out RaycastHit hitInfo){} public Vector3 GetArcPositionAtTime(float time){} private void HideLineSegments(int startSegment, int endSegment){} } //立钻哥哥:public class TeleportArc:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
++++立钻哥哥:在前面我们剖析了“Teleporting”这个预制体,这个预制体处理系统的所有传送逻辑,是一个非常重要的预制体哟;那这个“TeleportPoint(传送点)”也非常关键,这里提供了传送点功能逻辑;
++++从“\Assets\SteamVR\InteractionSystem\Teleport\Prefabs\”下拖入这个预制体“TeleportPoint.prefab”到场景中,就可以生成一个传送点;
++++立钻哥哥:上面展示了“TeleportPoint(传送点)”的效果,还不错,没有什么大的问题,那我们就可以根据这个初步Demo,来展开我们的想象了,替换成我们想要的功能和UI!
//Purpose: Single location that the player can teleport to.(立钻哥哥:用途:单一的位置,玩家可以传送到.) using UnityEngine; using UnityEngine.UI; #if UNITY_EDITOR using UnityEditor; #endif
namespace Valve.VR.InteractionSystem{ public class TeleportPoint : TeleportMarkerBase{ public enum TeleportPointType{ MoveToLocation, SwitchToNewScene };
public TeleportPointType teleportType = TeleportPointType.MoveToLocation;
void Awake(){} void Start(){} void Update(){} } //立钻哥哥:public class TeleportPoint:TeleportMarkerBase{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportMarkerBase.cs //Purpose: Base class for all the objects that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的所有对象的基类.) using UnityEngine; namespace Valve.VR.InteractionSystem{ public abstract class TeleportMarkerBase : MonoBehaviour{ public bool locked = false; public bool markerActive = true;
public virtual bool showReticle{} public void SetLocked(bool locked){} public virtual void TeleportPlayer(Vector3 pointedAtPosition){} public abstract void UpdateVisuals(); public abstract void Highlight(bool highlight); public abstract void SetAlpha(float tintAlpha, float alphaPercent); public abstract bool ShouldActivate(Vector3 playerPosition); public abstract bool ShouldMovePlayer(); } //立钻哥哥:public abstract class TeleportMarkerBase:MonoBehaviour{} } //立钻哥哥:namespace Valve.VR.InteractionSystem{} |
//Purpose: Single location that the player can teleport to.(立钻哥哥:玩家可以传送到的单一位置) using UnityEngine; using UnityEngine.UI; #if UNITY_EDITOR using UnityEditor; #endif
namespace Valve.VR.InteractionSystem{ public class TeleportPoint : TeleportMarkerBase{ public enum TeleportPointType{ MoveToLocation, SwitchToNewScene };
public TeleportPointType teleportType = TeleportPointType.MoveToLocation; public string title; public string switchToScene; public Color titleVisibleColor; public Color titleHighlightedColor; public Color titleLockedColor; public bool playerSpawnPoint = false;
private bool gotReleventComponents = false; private MeshRenderer markerMesh; private MeshRenderer switchSceneIcon; private MeshRenderer moveLocationIcon; private MeshRenderer lockedIcon; private MeshRenderer pointIcon; private Transform lookAtJointTransform; private new Animation animation; private Text titleText; private Player player; private Vector3 lookAtPosition = Vector3.zero; private int tintColorID = 0; private Color tintColor = Color.clear; private Color titleColor = Color.clear; private float fullTitleAlpha = 0.0f;
private const string switchSceneAnimation = “switch_scenes_idle”; private const string moveLocationAnimation = “move_location_idle”; private const string lockedAnimation = “locked_idle”;
public override bool showReticle{}
void Awake(){ GetRelevantComponents(); animation = GetComponent<Animation>(); tintColorID = Shader.PropertyToID(“_TintColor”); moveLocationIcon.gameObject.SetActive(false); switchSceneIcon.gameObject.SetActive(false); lockedIcon.gameObject.SetActive(false);
UpdateVisuals(); }
void Start(){ player = Player.instance; }
void Update(){ if(Application.isPlaying){ lookAtPosition.x = player.hmdTransform.position.x; lookAtPosition.y = lookAtJointTransform.position.y; lookAtPosition.z = player.hmdTransform.position.z;
lookAtJointTransform.LookAt(lookAtPosition); } }
public override bool ShouldActivate(Vector3 playerPosition){ return (Vector3.Distance(transform.position, playerPosition) > 0.1f); }
public override bool ShouldMovePlayer(){ return true; }
public override void Highlight(bool highlight){} public override void UpdateVisuals(){}
public override void SetAlpha(float tintAlpha, float alphaPercent){ tintColor = markerMesh.material.GetColor(tintColorID); tintColor.a = tintAlpha;
markerMesh.material.SetColor(tintColorID, tintColor); switchSceneIcon.material.SetColor(tintColorID, tintColor); moveLocationIcon.material.SetColor(tintColorID, tintColor); lockedIcon.material.SetColor(tintColorID, tintColor);
titleColor.a = fullTitleAlpha * alphaPercent; titleText.color = titleColor; }
public void SetMeshMaterials(Material material, Color textColor){ markerMesh.material = material; switchSceneIcon.material = material; moveLocationIcon.material = material; lockedIcon.material = material;
titleColor = textColor; fullTitleAlpha = textColor.a; titleText.color = titleColor; }
public void TeleportToScene(){}
//立钻哥哥:这里就是代码的硬编码,如果需要调整资源或者功能,需要调整这里,作为框架来说,这个很挫的??!!估计后期SteamVR会更新这个功能的,我相信! //这里我们可以把这块功能做一个抽象隔离,或者继承改写都可以! public void GetRelevantComponents(){ markerMesh = transform.Find(“teleport_marker_mesh”).GetComponent<MeshRenderer>(); switchSceneIcon = transform.Find(“teleport_marker_lookat_joint/teleport_marker_icons/switch_scenes_icon”).GetComponent<MeshRenderer>(); moveLocationIcon = transform.Find(“teleport_marker_lookat_joint/teleport_marker_icons/move_location_icon”).GetComponent<MeshRenderer>; lockedIcon = transform.Find(“teleport_marker_lookat_joint/teleport_marker_icons/locked_icon”).GetComponent<MeshRenderer>(); lookAtJointTransform = transform.Find(“teleport_marker_lookat_joint”);
titleText = transform.Find(“teleport_marker_lookat_joint/teleport_marker_canvas/teleport_marker_canvas_text”);
gotReleventComponents = true; }
public void ReleaseRelevantComponents(){ markerMesh = null; switchSceneIcon = null; moveLocationIcon = null; lockedIcon = null; lookAtJointTransform = null; titleText = null; }
public void UpdateVisualsInEditor(){} } //立钻哥哥:public class TeleportPoint:TeleportMarkerBase{}
#if UNITY_EDITOE [CustomEditor(typeof(TeleportPoint))] public class TeleportPointEditor : Editor{ void OnEnable(){} public override void OnInspectorGUI(){} } //立钻哥哥:public class TeleportPointEditor:Editor{} #endif } //立钻哥哥:namesapce Valve.VR.InteractionSystem{} |
++++立钻哥哥:“TeleportArea(传送区域)”这是一个由网格组成的传送区;当传送到这些东西上时,玩家将会准确地传送到他们所指向的地方(加上地板固定);将此组件(TeleportArea)添加到任何带有碰撞体和网格渲染器的对象中,以允许玩家在其上传送;
//Purpose: An area that the player can teleport to.(立钻哥哥:用途:玩家可以传送到的区域.) using UnityEngine; #if UNITY_EDITOR using UnityEditor;
namespace Valve.VR.InteractionSystem{ public class TeleportArea : TeleportMarkerBase{ public Bounds meshBounds{}
private MeshRenderer areaMesh; private int tintColorId = 0; private Color visibleTintColor = Color.clear; private Color highlightedTintColor = Color.clear; private Color lockedTintColor = Color.clear; private bool highlighted = false;
public void Awake(){ areaMesh = GetComponent<MeshRenderer>(); tintColorId = Shader.PropertyToID(“_TintColor”); CalculateBounds(); }
public void Start(){ visibleTintColor = Teleport.instance.areaVisibleMaterial.GetColor(tintColorId); highlightedTintColor = Teleport.instance.areaHighlightedMaterial.GetColor(tintColorId); lockedTintColor = Teleport.instance.areaLockedMaterial.GetColor(tintColorId); }
public override bool ShouldActivate(Vector3 playerPosition){} public override bool ShouldMovePlayer(){} public override void Highlight(bool highlight){}
public override void SetAlpha(float tintAlpha, float alphaPercent){ Color tintedColor = GetTintColor(); tintedColor.a *= alphaPercent; areaMesh.material.SetColor(tintColorId, tintedColor); }
public override void UpdateVisuals(){} public void UpdateVisualsInEditor(){} private bool CalculateBounds(){} private Color GetTintColor(){} } //立钻哥哥:public class TeleportArea:TeleportMarkerBase{}
#if UNITY_EDITOR [CustomEditor(typeof(TeleportArea))] public class TeleportAreaEditor : Editor{ void OnEnable(){} public override void OnInspectorGUI(){} } //立钻哥哥:public class TeleportAreaEditor:Editor{} #endif } //立钻哥哥:namespace Valve.VR.InteractionSystem{}
|
|
++知识点01:TeleportMarkerBase ++++立钻哥哥:Purpose: Base class for all the objects that the player can teleport to.(用途:玩家可以传送到的所有对象的基类。)
++++\Assets\SteamVR\InteractionSystem\Teleport\Scripts\TeleportMarkerBase.cs
|
++立钻哥哥推荐的热门分类:
++++SteamVR:https://blog.csdn.net/vrunsoftyanlz/article/category/8582642
++++XR技术企业内训:https://blog.csdn.net/vrunsoftyanlz/article/category/8037810
++++5G+云计算+雾计算:https://blog.csdn.net/vrunsoftyanlz/article/category/8741272
++++框架编程:https://blog.csdn.net/vrunsoftyanlz/article/category/7570175
++++SteamVR2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187
++++SteamVR2.2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/88784527
++++SteamVR2.2.0快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579
++++SteamVR2.2.0交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778
++++SteamVR2.2.0传送机制:https://blog.csdn.net/VRunSoftYanlz/article/details/89390866
++++SteamVR2.2.0教程(一):https://blog.csdn.net/VRunSoftYanlz/article/details/89324067
++++SteamVR2.2.0教程(二):https://blog.csdn.net/VRunSoftYanlz/article/details/89894097
++++SteamVR实战之PMCore:https://blog.csdn.net/VRunSoftYanlz/article/details/89463658
【XR游戏开发QQ群:784477094】
++立钻哥哥推荐的拓展学习链接(Link_Url):
立钻哥哥推荐的拓展学习链接(Link_Url) |
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
++++虚拟现实VR资讯: https://blog.csdn.net/VRunSoftYanlz/article/details/89165846
++++HTC_VIVE开发基础:https://blog.csdn.net/VRunSoftYanlz/article/details/81989970
++++Oculus杂谈:https://blog.csdn.net/VRunSoftYanlz/article/details/82469850
++++Oculus安装使用:https://blog.csdn.net/VRunSoftYanlz/article/details/82718982
++++Unity+SteamVR=>VR:https://blog.csdn.net/VRunSoftYanlz/article/details/88809370
++++Unity减少VR晕眩症:https://blog.csdn.net/VRunSoftYanlz/article/details/89115518
++++SteamVR简介:https://blog.csdn.net/VRunSoftYanlz/article/details/86484254
++++SteamVR脚本功能分析:https://blog.csdn.net/VRunSoftYanlz/article/details/86531480
++++SteamVR2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/86618187
++++SteamVR2.2.0开发指南:https://blog.csdn.net/VRunSoftYanlz/article/details/88784527
++++SteamVR2.2.0快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/88833579
++++SteamVR2.2.0交互系统:https://blog.csdn.net/VRunSoftYanlz/article/details/89199778
++++SteamVR2.2.0传送机制:https://blog.csdn.net/VRunSoftYanlz/article/details/89390866
++++SteamVR2.2.0教程(一):https://blog.csdn.net/VRunSoftYanlz/article/details/89324067
++++SteamVR2.2.0教程(二):https://blog.csdn.net/VRunSoftYanlz/article/details/89894097
++++SteamVR实战之PMCore:https://blog.csdn.net/VRunSoftYanlz/article/details/89463658
++++SteamVR/Extras:https://blog.csdn.net/VRunSoftYanlz/article/details/86584108
++++SteamVR/Input:https://blog.csdn.net/VRunSoftYanlz/article/details/86601950
++++OpenXR简介:https://blog.csdn.net/VRunSoftYanlz/article/details/85726365
++++VRTK杂谈:https://blog.csdn.net/VRunSoftYanlz/article/details/82562993
++++VRTK快速入门(杂谈):https://blog.csdn.net/VRunSoftYanlz/article/details/82955267
++++VRTK官方示例(目录):https://blog.csdn.net/VRunSoftYanlz/article/details/82955410
++++VRTK代码结构(目录):https://blog.csdn.net/VRunSoftYanlz/article/details/82780085
++++VRTK(SceneResources):https://blog.csdn.net/VRunSoftYanlz/article/details/82795400
++++VRTK_ControllerEvents:https://blog.csdn.net/VRunSoftYanlz/article/details/83099512
++++VRTK_InteractTouch:https://blog.csdn.net/VRunSoftYanlz/article/details/83120220
++++虚拟现实行业应用:https://blog.csdn.net/VRunSoftYanlz/article/details/88360157
++++Steam平台上的VR:https://blog.csdn.net/VRunSoftYanlz/article/details/88960085
++++Steam平台热销VR:https://blog.csdn.net/VRunSoftYanlz/article/details/89007741
++++VR实验:以太网帧的构成:https://blog.csdn.net/VRunSoftYanlz/article/details/82598140
++++实验四:存储器扩展实验:https://blog.csdn.net/VRunSoftYanlz/article/details/87834434
++++FrameVR示例V0913:https://blog.csdn.net/VRunSoftYanlz/article/details/82808498
++++FrameVR示例V1003:https://blog.csdn.net/VRunSoftYanlz/article/details/83066516
++++SwitchMachineV1022:https://blog.csdn.net/VRunSoftYanlz/article/details/83280886
++++PlaySceneManagerV1022:https://blog.csdn.net/VRunSoftYanlz/article/details/83280886
++++Unity5.x用户手册:https://blog.csdn.net/VRunSoftYanlz/article/details/81712741
++++Unity面试题ABC:https://blog.csdn.net/vrunsoftyanlz/article/details/78630687
++++Unity面试题D:https://blog.csdn.net/VRunSoftYanlz/article/details/78630838
++++Unity面试题E:https://blog.csdn.net/vrunsoftyanlz/article/details/78630913
++++Unity面试题F:https://blog.csdn.net/VRunSoftYanlz/article/details/78630945
++++Cocos2dx面试题:https://blog.csdn.net/VRunSoftYanlz/article/details/78630967
++++禅道[zentao]:https://blog.csdn.net/VRunSoftYanlz/article/details/83964057
++++Lua快速入门篇(Xlua拓展):https://blog.csdn.net/VRunSoftYanlz/article/details/81173818
++++Lua快速入门篇(XLua教程):https://blog.csdn.net/VRunSoftYanlz/article/details/81141502
++++Lua快速入门篇(基础概述):https://blog.csdn.net/VRunSoftYanlz/article/details/81041359
++++框架知识点:https://blog.csdn.net/VRunSoftYanlz/article/details/80862879
++++游戏框架(UI框架夯实篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80781140
++++游戏框架(初探篇):https://blog.csdn.net/VRunSoftYanlz/article/details/80630325
++++.Net框架设计:https://blog.csdn.net/VRunSoftYanlz/article/details/87401225
++++从零开始学架构:https://blog.csdn.net/VRunSoftYanlz/article/details/88095895
++++设计模式简单整理:https://blog.csdn.net/vrunsoftyanlz/article/details/79839641
++++专题:设计模式(精华篇):https://blog.csdn.net/VRunSoftYanlz/article/details/81322678
++++U3D小项目参考:https://blog.csdn.net/vrunsoftyanlz/article/details/80141811
++++Unity小游戏算法分析:https://blog.csdn.net/VRunSoftYanlz/article/details/87908365
++++Unity案例(Vehicle):https://blog.csdn.net/VRunSoftYanlz/article/details/82355876
++++UML类图:https://blog.csdn.net/vrunsoftyanlz/article/details/80289461
++++PowerDesigner简介:https://blog.csdn.net/VRunSoftYanlz/article/details/86500084
++++Unity知识点0001:https://blog.csdn.net/vrunsoftyanlz/article/details/80302012
++++Unity知识点0008:https://blog.csdn.net/VRunSoftYanlz/article/details/81153606
++++U3D_Shader编程(第一篇:快速入门篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80372071
++++U3D_Shader编程(第二篇:基础夯实篇):https://blog.csdn.net/vrunsoftyanlz/article/details/80372628
++++Unity引擎基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78881685
++++Unity面向组件开发:https://blog.csdn.net/vrunsoftyanlz/article/details/78881752
++++Unity物理系统:https://blog.csdn.net/vrunsoftyanlz/article/details/78881879
++++Unity2D平台开发:https://blog.csdn.net/vrunsoftyanlz/article/details/78882034
++++UGUI基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78884693
++++UGUI进阶:https://blog.csdn.net/vrunsoftyanlz/article/details/78884882
++++UGUI综合:https://blog.csdn.net/vrunsoftyanlz/article/details/78885013
++++Unity动画系统基础:https://blog.csdn.net/vrunsoftyanlz/article/details/78886068
++++Unity动画系统进阶:https://blog.csdn.net/vrunsoftyanlz/article/details/78886198
++++Navigation导航系统:https://blog.csdn.net/vrunsoftyanlz/article/details/78886281
++++Unity特效渲染:https://blog.csdn.net/vrunsoftyanlz/article/details/78886403
++++Unity数据存储:https://blog.csdn.net/vrunsoftyanlz/article/details/79251273
++++Unity中Sqlite数据库:https://blog.csdn.net/vrunsoftyanlz/article/details/79254162
++++WWW类和协程:https://blog.csdn.net/vrunsoftyanlz/article/details/79254559
++++Unity网络:https://blog.csdn.net/vrunsoftyanlz/article/details/79254902
++++Unity资源加密:https://blog.csdn.net/VRunSoftYanlz/article/details/87644514
++++PhotonServer简介:https://blog.csdn.net/VRunSoftYanlz/article/details/86652770
++++编写Photon游戏服务器:https://blog.csdn.net/VRunSoftYanlz/article/details/86682935
++++C#事件:https://blog.csdn.net/vrunsoftyanlz/article/details/78631267
++++C#委托:https://blog.csdn.net/vrunsoftyanlz/article/details/78631183
++++C#集合:https://blog.csdn.net/vrunsoftyanlz/article/details/78631175
++++C#泛型:https://blog.csdn.net/vrunsoftyanlz/article/details/78631141
++++C#接口:https://blog.csdn.net/vrunsoftyanlz/article/details/78631122
++++C#静态类:https://blog.csdn.net/vrunsoftyanlz/article/details/78630979
++++C#中System.String类:https://blog.csdn.net/vrunsoftyanlz/article/details/78630945
++++C#数据类型:https://blog.csdn.net/vrunsoftyanlz/article/details/78630913
++++Unity3D默认的快捷键:https://blog.csdn.net/vrunsoftyanlz/article/details/78630838
++++游戏相关缩写:https://blog.csdn.net/vrunsoftyanlz/article/details/78630687
++++UnityAPI.Rigidbody刚体:https://blog.csdn.net/VRunSoftYanlz/article/details/81784053
++++UnityAPI.Material材质:https://blog.csdn.net/VRunSoftYanlz/article/details/81814303
++++UnityAPI.Android安卓:https://blog.csdn.net/VRunSoftYanlz/article/details/81843193
++++UnityAPI.AndroidJNI安卓JNI:https://blog.csdn.net/VRunSoftYanlz/article/details/81879345
++++UnityAPI.Transform变换:https://blog.csdn.net/VRunSoftYanlz/article/details/81916293
++++UnityAPI.WheelCollider轮碰撞器:https://blog.csdn.net/VRunSoftYanlz/article/details/82356217
++++UnityAPI.Resources资源:https://blog.csdn.net/VRunSoftYanlz/article/details/83155518
++++JSON数据结构:https://blog.csdn.net/VRunSoftYanlz/article/details/82026644
++++CocosStudio快速入门:https://blog.csdn.net/VRunSoftYanlz/article/details/82356839
++++Unity企业内训(目录):https://blog.csdn.net/VRunSoftYanlz/article/details/82634668
++++Unity企业内训(第1讲):https://blog.csdn.net/VRunSoftYanlz/article/details/82634733
++++Unity企业内训(第2讲):https://blog.csdn.net/VRunSoftYanlz/article/details/82861180
++++Unity企业内训(第3讲):https://blog.csdn.net/VRunSoftYanlz/article/details/82927699
++++Unity企业内训(第4讲):https://blog.csdn.net/VRunSoftYanlz/article/details/83479776
++++Unity企业内训(第5讲):https://blog.csdn.net/VRunSoftYanlz/article/details/83963811
++++Unity企业内训(第6讲):https://blog.csdn.net/VRunSoftYanlz/article/details/84207696
++++钻哥带您了解产品原型:https://blog.csdn.net/VRunSoftYanlz/article/details/87303828
++++插件
++++计算机组成原理(教材篇):https://blog.csdn.net/VRunSoftYanlz/article/details/82719129
++++5G接入:云计算和雾计算:https://blog.csdn.net/VRunSoftYanlz/article/details/88372718
++++云计算通俗讲义:https://blog.csdn.net/VRunSoftYanlz/article/details/88652803
++++立钻哥哥Unity 学习空间: http://blog.csdn.net/VRunSoftYanlz/
--_--VRunSoft:lovezuanzuan--_--