1. 程式人生 > >教你如何用Unity和Cardboard把3D遊戲做成VR遊戲

教你如何用Unity和Cardboard把3D遊戲做成VR遊戲

原網址

隨著Oculus宣佈1月6日開啟預售,2016年很可能成為VR遊戲元年,但很多的調研顯示,手遊裝置才是市場增長的關鍵,SuperData釋出的報告顯示,2016年全球VR遊戲市場規模預計在51億美元左右,消費者裝置安裝量在3890萬左右,憑藉價格門檻的優勢,以谷歌Cardboard和三星Gear VR為代表的移動VR裝置很大可能成為使用者量最大的裝置,可能佔據2016年虛擬現實裝置安裝量71%的份額,達到2700萬。


最近,一位從事VR遊戲研發的開發者在自己的部落格中展示瞭如何用Unity和Cardboard把一款3D遊戲變成VR遊戲的方法,他在文章最後還表示,你甚至可以用這種方法把遊戲轉化為AR遊戲,或者從頭開始做新的VR遊戲,以下是Gamelook編譯的博文:

很多的科幻電影都展示了用人類意志控制物體的能力,但到目前為止,這仍舊是一種幻想,目前還沒有技術可以實現這一點。在這份新手教學部落格中,你可以學到如何用Unity做一款兼但的虛擬現實遊戲,配合谷歌Cardboard創造比較簡單的VR體驗,本文主要講的是:

把Cardboard攝像頭整合到你的遊戲中;調整UI元素以適應VR模式;做VR模式下可以選擇的按鈕;在遊戲執行的時候程式化地把遊戲在常規和VR模式下進行切換。

什麼是谷歌Cardboard?

理論上說,創造VR體驗是非常直接的,你在螢幕上展示的並不是一個單獨的圖片,而是需要2個。因為它們來自位置相隔幾英寸距離的兩個攝像頭,玩家們從左攝像頭看到的是左邊影象,右邊看到的則是右邊影象,這就創造了遊戲景深。

此外,再加上一些不錯的動態感測器,你可以探測到使用者面朝哪個方向。把這些和你所創造的3D世界結合起來的話,就可以獲得一個沉浸感很強的遊戲體驗。在實際情況中,在一個高解析度的螢幕上展示兩個影象需要非常複雜的硬體,還需要可以追蹤玩家的頭部運動,把所有的功能整合到一個裝置商,還要控制其重量,以免讓使用者戴起來太累。

然而,隨著谷歌Cardboard的出現,每一臺智慧機都有可能與Cardboard協作,可以用你手機的螢幕與感測器,把它們變成VR裝置的一種,而你所需要的,只是一些Cardboard和塑料鏡片。

開始準備

需要注意的是,你可能大量用到Unity GUI,所以如果從來沒有嘗試過這個工具,那麼最好是看看Unity GUI教程。想要用Google Cardboard做出自己的VR遊戲,你需要以下工具:

Unity專業版,版本5以上;一部智慧機,可以是iPhone 5代以後的iOS裝置,也可以是4.3以上版本的Android裝置。需要說的是,本文假設你是在用iPhone獲得VR遊戲體驗。

如果你從來沒有用過Unity而且也不熟悉介面,那最好是去讀Unity教程介紹

可能會有人說,我如何獲得一個Cardboard硬體呢?

當然,如果還沒有Cardboard裝置的話,最好是從供應商那裡選購,價格加運費大約是20-30美元,如果你覺得自己非常善於DIY,也可以動手做自己的版本。在購買Cardboard的時候,要注意提到V2或者Cardboard 2.0的字樣,因為它們適配大量的手機,包括大螢幕的iPhone 6+在內,它們還支援使用者通過按鈕進行輸入操作。

沒有Cardboard裝置可以嗎?

從某種程度上說,是可以的,你仍然可以在自己的裝置上執行做出來的遊戲,它看起來會是這樣的(下圖):

在玩遊戲的時候,如果你用恰當的方式盯著螢幕看,也可以找到VR的感覺。如果你四處移動手機,就可以進行控制。雖然你也可以玩這款遊戲,還能夠看到遊戲的實際效果,但這種體驗是比較有限的。

長話短說,如果你沒有足夠的耐心等待Cardboard到貨,你仍然可以從本文中學到東西,只是,如果有合適的裝置,你能夠學的東西更多。

樣本遊戲:Ninja Attack is Back!

投入一些時間嘗試這個樣本遊戲,下載並解壓這個Unity新手專案。接下來就是執行Unity,在歡迎介面,選擇開啟(Open)-找到StarterNinja資料夾,開啟NinjaAttack專案。

在專案瀏覽器(Project Browser)中,在Assets裡雙擊MainScene按鈕,然後點選Play嘗試一下這款遊戲。在圖片中,你是左邊的忍者,隨著怪獸在螢幕中出現,你可以在螢幕上點選任何地方釋放一個忍者之星消滅怪獸,在擊殺20個怪獸之後,你就贏了,但是,如果怪獸到達了左邊的紅色區域,你就輸了。

這款遊戲看起來很熟悉是嗎?熟悉的讀者可能會發現,它其實就是我之前介紹SpriteKit以及Cocos2D教程用到的遊戲,不過與之不同的是,這裡的遊戲是用3D渲染的。當然,你並不一定能夠真正地看到非常酷炫的3D效果,這款遊戲使用的是上帝視角,所以對所有的polygon進行渲染總覺得浪費時間,所以,你現在可以發現為什麼這款遊戲非常適合做成VR了。

開始使用Cardboard

你需要做的第一件事就是為Unity下載Cardboard SDK。接下來,把它匯入到你的專案中。從Unity的主選單,選擇Assets\Import Package\Custom Package,然後選擇你剛剛下載的CardboardSDKForUnity.unitypackage。確保所有東西都被選中,反選Legacy資料夾,然後點選Import按鈕。

為了讓你的遊戲作為一個VR體驗,你需要用到一些技巧,在Project Browser中的Cardboard\Prefabs資料夾裡,把CardboardMain Prefab拖拽到你的場景中,在Inspector中,給其賦予和你的忍者角色一樣的位置(5.53,1.13,0.122),並且要進行90度Y Rotation。

你會發現的是,它比忍者的中心部位略高,這樣可以展現出你在看他的眼睛。

接下來,選擇主攝像頭(Main Camera)並且在Inspector中反選,做raccoon忍者物件的時候也需要同樣的操作。現在,把遊戲在Unity編輯器中再次執行,你就會看到一些類似於3D場景的東西。如果你在移動滑鼠的時候按住選擇鍵,你的攝像頭就會隨著頭部的運動進行旋轉。

在iOS裝置上執行你的遊戲場景

在Unity編輯器中執行你的遊戲是非常不錯的,但最後一次檢查的時候,用VR頭盔配上電腦顯示器看起來會讓人很痛苦,所以我們需要適配到iPhone上。

選擇File\Build Settings,iOS應該已經被選為你的預設平臺,點選Click Player Settings然後轉換到Inspector。

在Resolution and Presentation選單下,把Default Orientation設定成Landscape Left。

在其他設定(Other Settings)中,把Bundle Identifier改成你的公司所需要的東西,比如com.(你的公司名).NinjaAttackVR。

把目標裝置改為iPhone,把iPhone和電腦進行連線,選擇Build和Run,然後給輸出資料夾命名,這個名字你可以隨意取。

這時候,Unity就會匯出你的專案,然後它就會自動在Xcode中開啟,如果沒有開啟,啟動Xcode並且手動開啟生成後的專案,執行然後在手機上嘗試。首次運行遊戲的時候,你需要一系列的設定過程,比如可以在Cardboard硬體上掃描二維碼,這樣Cardboard SDK就可以根據你的裝置、距離等進行畫質微調。

需要注意的是,如果設定過程中,你在掃描二維碼的時候出現了 網址開啟錯誤,那就必須調整Xcode專案中的info.plist,蘋果開發者論壇中有說到這個問題,感興趣的童鞋可以親自查閱。

接著,把你的手機插入Cardboard當中,來回轉頭以調整攝像頭視角,你就可以看到相對不錯的3D畫面了。

再一次把它做成遊戲

能夠看到你的遊戲世界是非常不錯的,但初次之外,你還需要把玩法加入到遊戲中,特別是你需要從忍者面朝的方向扔出忍者之星,這是你將要做的第一個玩法。

對於UI來說,Cardboard支援一個按鈕,看起來可能是比較有限,但如果把它和頭部的動態追蹤相結合的話,它可以做出更為複雜的互動。在《Ninja Attack》中,你通過Cardboard.SDK.VRModeEnable資源偵測玩家是否開始了VR模式,檢查按鈕是否和Cardboard.SDK.Triggered資源同時按下去了,如果這些值都對,就可以在使用者面朝的方向扔出忍者之星。

開啟你的NinjaStarLauncher.cs指令碼,你會發現它在Inspector裡是和GameLogic GameObject連在一起的。

創造一個新的private變數:

private Vector3 _vrShooterOffset;

把它在Start() method中初始化:

_vrShooterOffset = new Vector3(0.0f, -0.4f, 1.0f);

用以下程式碼替換Update ():

這就可以運行了,接下來我們看看Update()是做什麼的:

你首先檢查遊戲是否在VR模式,使用者是否按下了按鈕檢查Cardboard.SDK singleton object上的資源。

在此之後,你可以呼叫LaunchNinjaStarFrom()釋放一個忍者之星,你需要用到兩個parameter:

第一個是GameObject標頭檔案,Cardboard庫會為你調出來,所以它應該是已經指向了正確的位置;第二個是輕微偏移,這樣你面前的忍者之星就會看起來更真實,否則的話你扔出去的忍者之星就像是在四隻眼之間進行運動,雖然看起來很cool,但給人的感覺很奇怪。

由於你的Ninja Star GameObject已經被設計飛往特定方向,所以它會朝著正確的方向進攻。

再試一次,這時候,你可以轉頭扔向壞人,輸贏logic仍舊起作用。

解決Game Over選單

你可能已經注意到了,當遊戲結束的時候,用之前的Game Over按鈕,你的角色仍舊是在螢幕的左邊。這款遊戲用到了Display Canvas來展示Game Over介面,Unity最新的GUI教程中有講到這一點,它總是出現在遊戲視窗的頂部。這個標籤適用於大多數的遊戲GUI,因為它可以自動適應到你螢幕的上方,不論你的攝像頭在做什麼,而且它可以非常不錯地適應不同螢幕尺寸。

但在這個案例中,你需要一個存在於遊戲世界中的GUI canvas,有一部分原因是它可以在3D環境中更好渲染,但還因為不希望把玩家愛是叫鎖定到攝像頭上。你的玩家們需要可以上下自由地看,這樣他們可以看到不同的UI元素,找到最活躍的然後點選按鈕。

創造一個新的Canvas

在Hierarchy選單下選擇GameOverCanvas,右擊並且選擇複製,重新命名為VRGameOverCanvas,這樣可以使它與原來的進行區別開來,把GameOverTxt重新命名為VRGameOvertxt。

在VRGameOverCanvas元件中,把渲染模式改為World Space。

在Rect Transform元件中,把位置改為(-2.24,1.1,0.07),然後進行90度Y Rotation

最後,把X和Y Scale改為0.009,當所有一切完成的時候,VRGameOverCanvas看起來因該是這樣的:

你可以在Game View視角下看到兩個canvas是大致重疊的(當遊戲不執行的時候):

這些值是哪裡來的呢?坦白地說,我其實是調整到自己通過Cardboard攝像頭看起來比較不錯為止。有時候,程式設計更多的是一門藝術而不是學科。

支援兩個Canvas

接下來,你需要更改GameController.cs,這樣它才會發現兩個Canvas開啟和GameLogic GameObject指令碼,它也是和GameLogic GameObject聯絡在一起的。把以下的兩個公共變數加入到你的class裡:

public Canvas VRGameOverCanvas;
public Text VRGameOverTxt;

在resetGame()的開始加入如下程式碼:

VRGameOverCanvas.enabled = false;

用以下程式碼取代Gameover():

public void GameOver(bool didIWin) {
isGameOver = true;
_didIWin = didIWin;
string finalTxt = (_didIWin) ? “You won!” : “Too bad”;
if (Cardboard.SDK.VRModeEnabled) {
VRGameOverCanvas.enabled = true;
VRGameOverTxt.text = finalTxt;
} else {
gameOverCanvas.enabled = true;
gameOverTxt.text = finalTxt;
}
}

這個展示了正確的Canvas和Text物件,取決於你是否在VR模式(開啟Cardboard.SDK.VRMode).

在你儲存了指令碼之後,你需要把正確的物件分配到新的公用變數。在Inspector裡找到GameController,點選每個新變數旁邊的目標,然後選擇VRGameOverCanvas物件作為你的VR遊戲Over Over Canvas變數,把VRGameOverTxt物件選為你的VR Game Over Txt變數。

需要注意的是,可能你會奇怪,為什麼是很麻煩地支援兩個Canvas而不是至改變現有的一個呢?原因是,你既需要支援上帝視角,還需要支援VR模式,所以一定要進行優化。

如果你準備現在就運行遊戲,就可以發現VR模式裡的遊戲結束介面展示的很自然。你可以上下看介面的不同部分,現在所有缺少的東西就是再來一次的按鈕。

增加Gaze輸入方式

幸運的是,Unity內建了‘在使用world-space GUI Canvas的時候,攝像頭中心點可以作為滑鼠使用’,但你需要提供額外的指令碼才能使它在VR介面中進行使用。

首先,擴充套件Cardboard Main\Head,找到主攝像頭並把它重新命名為VR Main Camera。選中VRGameOverCanvas物件,你們應該可以看到一個事件攝像頭,點選Hierarchy裡的EventSystem專案,點選增加元件按鈕,並增加GazeInpute Module指令碼。這個指令碼可以確保Unity的GUI系統瞭解Cardboard攝像頭的工作方式。

檢查VR Mode Only,因為在VR模式下的時候,只需要這麼執行就可以了。最後,點選你剛剛增加的Gaze Input Module Component,然後選擇Move Up,重複一次,確保它可以出現在觸屏輸入和獨立輸入模式中,這可以確保Gaze Input Module在遊戲進行的同時優先選擇輸入方式。當所有都做好的時候,它看起來應該是這樣的:

現在,你就可以進行嘗試了。這一次,當你把視角放到Play Again按鈕的時候,它就會變綠,讓你重新開始一場新的遊戲。

玩法微調

或許你會發現這個版本的遊戲在VR模式下玩起來有點難,這是因為你的視角是縮水的,所以在你看著錯誤的方向時,敵人很容易從你身邊溜過去。而且,你無法迅速改變瞄準方向,你會因為脖子轉速的限制而影響到遊戲操作。你讓玩家體驗VR模式並不是為了懲罰他們,所以,你該如何調整呢?當然,可能會有人建議把敵人速度降低。

在Prefabs資料夾中選中EvilSlimeEnemy Prefab,然後開啟EnemyMover.cs,把以下程式碼增加到Start(),隨後設定速度:

這會讓你的遊戲在VR模式下變得更簡單,所以玩家們不至於因為選擇了VR模式就獲得糟糕體驗。

解決螢幕上的分數顯示問題

你還需要解決的一個UI問題是螢幕上的分數,這個就需要不同的方式來處理了。雖然它仍然需要在VR模式中恰當的被顯示出來,但你更希望它在你看任何方向的時候都固定在攝像頭上。

選中Cardboard Main\Head,右擊並選擇UI\Canvas,重新命名新的canvas為VRScoreCanvas,把渲染模式調整為World Space,為其賦予以下值:

位置(0,1,2.5)、寬度400、高度100、旋轉(0,0,0)、Scale(0.0115,0.0115,1)。當完成之後,遊戲看起來該是這樣的:

看起來可能你的文字很奇怪地放在了螢幕中央,但在VR模式裡,你能夠看到的世界比正常情況下是少很多的,所以你在遊戲中看到分數的時候應該是在邊緣部位的,你可以自由進行位置調整,以使其適應你的手機。

接下來,使用文字物件展示你的分數,這個過程和Game Over的做法類似。

開啟GameController.cs並增加一個新的公用變數:

public Text VRScoreTxt;

接下來,你每次更新scoreTxt的時候都需要更新VRScoreTxt,在ResetGame() method中,把以下程式碼加在每次更新後的scoreTxt之後:

VRScoreTxt.text = “–“;

然後把這行程式碼增加到GotOne(),也放在更新scoreTxt的後面:

VRScoreTxt.text = “” + _currScore;

儲存你的指令碼,回到Unity,然後你會發現GameLogic當中的GameController Component如今可以輸入VR Score Txt變量了,點選臨近的目標然後選擇你的VRScoreTxt文字物件。

再次體驗你的遊戲,現在,你就可以看到分數出現在左上角了,還可以允許你的頭部進行運動。

VR模式的切換

由於你的遊戲同時支援上帝視角和VR模式,你應該給使用者自由切換的選擇,UI做起來是很直觀的,你只需要在上帝視角模式中加入一個簡單的按鈕,讓玩家們來回切換模式即可。

首先,你需要增加切換的程式碼,選擇Hierarchy裡的GameLogic,點選增加元件,選擇新指令碼(New Script)然後把指令碼命名為CardboardSwapper。
開啟並用以下內容替換class程式碼:

這個class裡最重要的method就是ActiveVRMode,它是用來啟用Cardboard的VR模式的。其餘的logic負責控制場景中的多個GameObject,取決於是否處於VR模式,你在上帝視角是看不到某些東西的。

你還可以發現的是,當你偵測後面按鈕的時候呼叫了Switch(),這個功能非常適合測試。

你還需要為GameController指令碼增加更多的logic,這樣它才能在切換模式的時候展示或者隱藏一些東西,開啟GameController.cs,把這個method加進去:

public void RefreshGameOver() {
gameOverCanvas.enabled = false;
VRGameOverCanvas.enabled = false;
if (isGameOver) {
GameOver(_didIWin);
}
}

儲存一切然後重新回到Unity介面,選擇GameLogic然後向下滾動到Cardboard Swapper元件,對於Cardboard Object數列,把它的大小賦值為1,然後放到場景中的CardboardMain GameObject中。這樣不僅可以禁用你的Cardboard Head讓你回到上帝視角攝像頭模式,還可以禁用VRScoreCanvas。

對於Mono Object數列,把它的大小賦值為3,然後為你的場景選擇Canvas、Main Camera和raccoon ninja,不要從Assets裡選擇。

最後你需要在上帝視角canvas為使用者增加一個按鈕,為了節約時間,我已經把它做好了,位於prefabs資料夾中。

從Assets\Prefabs中把CardboardButton推拽到Hierarchy,這樣它就成為了你的Canvas物件的子物件,確保其位置設定是(-50,50,0):

在你的按鈕物件底部,把它們連線起來,這樣點選按鈕的時候就可以呼叫CardboardSwapper.Switch() method,你可以從這個動畫看看是如何做出來的:

再次嘗試你的遊戲,點選螢幕右下方的按鈕切換至VR模式,然後單機Cardboard介面背後的按鈕切換到上帝視角模式。做到這裡,你的VR模式切換就已經完成了。

現在,你可以把Unity中的任何3D遊戲做成VR遊戲了,而且只需要一個Cardboard和一些塑料鏡片,這是可以讓所有人都能夠體驗的VR遊戲。Android版本的做法和iOS大致相同,谷歌的Unity Developer指南還提供了更多的技術資訊。最後,你甚至可以為你的VR遊戲增加AR功能。

最後,你可以嘗試Unity裡所有的3D遊戲,看是否能夠順利地做成VR體驗,或者,這個教程也可以讓你做出全新的VR遊戲。