基于SteamVR_Unity_Toolkit自定义射线触发器简单结构

环境: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;
                    }
                }
            }
        }

你可能感兴趣的:(基于SteamVR_Unity_Toolkit自定义射线触发器简单结构)