此文章用于自己学习过程中的记录,以便日后翻阅
开发HTC VIVE 首先需要下载Steam 平台,然后在Steam的商店里搜索Steam VR下载安装就可以了。
创建新的Unity项目
创建一个新的Unity工程
下载Steam VR插件
打开unity的 Asset Store
在Unity中的商店里搜索Steam vr插件
下载完成后点击Import按钮
将下载好的Steam VR插件全部导入到新的Unity工程中
导入中会有绿色的读条,如果导入完成后弹出API Update Required,这是在提示你API更新,可以不用管他,点击No Thanks即可。(原因应该是Steam VR 插件的版本不是最新的)
等待SteamVr_Settings弹出后点击Accept All。到这里导入就完成了
实现对手柄的控制
打开SteamVR_LaserPointer,在这里实现对激光笔的控制功能,首先把SteamVR_LaserPointer
Ctrl+d 复制一份,然后再该脚本的基础上进行修改
新建一个文件夹命名为Script,把SteamVR_LaserPointer脚本重命名为LaserPointer,然后拖入新建的Script文件夹中
进入LaserPointer脚本,然后修改类名为LaserPointer
删除掉选中的蓝色部分,然后保存
制作激光笔选中的目标点
在void Update 找到代码判断的语句进行扩充,并执行Hit判断,把Hit到的点存到刚刚创建的HitPoint变量中
在SteamVr文件夹中找到Prefabs文件夹然后把CameraRig放到场景中去
在场景中用Cube搭建一个简单的房间,然后把CameraRig的位置进行调整
展开CameraRig,选择Controller(left)对左手的手柄进行控制操作
给Controller(left)添加修改的Laser Point 赋予给CameraRig和SteamVR_TrackedController
然后去掉TrackSteamVR_Tracked Object
到了这一步,如果你的HTC VIVE设备调试正确,那就能在Unity的场景中看到他们了。
创建传送的脚本
创建Teleport
复制脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Teleport : MonoBehaviour {
//手柄的引用
public GameObject Left;
//储存一些变量
LaserPointer LP_Left;
SteamVR_TrackedController ST_Left;
Transform CurrentTransform;
// Use this for initialization
void Start () {
//初始化变量 注册监听 获取激光笔和控制器
LP_Left = Left.GetComponent<LaserPointer>();
ST_Left = Left.GetComponent<SteamVR_TrackedController>();
LP_Left.PointerIn += LeftPointIn;//手柄指向事件
LP_Left.PointerOut += LeftPointOut;//手柄取消事件
ST_Left.TriggerClicked += TriggerClicked;//手柄扳机事件
}
//手柄有物体指向
void LeftPointIn(object sender,PointerEventArgs e)
{//当有物体指向 设置变量标识
CurrentTransform = e.target;
}
//取消指向
void LeftPointOut(object sender,PointerEventArgs e)
{
//取消指向事件 变量标识设置为空
CurrentTransform = null;
}
void TriggerClicked(object sender,ClickedEventArgs e)
{//当指向不为空的时候,进行移动
if (CurrentTransform != null)
{
TeleportPosition(LP_Left.HitPoint);
}
}
//移动的方法
private void TeleportPosition(Vector3 targetPosition)
{
this.gameObject.transform.position = new Vector3(targetPosition.x - Left.transform.localPosition.x, targetPosition.y, targetPosition.z - Left.transform.localPosition.z);
}
// Update is called once per frame
void Update () {
}
}
赋予Teleport脚本给CameraRig组件,然后把Controller(left)赋值到Left
到这一步就完成了传送功能
实现多场景加载
创建一个新的Check脚本用来检测
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Check : MonoBehaviour {
//检测 条件完成 达到时 隐藏
public GameObject _Object;
// 加载场景名字
public string SceneName;
//异步加载控制器
AsyncOperation _AsyncOperation;
private void OnTriggerEnter(Collider other)
{
//当检测到碰撞时 检查碰撞物体是不是主相机 如果是进行场景加载 对__AsyncOperation赋值 进行标记
if (other.tag == "MainCamera" && _AsyncOperation == null)
{
_AsyncOperation = SceneManager.LoadSceneAsync(SceneName, LoadSceneMode.Additive);
}
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void FixedUpdate () {
//通过_AsyncOperation.isDone 来检测场景是否加载完成 如果加载完成 就隐藏特殊物体 来展现新的场景 同时避免再度触发碰撞进行场景加载
if (_AsyncOperation!=null && _AsyncOperation.isDone)
{
_AsyncOperation = null;
_Object.SetActive(false);
}
}
}
把Check 赋予给一面墙(创建一个CUBE拉成一面墙的样子,既点击墙面之后跳转的场景),然后对这个墙壁添加BoxCollider组件,BoxCollider组件大小为包裹住墙壁。然后勾选IsTrigger(勾上代表触发器)
在CameraRig上的Camera(eye)上添加BoxCollider 组件,同意勾选上IsTrigger 选项
然后添加Rigidbody组件取消勾选UseGravity
创建场景管理
创建一个新的脚本 Manager 用来管理你的场景
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Manager : MonoBehaviour {
public static Manager Instance;
Check CurrentCheck;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Debug.LogError("不能重复创建Manager");
}
}
public void StartNewScene(Check _Check)
{
//检测当前是否有场景加载 如果没有将调用对象设置为currentCheck
if (CurrentCheck == null)
{
CurrentCheck = _Check;
}else if (CurrentCheck != _Check)//如果有 就调用CurrentCheck.Reset方法重置 并且更新CurrentCheck调用
{
CurrentCheck.Reset();
CurrentCheck = _Check;
}
}
}
回到Check脚本,添加两行新的代码
然后在Check脚本中添加Reset方法
回到Unity里创建一个GameObject,然后把它的位置Reset,重命名为Manager,然后把Manager脚本挂上去
现在不会两个场景一起显示了,只会显示其中一个
到这里就完成了场景卸载的功能
制作不可传送区域
需要对传送进行限制,例如不能传送到界外,或者不能传送到屋顶或者水里了
例如把水面设置为不可传送区域,在搜索栏中搜索命名为water的所有模型(前提是你的模型的名字为water,如果是别的就搜索你模型的名字)
然后把Layer层的Default全部设置为Ignore Raycast
到这里就无法选择水面进行移动了。但是还没有明显的禁止移动提示。
接下来需要把禁止移动的提示制作的更明显
打开LaserPoint脚本进行编辑,需要先添加一个Material 来控制射线的颜色
因为上面定义了新的Material ,所以把下面的删掉
在指向判断这里添加新的更改,把可以只想设置为绿色,否则设置为红色
到这里就完成了点击不可传送地区射线变红的功能
制作抛物线---把激光笔的直线更改为抛物线
创建一个新的脚本parabola
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parabola : MonoBehaviour {
//发射器位置
public Transform ShootTransform;
//起点
public Vector3 StartPosition;
//终点
public Vector3 EndPosition;
//重力加速度
public float GravitationalAcceleration = 10;
//绘制节点数量
public int LineNodeNum = 10;
//绘制抛物线
public LineRenderer Line;
Vector3[] Position;
// Use this for initialization
void Start () {
//初始化线段绘制节点
Position = new Vector3[LineNodeNum];
//设置定点数量
Line.SetVertexCount(LineNodeNum);
}
Vector3 GetPlaneVector(Vector3 v3)
{
return new Vector3(v3.x, 0, v3.z);
}
// Update is called once per frame
void FixedUpdate () {
//更新发射点的位置(曲线)
ShootTransform.position = this.transform.position;
ShootTransform.rotation = Quaternion.Euler(this.transform.rotation.eulerAngles.x - 30, this.transform.rotation.eulerAngles.y, 0);
//当结束点为0但没有结束点的时候 将线段恢复为直线
if (EndPosition == Vector3.zero)
{
ResetLine();
return;
}
StartPosition = ShootTransform.position;
//计算出水平和垂直上的位移
float Sx = Vector3.Distance(GetPlaneVector(EndPosition), GetPlaneVector(StartPosition));
float Sy = StartPosition.y - EndPosition.y;
//计算出垂直方向和水平方向上的初始速度比值
float tanA = -ShootTransform.forward.y / Vector3.Distance(Vector3.zero, GetPlaneVector(ShootTransform.forward));
//计算运动时间
float t = Mathf.Sqrt((2 * Sy - 2 * Sx * tanA) / GravitationalAcceleration);
if(float.IsNaN(t))
{
ResetLine();
return;
}
//推导出水平和垂直的初速度
float Vx = Sx / t;
float Vy = Vx * tanA;
//绘制出线段
float FirstLineNodeTime = t / LineNodeNum;
Position[8] = StartPosition;
for (int i = 1; i < LineNodeNum; i++)
{
float xz = GetX(Vx, FirstLineNodeTime * (i + 1));
float y = GetY(FirstLineNodeTime * (i + 1), Vy);
Position[i] = Vector3.Normalize(GetPlaneVector(ShootTransform.forward)) * xz + Vector3.down * y + ShootTransform.position;
}
Line.SetPositions(Position);
}
/// <summary>
/// 计算水平方向的位移
/// </summary>
/// <param name="Speed">水平方向初速度</param>
/// <param name="time">时间</param>
/// <returns></returns>
private float GetX(float Speed,float time)
{
float X = Speed * time;
return X;
}
/// <summary>
/// 计算垂直方向的位移
/// </summary>
/// <param name="time">时间</param>
/// <param name="SpeedDownFloat">垂直方向的初速度</param>
/// <returns></returns>
private float GetY(float time,float SpeedDownFloat)
{
float Y = (float)(SpeedDownFloat * time + 0.5 * GravitationalAcceleration * time * time);
return Y;
}
void ResetLine()
{
for (int i = 0; i < LineNodeNum; i++)
{
Position[i] = transform.forward * i + transform.position;
Line.SetPositions(Position);
}
}
}
回到LaserPointer脚本里去抛物线的处理
创建一个GameObject命名为Shooter,再创建一个命名为ShootLine
对ShootLine添加Line Renderer组件,然后创建一个材质球赋予它(颜色随意)
找到Controller (left)添加刚刚写好的抛物线脚本,然后把刚刚的Shooter、ShootLine指定过来
可以增加LineNodeNum的节点数让抛物线更平滑
到这里就实现了抛物线
转载自原文链接, 如需删除请联系管理员。
原文链接:HTC VIVE 基础开发1,转载请注明来源!