版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.02.14 星期四 |
前言
Unity是由Unity Technologies開發(fā)的一個讓玩家輕松創(chuàng)建諸如三維視頻游戲奠伪、建筑可視化拷淘、實時三維動畫等類型互動內(nèi)容的多平臺的綜合型游戲開發(fā)工具止邮,是一個全面整合的專業(yè)游戲引擎滓窍。Unity類似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的圖型化開發(fā)環(huán)境為首要方式的軟件骄崩。其編輯器運行在Windows 和Mac OS X下绍载,可發(fā)布游戲至Windows校哎、Mac两波、Wii瞳步、iPhone、WebGL(需要HTML5)腰奋、Windows phone 8和Android平臺单起。也可以利用Unity web player插件發(fā)布網(wǎng)頁游戲,支持Mac和Windows的網(wǎng)頁瀏覽劣坊。它的網(wǎng)頁播放器也被Mac 所支持馏臭。網(wǎng)頁游戲 坦克英雄和手機游戲王者榮耀都是基于它的開發(fā)。感興趣的看下面幾篇文章讼稚。
1. Unity強化篇(一) —— 如何使用Vuforia制作AR游戲(一)
2. Unity強化篇(二) —— 適用于Unity的HTC Vive教程(一)
Using The Controllers With Physics Objects
VR為用戶提供了許多在現(xiàn)實世界中無法實現(xiàn)的機會括儒,包括拾取物體,檢查它們并將其丟棄而不必在之后進行清理锐想。
您可以通過使用一些觸發(fā)器碰撞器并執(zhí)行一些腳本來創(chuàng)建這種無憂無慮的虛擬體驗帮寻。
在層次結(jié)構(gòu)中選擇both controllers
,并為它們添加Rigidbody
組件赠摇。 (Add Component > Physics > Rigidbody)
選中Is Kinematic
復選框并取消選中Use Gravity
:
現(xiàn)在固逗,向兩個控制器添加Box Collider
(Add Component > Physics > Box Collider
)并選中Is Trigger
。
默認collider
很大藕帜,因此您需要調(diào)整大小并重新定位它烫罩。 將Center
設置為(X:0,Y:-0.04洽故,Z:0.02)
并將Size
設置為(X:0.14贝攒,Y:0.07,Z:0.05)
时甚。 在這種情況下隘弊,您需要這些類型的精確值,因為即使百分之一單位也會影響collider
的最終位置荒适。
再次運行游戲梨熙。 在層次結(jié)構(gòu)中選擇一個控制器并選擇真實控制器。 查看Scene
視圖并將焦點放在您所持有的控制器上(按F鍵)刀诬。 collider
正好位于控制器的頂部咽扇,這是您用來拾取物體的部分。
沒有腳本陕壹,這個collider
只不過是一個無用的立方體质欲。 在RW \ Scripts
中創(chuàng)建一個新的C#
腳本,將其命名為ControllerGrabObject
并將其打開帐要。
將其添加到腳本的頂部:
using Valve.VR;
與前一個腳本一樣把敞,這使您可以輕松訪問SteamVR
類。
現(xiàn)在榨惠,刪除Start()
方法并在其位置添加這個熟悉的代碼:
public SteamVR_Input_Sources handType;
public SteamVR_Behaviour_Pose controllerPose;
public SteamVR_Action_Boolean grabAction;
這與您用于輸入測試腳本的代碼相同奋早。 它存儲對手部類型和動作的引用盛霎。
將這些變量添加到您剛剛添加的變量之下:
private GameObject collidingObject; // 1
private GameObject objectInHand; // 2
每個變量都有一個目的:
- 1) 存儲觸發(fā)器當前與之碰撞的
GameObject
,因此您可以抓取對象耽装。 - 2) 用作玩家當前抓取的
GameObject
的參考愤炸。
接下來,在Update()
上面添加此方法:
private void SetCollidingObject(Collider col)
{
// 1
if (collidingObject || !col.GetComponent<Rigidbody>())
{
return;
}
// 2
collidingObject = col.gameObject;
}
此方法接受collider
作為參數(shù)掉奄,并使用其GameObject
作為抓取和釋放的collidingObject
规个。 而且,它:
- 1) 如果玩家已經(jīng)持有某物或物體沒有
rigidbody
姓建,則不會使GameObject
成為潛在的抓取目標诞仓。 - 2) 將對象指定為潛在的抓取目標。
添加以下觸發(fā)器方法:
// 1
public void OnTriggerEnter(Collider other)
{
SetCollidingObject(other);
}
// 2
public void OnTriggerStay(Collider other)
{
SetCollidingObject(other);
}
// 3
public void OnTriggerExit(Collider other)
{
if (!collidingObject)
{
return;
}
collidingObject = null;
}
這些方法處理trigger collider
進入和退出另一個collider
時應該發(fā)生的情況速兔。
- 1) 當
trigger collider
進入另一個時墅拭,這會將另一個collider
設置為潛在的抓取目標。 - 2) 類似于第一部分
(// 1)
涣狗,但不同谍婉,因為它確保當玩家將控制器保持在對象上一段時間時設置目標。 如果沒有這個镀钓,碰撞可能會失敗或變成buggy
穗熬。 - 3) 當
collider
退出對象時,放棄未抓取的目標丁溅,此代碼通過將其設置為null
來移除其目標唤蔗。
接下來,您將添加一些代碼來獲取OnTriggerExit()
下面的對象:
private void GrabObject()
{
// 1
objectInHand = collidingObject;
collidingObject = null;
// 2
var joint = AddFixedJoint();
joint.connectedBody = objectInHand.GetComponent<Rigidbody>();
}
// 3
private FixedJoint AddFixedJoint()
{
FixedJoint fx = gameObject.AddComponent<FixedJoint>();
fx.breakForce = 20000;
fx.breakTorque = 20000;
return fx;
}
在這里唧瘾,您:
- 1) 將碰撞的
GameObject
移動到玩家手中并將其從collidingObject
變量中移除措译。 - 2) 使用下面的
AddFixedJoint()
方法添加一個將控制器連接到對象的新關節(jié)。 - 3) 制作一個新的固定接頭饰序,將其添加到控制器,然后進行設置规哪,使其不會輕易斷裂求豫。 最后,你返回它诉稍。
必須釋放什么可以被抓住蝠嘉。 下一個塊處理釋放對象:
private void ReleaseObject()
{
// 1
if (GetComponent<FixedJoint>())
{
// 2
GetComponent<FixedJoint>().connectedBody = null;
Destroy(GetComponent<FixedJoint>());
// 3
objectInHand.GetComponent<Rigidbody>().velocity = controllerPose.GetVelocity();
objectInHand.GetComponent<Rigidbody>().angularVelocity = controllerPose.GetAngularVelocity();
}
// 4
objectInHand = null;
}
此代碼移除抓取對象的固定關節(jié),并在玩家將其拋棄時控制其速度和旋轉(zhuǎn)杯巨。 控制器的速度在這里至關重要蚤告。 不使用它,無論你的投擲多么完美服爷,丟棄的物體都會直接下降杜恰。 相信我获诈,這樣感覺不是很好。
逐節(jié)細分:
- 1) 確毙暮郑控制器上有固定接頭舔涎。
- 2) 移除與關節(jié)保持的對象的連接并破壞關節(jié)。
- 3) 當玩家釋放對象時添加控制器的速度和旋轉(zhuǎn)逗爹,因此結(jié)果是真實的弧亡嫌。
- 4) 刪除對以前附加對象的引用。
最后掘而,在Update()
中添加它來處理控制器輸入:
// 1
if (grabAction.GetLastStateDown(handType))
{
if (collidingObject)
{
GrabObject();
}
}
// 2
if (grabAction.GetLastStateUp(handType))
{
if (objectInHand)
{
ReleaseObject();
}
}
- 1) 當玩家觸發(fā)抓取動作時挟冠,抓住該對象。
- 2) 如果玩家釋放鏈接到Grab動作的輸入并且有一個對象附加到控制器袍睡,則會釋放它圃郊。
我打賭你迫不及待地試試這個! 保存腳本并返回編輯器女蜈。
在層次結(jié)構(gòu)中選擇兩個控制器持舆,并為每個控制器添加一個Controller Grab Object
組件。
在兩個控制器仍處于選中狀態(tài)的情況下伪窖,將Grab Action
設置為\ actions \ default \ in \ Grab
逸寓。 接下來,僅選擇Controller (left)
覆山,將其Hand Type
設置為Left Hand
并將Steam VR_Behaviour_Pose
組件拖到Controller Pose
插槽上竹伸。
現(xiàn)在對右側(cè)的控制器執(zhí)行相同操作,但請使用右手簇宽。
是時候玩得開心了勋篓! 準備好控制器,開始游戲并戴上headset
魏割。 使用hair trigger
或grip button
拾起并折騰一些立方體和球譬嚣。 你甚至可以通過一些練習來兼顧。
你必須把它交給自己钞它,你現(xiàn)在非常棒拜银。 但是,我認為你可以讓你的VR體驗更酷遭垛。
Making A Laser Pointer
出于各種原因尼桶,激光指示器在VR世界中很方便。 您可以使用它們彈出虛擬氣球锯仪,更好地瞄準槍支泵督。
制作一個很簡單:你需要的只是一個立方體和另一個腳本。 首先在層次結(jié)構(gòu)的根目錄中創(chuàng)建一個新的Cube
(Create > 3D Object > Cube
)庶喜。
將其命名為Laser
小腊,將其位置設置為(X:0救鲤,Y:5,Z:0)
溢豆,將比例更改為(X:0.005蜒简,Y:0.005,Z:1)
并移除Box Collider
組件漩仙。 專注于它搓茬,你會看到它漂浮在其他level
之上:
激光不應投射陰影,它們總是相同的顏色队他,因此您可以使用未照明的材料獲得所需的效果卷仑。
在RW \ Materials
中創(chuàng)建一個新材質(zhì),并將其命名為Laser
麸折。 然后锡凝,將其著色器更改為Unlit / Color
并將其Main Color
設置為純紅色:
通過在層次結(jié)構(gòu)或Scene
視圖中將其拖動到Laser
來指定新材質(zhì):
最后,將Laser
從層次結(jié)構(gòu)拖動到RW \ Prefabs
并從層次結(jié)構(gòu)中刪除原始激光垢啼。
現(xiàn)在在RW \ Scripts
中創(chuàng)建一個名為LaserPointer
的新C#
腳本并打開它窜锯。
使用聲明將此添加到文件的頂部:
using Valve.VR;
接下來,在Start()
上方添加這些熟悉的變量:
public SteamVR_Input_Sources handType;
public SteamVR_Behaviour_Pose controllerPose;
public SteamVR_Action_Boolean teleportAction;
這些引用了控制器和Teleport
動作芭析。
在teleportAction
下面添加這些變量:
public GameObject laserPrefab; // 1
private GameObject laser; // 2
private Transform laserTransform; // 3
private Vector3 hitPoint; // 4
- 1) 這是對激光預制件的引用锚扎。
- 2)
laser
存儲對激光器實例的引用。 - 3) 存儲變換組件以便于使用馁启。
- 4) 這是激光擊中的位置驾孔。
在Update()
下面添加此方法以顯示激光:
private void ShowLaser(RaycastHit hit)
{
// 1
laser.SetActive(true);
// 2
laserTransform.position = Vector3.Lerp(controllerPose.transform.position, hitPoint, .5f);
// 3
laserTransform.LookAt(hitPoint);
// 4
laserTransform.localScale = new Vector3(laserTransform.localScale.x,
laserTransform.localScale.y,
hit.distance);
}
此方法將RaycastHit
作為參數(shù),因為它包含命中的位置和它行進的距離惯疙。
下面細分:
- 1) 顯示激光翠勉。
- 2) 將激光定位在控制器和光線投射點之間。 你使用
Lerp
是因為你可以給它兩個位置和它應該移動的百分比霉颠。 如果你傳遞0.5f
对碌,即50%,它將返回精確的中間點掉分。 - 3) 將激光指向光線投射的位置俭缓。
- 4) 縮放激光,使其完全適合兩個位置酥郭。
在Update()
中添加以下內(nèi)容以使用玩家的輸入:
// 1
if (teleportAction.GetState(handType))
{
RaycastHit hit;
// 2
if (Physics.Raycast(controllerPose.transform.position, transform.forward, out hit, 100))
{
hitPoint = hit.point;
ShowLaser(hit);
}
}
else // 3
{
laser.SetActive(false);
}
- 1) 如果激活
Teleport
操作: - 2) 從控制器射出光線。 如果碰到某些東西愿吹,請將其存放在它所觸及的位置并顯示激光不从。
- 3)
Teleport
動作取消激活時隱藏激光。
在空的Start()
方法中添加以下內(nèi)容:
// 1
laser = Instantiate(laserPrefab);
// 2
laserTransform = laser.transform;
- 1) 產(chǎn)生一種新的激光并在
laser
中保存它的引用犁跪。 - 2) 存儲激光的變換組件椿息。
保存此腳本并返回編輯器歹袁。 在層次結(jié)構(gòu)中選擇兩個控制器,并為每個控制器添加一個Laser Pointer
寝优。
在兩個控制器仍處于選中狀態(tài)的情況下条舔,將Hand Type
設置為Left Hand
并將Steam VR_Behaviour_Pose
組件拖動到Controller Pose
插槽。 接下來乏矾,將Teleport Action
設置為Teleport
孟抗。
最后,將Laser
預制件從Prefabs
拖到Inspector
中的Laser
插槽上:
現(xiàn)在選擇正確的控制器并將Laser Pointer
組件上的Hand Type
設置為Right Hand
钻心。
保存您的項目并讓游戲再次運行凄硼。 拿起一個控制器,戴上headset
捷沸,然后拿著觸摸板摊沉。 你現(xiàn)在會看到激光:
在繼續(xù)之前,通過右鍵單擊控制器并選擇Remove Component
痒给,從控制器中刪除Actions Test
組件说墨。
您正在刪除它們,因為它們?yōu)槊總€幀編寫字符串并將它們記錄到控制臺苍柏。這對于性能來說并不是一件好事尼斧,每一毫秒都在VR中。它們對于測試輸入很方便序仙,但是你不應該將它們用于實際的游戲玩法突颊。
下一步是使用這種激光傳送到房間周圍!
Moving Around
在VR中移動并不像推動玩家那么簡單潘悼;這樣做是一種引起惡心的可靠方法律秃。一種更可行的出行方式是遠程傳送雹熬。
玩家的感知感比漸進的感覺更容易接受突然的位置變化闯捎。 VR設置中的微妙變化可能會讓您感覺平衡和速度更快滔以,而不是突然發(fā)現(xiàn)自己處于一個新的位置贫橙。
要準確顯示最終的位置破婆,您將使用Prefabs
中提供的標記或標線勺像。
十字線是一個簡單的债沮,沒有照明的圓盤:
要使用reticle
擂错,您將附加LaserPointer
腳本缕陕,因此在代碼編輯器中打開它并將這些變量添加到現(xiàn)有的變量下面:
// 1
public Transform cameraRigTransform;
// 2
public GameObject teleportReticlePrefab;
// 3
private GameObject reticle;
// 4
private Transform teleportReticleTransform;
// 5
public Transform headTransform;
// 6
public Vector3 teleportReticleOffset;
// 7
public LayerMask teleportMask;
// 8
private bool shouldTeleport;
每個變量都起著重要作用:
- 1)
[CameraRig]
的變換粱锐。 - 2) 存儲傳送十字線預制件的引用。
- 3) 對標線
(reticle)
實例的引用扛邑。 - 4) 存儲對傳送十字線變換的參考以便于使用怜浅。
- 5) 存儲對玩家頭部(相機)的引用。
- 6) 標線偏離平面,因此與其他表面沒有
“Z-fighting”
恶座。 - 7) 一個圖層蒙版搀暑,用于過濾允許傳送的區(qū)域。
- 8) 找到有效的傳送位置時設置為
true
跨琳。
在Update()
中自点,替換此行:
if (Physics.Raycast(controllerPose.transform.position, transform.forward, out hit, 100))
使用這個將圖層蒙版考慮在內(nèi)的:
if (Physics.Raycast(controllerPose.transform.position, transform.forward, out hit, 100, teleportMask))
這可以確保激光只能擊中你可以傳送到的游戲?qū)ο蟆?/p>
同樣在Update()
中,在ShowLaser(hit)
調(diào)用下添加此代碼:
// 1
reticle.SetActive(true);
// 2
teleportReticleTransform.position = hitPoint + teleportReticleOffset;
// 3
shouldTeleport = true;
這是這樣做的:
- 1) 顯示傳送的十字線
(reticle)
脉让。 - 2) 將
(reticle)
移動到光線投射所在的位置并添加偏移以避免Z-fighting
桂敛。 - 3) 將
shouldTeleport
設置為true表示腳本找到了傳送的有效位置。
仍然在Update()
中侠鳄,找到laser.SetActive(false);
并在其下添加以下行:
reticle.SetActive(false);
這在沒有有效目標的情況下隱藏了reticle
埠啃。
在ShowLaser()
下面添加以下方法來處理傳送行為:
private void Teleport()
{
// 1
shouldTeleport = false;
// 2
reticle.SetActive(false);
// 3
Vector3 difference = cameraRigTransform.position - headTransform.position;
// 4
difference.y = 0;
// 5
cameraRigTransform.position = hitPoint + difference;
}
誰知道傳送就像五行一樣簡單? 是時候逐步完成代碼了:
- 1) 在傳送正在進行時將
shouldTeleport
設置為false
伟恶。 - 2) 隱藏十字線
(reticle)
碴开。 - 3) 計算攝像機裝備中心位置與玩家頭部之間的差異。
- 4) 將上述差異的y位置重置為0博秫,因為計算不考慮玩家頭部的垂直位置潦牛。
- 5) 將攝像機裝置移動到命中點的位置并添加計算的差異。 沒有差別挡育,玩家將傳送到不正確的位置巴碗。 請參閱以下示例:
正如您所看到的,差異在精確定位攝像機裝置并將玩家準確放置到他們希望降落的位置方面起著至關重要的作用即寒。
在Update()
的末尾添加它橡淆,就在teleport
動作狀態(tài)if-else
語句之外:
if (teleportAction.GetStateUp(handType) && shouldTeleport)
{
Teleport();
}
如果觸摸板被釋放并且有一個有效的傳送位置,則傳送玩家母赵。
最后逸爵,將此代碼添加到Start()
:
// 1
reticle = Instantiate(teleportReticlePrefab);
// 2
teleportReticleTransform = reticle.transform;
- 1) 產(chǎn)生一個新的
reticle
并在reticle
中保存對它的引用。 - 2)存儲
reticle
的變換組件凹嘲。
就這些师倔! 保存您的腳本并返回Unity
。
在層次結(jié)構(gòu)中選擇兩個控制器并記下新字段:
將[CameraRig]
拖動到Camera Rig Transform
插槽周蹭,將TeleportReticle
從Prefabs
拖動到Teleport Reticle Transform
插槽趋艘,然后將Camera
拖動到Head Transform
插槽。
現(xiàn)在將Teleport Reticle Offset
設置為(X:0凶朗,Y:0.05瓷胧,Z:0)
并將Teleport Mask
設置為CanTeleport
。 CanTeleport
不是默認圖層 - 它是為本教程創(chuàng)建的棚愤。 Floor
和Table
對象是該層中唯一的對象抖单。
玩游戲并在地板上使用激光傳送到房間周圍。
在這個針對Unity
的HTC Vive
教程中遇八,您學習了如何:
- 下載并配置
SteamVR
矛绘。 - 處理
HTC Vive
控制器輸入。 - 在VR中與物理對象交互刃永。
- 制作激光筆货矮。
- 傳送一個區(qū)域。
這個項目只是一個開始 - 讓它成為你自己的斯够。 我很想知道你想出了什么囚玫。
后記
本篇主要講述了適用于Unity的HTC Vive教程,感興趣的給個贊或者關注~~~