环境:HtcVive,Unity,C#,商店的SteamVR_Unity_Toolkit插件
目前htc交互比较主流的还是那个实体射线交互,工具包自带的三种:
GetComponent().DestinationMarkerEnter
GetComponent().DestinationMarkerExit
GetComponent().DestinationMarkerSet
工具包自带的三种交互使用起来不太灵活,自己在VRTK_SimplePointer基础上拓展了一点功能,这里提供一个简单的例子:
废话不多说直接上:
///
/// 这是M,不多说
///
public class Msg_PointTrigger
{
public const string PointEnterMsg = "EnterTrigger";
public const string PointStayDownMsg = "PointStayDownMsg";
public const string PointStayUpMsg = "PointStayUPMsg";
public const string PointExittMsg = "ExittMsg";
/*
* 这里只做了4种,后期可以跟进
*/
}
1、这是Base模版,大概思路是,触发后根据消息解析做出相应处理,还是比较灵活的。
public class SteamVR_PointTriggerBase : MonoBehaviour {
//左右手柄输入器
public SteamVR_TrackedObject rightTracket;
public SteamVR_TrackedObject leftTracket;
//左右射线头位置
public Transform rightPoint;
public Transform leftPoint;
protected string msg;
///
/// 有响应
///
///
public virtual void Trigger(string msg)
{
this.msg = msg;
ExplainMSg();
}
private void ExplainMSg()
{
switch (msg)
{
case Msg_PointTrigger.PointEnterMsg :
OnPointEnter();
break;
case Msg_PointTrigger.PointStayDownMsg:
OnPointStayDown();
break;
case Msg_PointTrigger.PointStayUpMsg:
OnPointStayUp();
break;
case Msg_PointTrigger.PointExittMsg:
OnExitState();
break;
default:
break;
}
}
///
/// 射线按下进入
///
protected virtual void OnPointEnter() { Debug.Log("OnPointEnter"); }
///
/// 射线按下且在物体上
///
protected virtual void OnPointStayDown()
{
//以下时我目前根据项目加新增的,后期可以独立出来
EffectHighting.AddConstantHighting(gameObject);
if (null!=rightTracket)
{
SteamVR_Controller.Device rightDevice = SteamVR_Controller.Input((int)rightTracket.index);
if (rightDevice.GetTouch(SteamVR_Controller.ButtonMask.Trigger))
{
Debug.Log("右手Triger按下");
OnPointStayDownRightTriggerTouch();
}
}
if (null!=leftTracket)
{
SteamVR_Controller.Device leftDevice = SteamVR_Controller.Input((int)leftTracket.index);
if (leftDevice.GetTouch(SteamVR_Controller.ButtonMask.Trigger))
{
Debug.Log("左手Triger按下");
OnPointStayDownLeftTriggerTouch();
}
}
}
//这俩是临时加的为:当进入时左右手钩住扳机
protected virtual void OnPointStayDownRightTriggerTouch() { }
protected virtual void OnPointStayDownLeftTriggerTouch() { }
//当射线在物体上时弹起发射线按钮
protected virtual void OnPointStayUp() { Debug.Log("OnPointStayUp"); }
//退出
protected virtual void OnExitState() {EffectHighting.ResetRemoveHightingEffect();Debug.Log("OnExitState"); }
2、使用的例子:
如我写的一个控制灯的开关的功能,只需要利用其中一种就可以了:
public class SteamVR_PointTriggerLights : SteamVR_PointTriggerBase
{
public bool isOn = false;
//变色
public void TrunColor(Color openColor, Color closeColor)
{
if (isOn)
{
gameObject.GetComponent().material.color = openColor;
}
else
{
gameObject.GetComponent().material.color = closeColor; ;
}
}
//开关灯
private void TurnLights(bool isOn)
{
PointLightControler.instance.TurnLights(isOn);
}
protected override void OnPointEnter()
{
base.OnPointEnter();
}
protected override void OnPointStayDown()
{
base.OnPointStayDown();
}
protected override void OnPointStayDownRightTriggerTouch()
{
base.OnPointStayDownRightTriggerTouch();
}
protected override void OnPointStayDownLeftTriggerTouch()
{
base.OnPointStayDownLeftTriggerTouch();
}
//只个只用到了一种回调:当射线进入并在内部弹起后响应
protected override void OnPointStayUp()
{
base.OnPointStayUp();
isOn = !isOn;
TrunColor(Color.green, Color.red);
TurnLights(isOn);
Debug.Log("OnPointStayUp");
}
protected override void OnExitState()
{
base.OnExitState();
}
}
3、下面是改写的VRTK_SimplePointer,临时改的,还没有优化过,后期可以补上,思路就是利用射线检测判断一些情况的逻辑,主要是改了Update方法,附上参考一下
protected override void Update()
{
base.Update();
if (pointer.gameObject.activeSelf)
{
RaycastHit pointerCollidedWith;
Ray pointerRaycast = new Ray(transform.position, transform.forward);
var rayHit = Physics.Raycast(pointerRaycast, out pointerCollidedWith, pointerLength, ~layersToIgnore);
var pointerBeamLength = GetPointerBeamLength(rayHit, pointerCollidedWith);
SetPointerTransform(pointerBeamLength, pointerThickness);
//增加射线触发事件
//是否检测到物体
if (null!=pointerCollidedWith.collider)
{
selectObj = pointerCollidedWith.collider.gameObject;
}
else
{
/*
* -------------NO1
* 按下射线移出物体
*/
if (null!=selectObj)
{
if (null != selectObj.GetComponent())
{
selectObj.GetComponent().Trigger(Msg_PointTrigger.PointExittMsg);
}
}
selectObj = null;
canEnter = true;
}
//当检检测到物体时
if (null != selectObj)
{
//物体是VR交互物体
if (null != selectObj.GetComponent())
{
/*
* --------------NO2
* 射线按下Enter事件
*/
if (canEnter)
{
canEnter = false;
if (transform.root.GetComponent().right.activeSelf)
{
selectObj.GetComponent().rightTracket = transform.root.GetComponent().right.GetComponent();
selectObj.GetComponent().rightPoint = pointerTip.transform;
//Debug.Log(pointerTip.transform.position);
}
if (transform.root.GetComponent().left.activeSelf)
{
selectObj.GetComponent().leftTracket = transform.root.GetComponent().left.GetComponent();
selectObj.GetComponent().leftPoint = pointerTip.transform;
}
selectObj.GetComponent().Trigger(Msg_PointTrigger.PointEnterMsg);
}
/*
* ------------NO3
* 射线按下Stay事件
*/
selectObj.GetComponent().Trigger(Msg_PointTrigger.PointStayDownMsg);
}
}
}
else
{
if (null != selectObj)
{
if (null != selectObj.GetComponent())
{
/*
* --------------------------NO4
* 当射线在检测物体内,弹按钮回掉
*/
selectObj.GetComponent().Trigger(Msg_PointTrigger.PointStayUpMsg);
selectObj.GetComponent().Trigger(Msg_PointTrigger.PointExittMsg);
selectObj = null;
}
}
}
}