文章目錄
HTCVIVE與設備連接
-
匯入SteamVR和VRTK
• 注意點選I made a back up/ Go ahead更新
• 對於匯入後報錯需要跳轉到 line 146: new Texture改爲new Texture2D(0,0) -
新建場景Pro1使用SteamVR/Prefabs/[CameraRig],同時刪除主攝影機
-
給[CameraRig]/Controller(Left)/Model和[CameraRig]/Controller(Right)/Model分別添加BoxCollider(isTrigger=True,Size=(0,0,0)))和Rigibody(useGravity=false)
-
場景中加入Cube,添加BoxCollider(isTrigger=T,rigibody(useGravity=F) ,設置Cube.Tag=(new)Object
-
[CameraRig]/Controller(Left)/Model和[CameraRig]/Controller(Right)/Model添加SteamVRController.cs,將Controller(Left)和Controller(Right)拖入Trackobj槽中
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SteamVRController : MonoBehaviour
{
[Header("VIVE手把控制器")]
public SteamVR_TrackedObject trackobj;
//當HTC VIVE 手把碰到物件
void OnTriggerStay(Collider hit)
{
var steam_state=SteamVR_Controller.Input((int)trackobj.index) ;
/* 更改ButtonMask.Grip/Trigger/System/Touchpad
*
*steam_state.GetPress(SteamVR_Controller.ButtonMask.Grip);
* steam_state.GetPress(SteamVR_Controller.ButtonMask.Trigger);
*steam_state.GetPress(SteamVR_Controller.ButtonMask.System);
*steam_state.GetPress(SteamVR_Controller.ButtonMask.Touchpad);
*GetPressDown;
*GetPressUp;
*if(steam_state.GetPress(SteamXR_Controller.ButtonMask.Grip))
*
*/
//持續按下HTC VIVE 手把上的Grip鍵
if(steam_state.GetPress(SteamVR_Controller.ButtonMask.Grip))
{
//如果手把碰到的物件標籤爲Object(如Cube物件)
if(hit.GetComponent<Collider>().tag=="Object")
{
//碰撞物的座標位置/角度=手把位置/角度
hit.transform.position=transform.position;
hit.transform.rotation=transform.rotation;
//手把先開機的爲左手把
//如果按下左手把Grip按鈕
if(trackobj.name=="Controller (left)")
{
print("Controller (left) Grip");
var deviceIndex=SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Leftmost);
//手把震動幅度0-3999,如果值小於100,基本上沒啥感覺
SteamVR_Controller.Input(deviceIndex).TriggerHapticPulse(3000);
}
else
{
print("Controller (right) Grip");
var deviceIndex=SteamVR_Controller.GetDeviceIndex(SteamVR_Controller.DeviceRelation.Rightmost);
//手把震動幅度0-3999,如果值小於100,基本上沒啥感覺
SteamVR_Controller.Input(deviceIndex).TriggerHapticPulse(3000);
}
}
}
}
}
實現手柄控制發射子彈功能
- 新建場景Pro2,使用SteamVR/Prefabs/[CameraRig],同時刪除主攝影機
- 在[CameraRig]/Controller(Left)/Model或[CameraRig]/Controller(Right)/Model下建立Sphere. 設置Rigibody.UseGravity=F;SphereCollider.IsTrigger=F
- 給[CameraRig]/Controller(Left)/Model或[CameraRig]/Controller(Right)/Model添加SteamVRFire.cs。將Sphere拖入Bullet槽,Controller(Left)或Controller(Right)拖入Trackobj槽。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SteamVRFire : MonoBehaviour
{
[Header("子彈物件")]
public GameObject Bullet;
//子彈移速
private float Speed=1000f;
//設定子彈銷燬時間
private float BulletLife=5f;
[Header("VIVE手把控制器")]
public SteamVR_TrackedObject trackobj;
void Start(){}
// Update is called once per frame
void Update()
{
var steam_state=SteamVR_Controller.Input((int)trackobj.index);
//如果按下滑鼠左鍵或HTC VIVE 手把Trigger按鍵
//if(Input.GetMouseButton(0)||steam_state.GetPress(SteamVR_Controller.ButtonMask.Trigger))//
if(Input.GetMouseButton(0)||steam_state.GetPressDown(SteamVR_Controller.ButtonMask.Trigger))
{
//動態生成一顆子彈(強制轉換)
GameObject BulletPrefab=Instantiate(Bullet,Bullet.transform.position,Bullet.transform.rotation) as GameObject;
//開啓動態生成的物件(子彈)
BulletPrefab.SetActive(true);
//抓取子彈的RigiBody屬性
Rigidbody rb=BulletPrefab.GetComponent<Rigidbody>();
//透過AddForce給子彈某一個方向力,讓物體繼續往前
rb.AddForce(BulletPrefab.transform.forward*Speed);
//子彈沒有達到任何東西的情況下就等待5秒刪除子彈
Destroy(BulletPrefab,BulletLife);
}
}
}
VRTK插件與UGUI的交互:Menu Scene製作
必備Game Object如下。Directional Light,Floor分別控制打光和場景的“地面”,這裏不再作具體說明。
[外鏈圖片轉存失敗(img-W6cQ1R6Q-1562839244125)(https://i.imgur.com/GoauE0Q.png)]
[VRTK_SDKManager]
為VR SDK提供支持。核心是SDKSetups,SDKSetupSwitcher將SDKSetups轉換為便於操作的GUI界面。
[VRTK_Scripts]
設定手柄等控制器與UGUI的交互。
這裏只賦予右手把(RightController)交互功能,需要添加的Component如下。
[外鏈圖片轉存失敗(img-GeoHCATK-1562839057544)(https://i.imgur.com/6k8KLym.png)]
VRTK_Controller Events
[外鏈圖片轉存失敗(img-mmwFUE6G-1562839057544)(https://i.imgur.com/bhiuPlB.png)]
details
VRTK_Pointer
Provides a basis of being able to emit a pointer from a specified GameObject.
[外鏈圖片轉存失敗(img-MIpJIiaD-1562839057545)(https://i.imgur.com/57miUrZ.png)]
VRTK_Straight Pointer Renderer
A visual pointer representation of a straight beam with an optional cursor at the end.
[外鏈圖片轉存失敗(img-Z9qILiV3-1562839057546)(https://i.imgur.com/piycVQW.png)]
details
記得更改設置
General Appearance Settings.Tracer Visibility = Always On;
General Appearance Settings.Cursor Visibility = Always On;
VRTK_UI Pointer
Provides the ability to interact with UICanvas elements and the contained Unity UI elements within.
[外鏈圖片轉存失敗(img-F4DIAIaF-1562839057547)(https://i.imgur.com/54S5Yb3.png)]
details
記得更改設置
Activation.Activation Mode = Always On;
[Canvas]
[外鏈圖片轉存失敗(img-AQxN2VMm-1562839057548)(https://i.imgur.com/uMd8RqO.png)]
- Canvas基礎設置
Canvas.RenderMode = WorldSpace; - 添加VRTK_UI Canvas
- 綁定Menu.cs控制程式
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Menu : MonoBehaviour
{
public void ToProj1()
{
Application.LoadLevel("Pro1");
}
public void ToProj2()
{
Application.LoadLevel("Pro2");
}
public void ToProj4()
{
Application.LoadLevel("Pro4");
}
}
- Button添加對應的OnClick()事件
[外鏈圖片轉存失敗(img-9PSDSA4w-1562839057549)(https://i.imgur.com/0stbZYS.png)]
[EventSystem]
Menu Scene製作步驟概括
- 新建保存一個Scene。
- 匯入[VRTK_SDKManager]預知
- 創建Empty Game Object作為Right Controller和Left Controller。
- 添加Canvas及其下的Button。
- 確保有EventSystem生成(若沒有從Scene/[SDKSetupManager]/SDKSetupSwitcher/EventSystem 中複製粘貼一個EventSystem到Scene/EventSystem並勾選Inspector的小方框使之有效)。
- 設置Canvas模式為World Space,並添加VRTK_UIPointer元件。
- 編寫menu.cs程式,並將之綁定在Canvas上,然後爲Button增添Click事件。
- 給Scene/LeftController添加VRTK_Controller Events。
- 給Scene/RighttController添加
- VRTK_Controller Events
- VRTK_UI Pointer:
.ActivationMode = Always On; - VRTK_Controller UI Pointer Events_Listener Example
- VRTK_Pointer
- VRTK_Straight Pointer Renderer:
.TracerVisibility = Always On;
.CursorVisibility = Always On;
- 在build setting中增添設計的場景並編譯
- 運行(調整button位置)。
加入VRTK的遊戲製作:模擬水果忍者
在Menu場景的基礎上修改:
[外鏈圖片轉存失敗(img-P0uRZJc3-1562839057550)(https://i.imgur.com/GoauE0Q.png)]
[VRTK_Scripts]不變,需要修改[VRTK_SDKManager],把遊戲結構加入到其中,即可:
[外鏈圖片轉存失敗(img-4QCy25hZ-1562839057551)(https://i.imgur.com/8WOgAOr.png)]
修改Canvas
- 刪除Button元件
- 去掉VRTK_UIPointer元件和menu.cs(用不上了)
- 設置Canvas模式為Screen Space (Camera)
- 在Canvas下添加三個Text,分別管理Score,Time和GAME OVER文字顯示
- 將Canvas拖至[VRTK_SDKManager]/SDKSetups/SteamVR/[CameraRig]/Camera(head)下
[外鏈圖片轉存失敗(img-KcVxnWmD-1562839057552)(https://i.imgur.com/R5u7lbG.png)]
設置Controller
- 製作左右手的武器(從asset找或用cube替代皆可)
- 分別添加帶Trigger的Box Collider和不帶Gravity的Rigibody
- 將武器分別拖至[VRTK_SDKManager]/SDKSetups/SteamVR/[CameraRig]/Controller(Left)和[VRTK_SDKManager]/SDKSetups/SteamVR/[CameraRig]/Controller(Right)下
[外鏈圖片轉存失敗(img-Ai3ElVeS-1562839057552)(https://i.imgur.com/e2SZN7P.png)]
製作遊戲
- 創建Empty Object命名爲GM,並賦其GM.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GM : MonoBehaviour
{
#region 倒計時
[Header("倒數時間的文字")]
public Text CountdownTimeText;
[Header("屬性面板中可調整整體遊戲的時間")]
public int Timer;
//程式中倒數計時
int ScriptTimer;
#endregion
#region 計分
[Header("計分文字")]
public Text ScoreText;
//計算總分數
int TotalScore;
#endregion
#region 產出物件
[Header("所有要產出的物件")]
public GameObject[] CreateObject;
[Header("物件產出的位置")]
public GameObject[] CreatePos;
#endregion
[Header("遊戲結束文字")]
public GameObject GameOverObj;
//判斷是否遊戲結束
bool isGameOver;
// Start is called before the first frame update
void Start()
{
//程式中的倒計時=屬性面板中調整的時間
ScriptTimer=Timer;
InvokeRepeating("CountdownTime",1f,1f);
InvokeRepeating("CreateObj",Random.Range(0.5f,1.5f),Random.Range(0.5f,1.5f));
}
// Update is called once per frame
void Update()
{
//判斷是否遊戲結束
if(isGameOver)
{
GameOverObj.SetActive(true);
}
else
{
GameOverObj.SetActive(false);
}
}
void CountdownTime()
{
ScriptTimer--;
ScriptTimer=Mathf.Clamp(ScriptTimer,0,Timer);
CountdownTimeText.text="Time: "+ScriptTimer+"s";
if(ScriptTimer<=0)
{
isGameOver=true;
}
}
public void totalScore(int AddScore)
{
TotalScore+=AddScore;
ScoreText.text="Score: "+TotalScore;
}
void CreateObj()
{
if(!isGameOver)
{
Instantiate(CreateObject[Random.Range(0,CreateObject.Length)],CreatePos[Random.Range(0,CreateObject.Length)].transform.position,transform.rotation);
}
}
}
- 將Canvas中的Text拖至GM設定中的對應槽中,隨便設置一個遊戲時間(30s爲例)
[外鏈圖片轉存失敗(img-RIkxxV47-1562839057553)(https://i.imgur.com/4sUReRp.png)] - 製作產出位置:新建Empty Object命名爲Game拖至Position,在該空物件下再新建空物件若干,分別調節各個空物件位置(空物件所處位置即爲產出位置)。
[外鏈圖片轉存失敗(img-csoAF19k-1562839057554)(https://i.imgur.com/tV810Bo.png)]
Note:可用Select Icon與其它遊戲物件作區分
- 將GamePosition拖至[VRTK_SDKManager]/SDKSetups/SteamVR下
- 指定GM中的產出位置數目,將GamePosition中的空物件拖至生成的對應槽中。
[外鏈圖片轉存失敗(img-QsP9wQhX-1562839057555)(https://i.imgur.com/q8YUCYx.png)] - 製作產出物件之水果:從3D農產品中拖出幾種水果,設置Tag=Food;添加帶Trigger的Sphere Collider和帶Gravity的Rigibody;同時賦其Object.cs;給水果的子物件分別添加不帶Trigger的Sphere Collider;完成後將物件製成Prefab保存後從場景中刪除。
Note: 水果的各個Collider尤其要注意範圍設置適當。
- 製作產出物件之炸彈:從3D Weapon中拖出幾種炸彈,設置Tag=NotFood;添加帶Trigger的Sphere Collider和帶Gravity的Rigibody;同時賦其Object.cs;完成後將物件製成Prefab保存後從場景中刪除。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Objects : MonoBehaviour
{
//往某個方向飛的力量值
float StartForce;
Rigidbody rigidbodyObject;// * 動態生成物件最好聲明爲私有
// Start is called before the first frame update
void Start()
{
//如果物件沒有被削到,過5s消失
Destroy(gameObject,5f);
//隨機生成一定範圍內的力量值
StartForce=Random.Range(7.5f,8.5f);
//抓取水果/炸彈物件身上的rigibody
rigidbodyObject = GetComponent<Rigidbody>();
//給帶有Rigibody的物件一個方向力
//Vector3.up;//世界座標y軸
//transform.up;//物件座標y軸
rigidbodyObject.AddForce(transform.up * StartForce,ForceMode.Impulse);
}
}
-
指定GM中的產出物件數目,將製作的產出物件預製物拖至生成的對應槽中。
[外鏈圖片轉存失敗(img-VnjOlGzS-1562839057556)(https://i.imgur.com/MGM6vl3.png)] -
完善特效預製:從Prefab中拖出效果預知,分別賦予DestroyObject.cs並指定效果持續時間(假設爲2s)後保存修改。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyObject : MonoBehaviour
{
public float DeletTime;
// Start is called before the first frame update
void Start()
{
Destroy(gameObject,DeletTime);
}
}
- 添加武器劈砍產出物件的效果:給之前製作的左右手武器賦予HitObject.cs,指定效果槽數爲2,Element0放置刀影效果,Element1放置爆炸效果。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HitObject : MonoBehaviour
{
//透過腳本抓取食物子物件
Transform[] FoodChildren;
//水果與爆炸物的特效 0:水果特效;1:爆炸特效
public GameObject[] EffectPrefab;
// Start is called before the first frame update
//void Start(){}
private void OnTriggerEnter(Collider hit)
{
//如果刀子碰到食物
if(hit.GetComponent<Collider>().tag=="Food")
{
//當刀子砍到水果,防止水果物件重新被觸發,將父物件Collider關閉
hit.GetComponent<Collider>().enabled=false;
//將父物件的Rigidbody屬性刪除
Destroy(hit.transform.GetComponent<Rigidbody>());
//找尋下一階層的子物件
FoodChildren=hit.GetComponentsInChildren<Transform>();
//給子階層物件Rigidbody
FoodChildren[2].gameObject.AddComponent<Rigidbody>();
FoodChildren[1].gameObject.AddComponent<Rigidbody>();
//開啓子階層物件Collider
FoodChildren[2].gameObject.GetComponent<Collider>().enabled=true;
FoodChildren[1].gameObject.GetComponent<Collider>().enabled=true;
//傳遞分數資訊給GM並顯示加250分
GameObject.Find("GM").GetComponent<GM>().totalScore(250);
//動態產生水果特效
Instantiate(EffectPrefab[0],hit.transform.position,hit.transform.rotation);
}
//如果刀子碰到爆炸物
if(hit.GetComponent<Collider>().tag=="NotFood")
{
//傳遞分數資訊給GM並顯示扣150分
GameObject.Find("GM").GetComponent<GM>().totalScore(-150);
//動態產生爆炸物特效
Instantiate(EffectPrefab[1],hit.transform.position,hit.transform.rotation);
//刪除爆炸物件
Destroy(hit.gameObject);
}
}
}
測試
- 將任一武器拖至Scene下後運行遊戲(Simulator模式下)通過拖動武器檢驗遊戲進行中的水果炸彈生成上拋,武器劈砍,水果切開,炸彈爆炸等效果。
- 暫停遊戲後開啓SteamVR關閉Simulator後繼續進行遊戲,觀察遊戲界面分數與時間的顯示,以及遊戲結束後“Game Over”字體的顯示。
參考設置圖片
[外鏈圖片轉存失敗(img-4aKYeDjF-1562839057557)(https://i.imgur.com/oiIzAsR.png)]
[外鏈圖片轉存失敗(img-QwGYDen7-1562839057558)(https://i.imgur.com/wpUvov1.png)]
[外鏈圖片轉存失敗(img-cBL7qMHH-1562839057560)(https://i.imgur.com/OU6IzpL.png)]
[外鏈圖片轉存失敗(img-DZNaXLgh-1562839057560)(https://i.imgur.com/U691syB.png)]
[外鏈圖片轉存失敗(img-Rd2N3USw-1562839057562)(https://i.imgur.com/R9qHCAH.png)]
[外鏈圖片轉存失敗(img-Hhtkv2na-1562839057563)(https://i.imgur.com/uytl1RS.png)]
[外鏈圖片轉存失敗(img-7EdOs8mE-1562839057564)(https://i.imgur.com/zvgtqiF.png)]
[外鏈圖片轉存失敗(img-4G1nNMXv-1562839057564)(https://i.imgur.com/PZRokx0.png)]
[外鏈圖片轉存失敗(img-N4qkXNyc-1562839057565)(https://i.imgur.com/q3KXImH.png)]
[外鏈圖片轉存失敗(img-J7xy38Fs-1562839057566)(https://i.imgur.com/26m8Pib.png)]
[外鏈圖片轉存失敗(img-B3KReZLR-1562839057568)(https://i.imgur.com/qADuEVE.png)]
[外鏈圖片轉存失敗(img-2BU4tWe3-1562839057568)(https://i.imgur.com/JunbrGl.png)]
[外鏈圖片轉存失敗(img-drHL8Eu6-1562839057569)(https://i.imgur.com/0xxjk3x.png)]
[外鏈圖片轉存失敗(img-JeQP7oMn-1562839057570)(https://i.imgur.com/i4U8U2n.png)]
[外鏈圖片轉存失敗(img-LtHrid4Q-1562839057570)(https://i.imgur.com/HYxGEN8.png)]