SteamVR:Easy Vive(二)抛物线移动

来源:互联网 发布:淘宝美工都用什么软件 编辑:程序博客网 时间:2024/05/15 09:27
SteamVR 抛物线移动
其实实现抛物线很简单,生成一组抛物点,然后将点渲染成线就好。渲染成线有很多方式,你可以用模型,也可以用GL的绘制线段,也可以用LineRender。重点是优化点的生成计算。
楼主上班比较忙,很少写demo。我做项目一般有严密的框架,但是为了更加简明的为大家展示功能的实现剔除了很多代码,并且写了不符合我风格的代码,就是为了让大家能看清楚功能的实现。
我不是个人开发者,家中无测试环境,如果有问题可以在下面回复。本教程中的代码已经用在实际的案例上,因为工作保密我不能截图或者共享项目源码,只是把开发过程的部分代码功能以个人的名义分享,欢迎交流。
如何生成抛物点,一个很简单的公式:
nextPos = lastPos + 水平位移 垂直位移。
 
稍后的代码有详尽的注释我就不多赘述了。
重点是对点集的优化,优化抛物点分两个部分,一是如何计算碰撞点,二是内存开销的优化。考虑到一般的VR项目只在水平面上进行移动,所以通过判断抛物点的y轴来判定碰撞。关于内存开销,我们可以限定生成的抛物点个数,同时优化计算。我们使用一个List来保存点集,动态的根据点的情况来生成点,或者改变点的位置。例如当手柄角度不变时,只需要将List集合中的点改变Y轴就行了。
现在思路已经明了了。以下是伪代码:
int i = 0;
while( nextPos.y>0 && maxPoint>0 ){
if(list.count<=i){
list.add(nextPos);
}
else{
list = nextPos;
}
///生成,优化,计算下一个抛物点
i++;
}
list.remove(i,list.count-i);//移除上一个点集的多余数据
生成抛物线点集后,接下来就是绘制曲线,LineRenderGL都可以很方便的绘制。但是就性能来说,GL更加快一点。建议大家用GL。当然大家也可以使用自己的模型绘制,原理就是,在对应的点生成你的模型,然后计算对应的角度即可。这几种实现方案我都会写到代码中,效果大家自己调用查看。
最后就是生成抛物线的终点,因为我是按照y轴来判断抛物线的落点,但是落点可能有障碍物等等,或者落点在墙角,这些位置显然是不能跳跃的,所以我们需要对落点进行判断。在Physics中有一个方法可以检测一个球形范围是否会碰撞,我们可以给地面添加一个层,以便忽略地面的检测,这样就可以安全的着陆了。
好了,也许你没听懂,没关系,接下来就是代码,代码中也有详尽的注释。

[C#] 纯文本查看 复制代码
?
 
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
usingUnityEngine;
usingSystem.Collections.Generic;
usingSystem;
 
/// <summary>
/// 抛物线脚本
/// </summary>
publicclass HandRay : MonoBehaviour
{
 
    privateTransform CurrentHand; //当前触发的手
    privateList<Vector3> pointList; //曲线点集合
    privateQuaternion lastRotation; //上一个移动的角度
    privateVector3 lastPostion; //上一个位置
    privateVector3 lastPos; //上一个点,为了优化将一个临时变量做成全局的,节省内存开销
    privateVector3 nextPos;//下一个点,理由同上
    privateevent Action OnChangeTransform;//一个事件,用来检测手柄位置和角度变化的
    privateMaterial material;//渲染射线的材质球
    privateVector3 HitPoint;//抛物线的碰撞点
    privateRay ray;
    privatebool canJump = false;//
 
    publicGameObject PointEffect;//一个特效,就是在射线的终点放置一个光柱什么的,大家可以自己做这个特效
 
    publicint MaxPoint;  //生成曲线的点最大数量
    publicfloat Distence;//水平位移
    publicfloat Grity;//垂直位移
    publicfloat CheckRange;//检测位置是否存在障碍物
 
    publicvoid Awake()
    {
        SetData();
    }
 
    publicvoid Start()
    {
        pointList = newList<Vector3>();
        OnChangeTransform += OnChangeTransformCallBack;
        HitPoint = -Vector3.one;
        ray = newRay();
 
 
    }
    publicvoid Update()
    {
        //当手柄按下触摸键同时角度合适时触发事件开始计算点
        if(CurrentHand != null&& ((CurrentHand.eulerAngles.x > 275 && CurrentHand.eulerAngles.x <= 360) || (CurrentHand.eulerAngles.x >= -0.01f && CurrentHand.eulerAngles.x < 85)))
        {
            if(OnChangeTransform != null) OnChangeTransform();
        }
        else
        {
            pointList.Clear();
            PointEffect.SetActive(false);
        }
    }
    /// <summary>
    /// 计算抛物线的点
    /// 此方法已经优化过性能
    ///
    /// </summary>
    privatevoid OnChangeTransformCallBack()
    {
        if(lastRotation != CurrentHand.rotation || lastPostion != CurrentHand.position)
        {
            lastPos = nextPos = CurrentHand.position;
            inti = 0;
            while(nextPos.y > 0 && (i < MaxPoint))
            {
                if(pointList.Count <= i)
                {
                    pointList.Add(nextPos);
                }
                else
                {
                    pointList[i] = nextPos;
                }
                if(lastRotation == CurrentHand.rotation && lastPostion != CurrentHand.position && i < pointList.Count - 1)
                {
                    nextPos = pointList[i + 1] + CurrentHand.position - lastPostion;
                }
                else
                {
                    nextPos = lastPos + CurrentHand.rotation * Vector3.forward * Distence + Vector3.up * Grity * 0.1f * i * Time.fixedDeltaTime;
                }
                lastPos = nextPos;
                i++;
            }
            if(pointList.Count > i)
            {
                pointList.RemoveRange(i, pointList.Count - i);
            }
            lastRotation = CurrentHand.rotation;
            lastPostion = CurrentHand.position;
            if(pointList.Count > 1)
            {
                HitPoint = pointList[pointList.Count - 1];
                PointEffect.SetActive(true);
                PointEffect.transform.position = HitPoint;
            }
            else
            {
                HitPoint = -Vector3.one;
                PointEffect.SetActive(false);
            }
        }
    }
 
    publicvoid Enable()
    {
        SteamVR_InitManager.Instance.OnLeftDeviceActive += OnHandActive;
        SteamVR_InitManager.Instance.OnRightDeviceActive += OnHandActive;
        OnChangeTransform += OnChangeTransformCallBack;
    }
    publicvoid OnHandActive(SteamVR_TrackedObject obj)
    {
        DeviceInput device = obj.GetComponent<DeviceInput>();
        device.OnPressDownPadV3 += OnPressDownPad;
        device.OnPressUpPad += OnPressUpPadAction;
    }
 
    publicvoid OnHandDis(SteamVR_TrackedObject obj)
    {
        if(obj && obj.gameObject.activeSelf)
        {
            DeviceInput device = obj.GetComponent<DeviceInput>();
            device.OnPressDownPadV3 -= OnPressDownPad;
            device.OnPressUpPad -= OnPressUpPadAction;
        }
    }
 
    publicvoid Disable()
    {
        SteamVR_InitManager.Instance.OnLeftDeviceActive -= OnHandActive;
        SteamVR_InitManager.Instance.OnRightDeviceActive -= OnHandActive;
        OnHandDis(SteamVR_InitManager.Instance.LeftObject);
        OnHandDis(SteamVR_InitManager.Instance.LeftObject);
        OnChangeTransform -= OnChangeTransformCallBack;
    }
 
    publicvoid SetData()
    {
        if(PointEffect)
            PointEffect.SetActive(false);
    }
 
    /// <summary>
    /// 抬起触摸板时,计算落脚点
    /// </summary>
    privatevoid OnPressUpPadAction()
    {
        if(CurrentHand == null)return;
        canJump = true;
        ray.origin = CurrentHand.position;
        Vector3 dir = HitPoint - CurrentHand.position;
        ray.direction = dir;
        if(Physics.CheckSphere(HitPoint, CheckRange, ~(1 << 8)))
        {
            canJump = false;
        }
        if(canJump)
        {
            JumpPoint(HitPoint);
        }
        CurrentHand = null;
    }
    /// <summary>
    /// 跳到指定的点
    /// </summary>
    /// <param name="point"></param>
    publicvoid JumpPoint(Vector3 point)
    {
        point.y = transform.position.y;
        transform.position = point;
    }
 
    privatevoid OnPressDownPad(Transform parent)
    {
 
        CurrentHand = parent;
 
    }
 
    /// <summary>
    /// 使用GL来绘制曲线
    /// 将点绘制出来
    /// </summary>
    voidOnRenderObject()
    {
        material.SetPass(0);
        if(pointList == null)return;
        GL.Begin(GL.LINES);
        for(inti = 0; i < pointList.Count; i++)
        {
            GL.Vertex(pointList[i]);
        }
        GL.End();
    }
 
    /// <summary>
    /// 一个额外的附加方法,即用一个曲线来绘制抛物线,性能较低,因为点数比较多
    /// 感兴趣的可以把此方法添加到Update中更新
    /// </summary>
 
    publicvoid ShowLineByRender()
    {
 
        LineRenderer line = GetComponent<LineRenderer>();
        if(line)
        {
            line.SetVertexCount(pointList.Count);
            for(inti = 0; i < pointList.Count; i++)
            {
                line.SetPosition(i, pointList[i]);
            }
        }
    }
}
下一章主要接受手柄和物体的交互事件代码,通过事件系统把射线和触碰进行封装的一个架构也是Htc Vive开发的最后一章。基本上
Vive开发相关的东西也就是这些了,其他的只要按照正常的逻辑去写,然后通过监听对应的手柄事件来调用你的代码就好,不再为外部
设备问题而烦恼。
对了,没图好像不让发……容我偷几张图。
 
0 0