原文:Unreal Engine 4 Blueprints Tutorial
作者:Tommy Tran
譯者:Shuchang Liu
在本篇教程里,你將學(xué)會(huì)如何用藍(lán)圖系統(tǒng)創(chuàng)建玩家角色,設(shè)置輸入,并編寫角色通過觸碰,收集道具的游戲邏輯。
藍(lán)圖是Unreal Engine 4的一套可視化腳本系統(tǒng),通過藍(lán)圖可以快速制作游戲原型。你不再需要一行行的編寫代碼,取而代之的是可視化操作:拖拽節(jié)點(diǎn),在UI里設(shè)置節(jié)點(diǎn)參數(shù),給節(jié)點(diǎn)進(jìn)行連線。
除了作為一款非常便捷的原型工具,藍(lán)圖也降低了非開發(fā)人員制作游戲邏輯的門檻。
在本篇教程,你將使用藍(lán)圖來:
- 設(shè)置垂直視角攝像機(jī)
- 創(chuàng)建具備基本移動(dòng)的玩家控制器角色
- 設(shè)置玩家輸入
- 創(chuàng)建可被角色觸碰并收集的道具
注意:本篇教程假定你已了解Unreal Engine 4的基本操作界面。你也應(yīng)該熟悉基本的藍(lán)圖概念,比如組件和節(jié)點(diǎn)。如果你需要復(fù)習(xí)以上內(nèi)容,點(diǎn)擊入門教程。
注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:
起步入門
下載示例項(xiàng)目并解壓。進(jìn)入項(xiàng)目文件夾,雙擊BananaCollector.uproject打開項(xiàng)目。
注意:如果你看到了項(xiàng)目是由較早的引擎版本創(chuàng)建的提示,這很正常(因?yàn)橐娼?jīng)常更新版本)。你可以選擇以拷貝副本的形式打開,也可以直接轉(zhuǎn)換項(xiàng)目版本打開。
你可以看到以下的場(chǎng)景。我們創(chuàng)建的角色會(huì)在場(chǎng)景內(nèi)移動(dòng)并收集道具。
為了方便起見,我已經(jīng)給項(xiàng)目文件做了文件夾分類,如下圖所示:
你可以點(diǎn)擊紅框處按鈕來顯示/隱藏側(cè)邊欄列表。
創(chuàng)建玩家
點(diǎn)擊進(jìn)入Content Browser界面的Blueprints文件夾。點(diǎn)擊Add New按鈕并選擇Blueprint Class。
由于玩家需要能夠獲取輸入,Pawn類比較適合。在彈出窗口選擇創(chuàng)建Pawn,將其命名為BP_Player。
注意:選擇Character類創(chuàng)建也可以,它還默認(rèn)引入了移動(dòng)組件。不過,既然我們想要自己動(dòng)手實(shí)現(xiàn)移動(dòng),Pawn類已經(jīng)足夠了。
關(guān)聯(lián)攝像機(jī)
攝像機(jī)是玩家觀察游戲世界的方式。我們要?jiǎng)?chuàng)建一個(gè)垂直視角觀察玩家角色的攝像機(jī)。
在Content Browser 雙擊BP_Player打開藍(lán)圖編輯器。
為了創(chuàng)建攝像機(jī),在Components面板點(diǎn)擊Add Component并選擇Camera。
為了讓攝像機(jī)視角自頂向下,我們需要先把它放在玩家角色上方。選中攝像機(jī)組件,再切換到Viewport頁簽。
按下W鍵激活移動(dòng)操作桿,將攝像機(jī)移動(dòng)到(-1100, 0, 2000)。或者,你可以在Location字段輸入坐標(biāo)點(diǎn)來移動(dòng)攝像機(jī)。
如果攝像機(jī)被移出界面外,按下F鍵就可以重新定位看到攝像機(jī)。
接著,按下E鍵激活旋轉(zhuǎn)操作桿,將攝像機(jī)沿Y軸旋轉(zhuǎn)-60度。
玩家表示
我們用一個(gè)紅色方塊來表示玩家,所以需要使用Static Mesh組件進(jìn)行展示。
首先,在Components面板左鍵點(diǎn)擊空白處取消選中Camera組件。否則,新加的組件會(huì)成為攝像機(jī)的子節(jié)點(diǎn)。
點(diǎn)擊Add Component并選擇Static Mesh。
為了展示紅色方塊,選擇Static Mesh組件,隨后在Details頁簽Static Mesh屬性點(diǎn)擊下拉框,選擇SM_Cube。
你在關(guān)卡場(chǎng)景里應(yīng)該就能看到如下畫面(如果看不到,你可以在Viewport窗口按下F鍵聚焦畫面)
現(xiàn)在,是時(shí)候在關(guān)卡里動(dòng)態(tài)生成玩家了。點(diǎn)擊Compile按鈕并回到主編輯器。
生成玩家
為了讓玩家能夠控制角色,你需要明確兩件事:
- 玩家所要控制的Pawn類
- 角色應(yīng)該在哪里生成
你可以通過創(chuàng)建Game Mode類(游戲模式類)來實(shí)現(xiàn)第一點(diǎn)。
創(chuàng)建游戲模式
游戲模式是一個(gè)類,用于控制玩家進(jìn)入游戲的方式。比如,在多人游戲里,可以使用游戲模式,決定每個(gè)玩家在哪里生成。更重要的是,游戲模式?jīng)Q定了玩家使用哪個(gè)角色。
在Content Browser里點(diǎn)擊進(jìn)入Blueprints文件夾。點(diǎn)擊Add New按鈕并選擇Blueprint Class。
從彈出窗口里選擇Game Mode Base,并命名為GM_Tutorial。
現(xiàn)在,你需要指定哪個(gè)Pawn作為默認(rèn)類。雙擊GM_Tutorial打開藍(lán)圖編輯器。
留意Details面板的Classes部分。點(diǎn)擊Default Pawn Class屬性的下拉框,并選擇BP_Player。
其次,關(guān)卡還需要知道當(dāng)前使用哪個(gè)游戲模式。你可以在World Settings里指明這一點(diǎn)。點(diǎn)擊Compile并關(guān)閉藍(lán)圖編輯器。
每個(gè)關(guān)卡都有自己的設(shè)置。你可以通過Window\World Settings查看設(shè)置。同樣地,也可以在Toolbar選擇Settings\World Settings進(jìn)行查看。
Details頁簽旁邊就會(huì)出現(xiàn)World Settings頁簽。點(diǎn)擊該頁簽的GameMode Override字段,選擇GM_Tutorial。
現(xiàn)在可以看到Game Mode類已經(jīng)修改成GM_Tutorial。
最后,我們還需要指定玩家的生成位置。通過在關(guān)卡里放置Player Start(玩家出生點(diǎn))即可。
放置玩家出生點(diǎn)
在生成玩家的過程中,游戲模式會(huì)尋找關(guān)卡中是否有玩家出生點(diǎn)。如果有,游戲模式就會(huì)在該點(diǎn)生成玩家。
為了放置玩家出生點(diǎn),在Modes面板搜索Player Start。左鍵拖拽 Player Start至Viewport面板。
你可以隨意放置玩家出生點(diǎn)。放好后,點(diǎn)擊Toolbar的Play按鈕。玩家就會(huì)在出生點(diǎn)生成。
如果想要退出游戲,點(diǎn)擊Toolbar的Stop按鈕或按下Esc鍵皆可。如果你看不到鼠標(biāo)指針,按下Shift+F1。
如果玩家不能控制移動(dòng),那其實(shí)算不上游戲,對(duì)吧?我們的下個(gè)任務(wù)就是設(shè)置輸入控制。
設(shè)置輸入
將某個(gè)按鍵指定成觸發(fā)某個(gè)行為,稱之為按鍵綁定。
在Unreal里,你可以通過按鍵觸發(fā)event(事件)的方式來實(shí)現(xiàn)按鍵綁定。事件節(jié)點(diǎn)是一類當(dāng)接收到特定行為時(shí),觸發(fā)執(zhí)行的節(jié)點(diǎn)(比如在這個(gè)例子里,當(dāng)你按下綁定按鍵時(shí),觸發(fā)執(zhí)行某個(gè)事件節(jié)點(diǎn))。當(dāng)某個(gè)事件被觸發(fā)時(shí),任何跟事件節(jié)點(diǎn)連接的節(jié)點(diǎn)就會(huì)被執(zhí)行。
這種按鍵綁定的方式非常有好處,因?yàn)檫@意味著你不需要硬編碼按鍵對(duì)應(yīng)的邏輯。
比如,你綁定了鼠標(biāo)左鍵并命名為Shoot事件。任何有射擊能力的Actor都可以使用Shoot事件,用于檢測(cè)玩家何時(shí)按下了鼠標(biāo)左鍵。如果你想修改射擊對(duì)應(yīng)綁定的按鍵,只要在輸入設(shè)置里修改即可。
如果以硬編碼方式實(shí)現(xiàn),你需要遍歷每個(gè)Actor,分別修改射擊對(duì)應(yīng)綁定的按鍵。
軸映射和操作映射
在Edit\Project Settings里可以看到輸入設(shè)置。點(diǎn)擊Engine部分的Input選項(xiàng)進(jìn)入設(shè)置界面。
Bindings就是用于設(shè)置輸入的部分。
Unreal提供了兩類按鍵綁定方法:
- Action Mapping(操作映射):這類綁定只有兩種狀態(tài):按下或者沒按下。行為只會(huì)在按下或釋放按鍵的時(shí)候觸發(fā)。這類綁定適用于沒有中間狀態(tài)的行為,比如槍械射擊。
- Axis Mapping(軸映射):這類綁定輸出一個(gè)稱之為Axis Value(下文有更多介紹)的數(shù)字。每幀都會(huì)觸發(fā)對(duì)應(yīng)的軸事件。這類綁定通常用于搖桿或者鼠標(biāo)。
在這篇教程里,我們會(huì)使用Axis Mapping。
創(chuàng)建移動(dòng)映射
首先,你需要?jiǎng)?chuàng)建兩組Axis Mapping。這樣就可以實(shí)現(xiàn)多按鍵觸發(fā)同一個(gè)事件。
為了創(chuàng)建一組新的Axis Mapping,點(diǎn)擊Axis Mappings右側(cè)的+號(hào)。創(chuàng)建兩組Axis Mapping,分別命名為MoveForward和MoveRight。
MoveForward負(fù)責(zé)前后移動(dòng)。MoveRight負(fù)責(zé)左右移動(dòng)。
我們需要把移動(dòng)映射到四個(gè)按鍵上:W,A,S和D。現(xiàn)在只有兩個(gè)插槽用于映射按鍵。通過點(diǎn)擊每組映射文本框右側(cè)的+號(hào),添加映射插槽。
接著點(diǎn)擊每組插槽的下拉框,將W和S鍵映射到MoveForward,A和D鍵映射到MoveRight。
接著,我們需要設(shè)置Scale字段。
Axis Value和Input Scale
在你設(shè)置Scale字段前,我們需要了解它是怎么跟axis values搭配起作用的。
Axis Value的輸出數(shù)值取決于輸入類型和使用方式。按鈕點(diǎn)擊會(huì)輸出1。搖桿根據(jù)推動(dòng)方向和力度,輸出-1~1之間的數(shù)值。
你可以使用Axis Value控制角色的移動(dòng)速度。比如,如果你把搖桿推到了最邊上,Axis Value是1。如果你只推一半,Axis Value就是0.5。
將Axis Value跟某個(gè)速度變量進(jìn)行相乘,你就能夠調(diào)整搖桿的速度。
你也可以通過Axis Value判斷出方向。如果你將角色速度與一個(gè)Axis Value正數(shù)相乘,得到的就是正數(shù)偏移。角色速度與一個(gè)Axis Value負(fù)數(shù)相乘,得到的就是負(fù)數(shù)偏移。將偏移值與角色位置相加,就能知道角色往哪個(gè)方向移動(dòng)了。
由于鍵盤按鍵只能輸出0或1的Axis Value,你可以使用Scale來將其轉(zhuǎn)換成負(fù)數(shù)。通過Axis Value和Scale值相乘就可以做到這點(diǎn)。
如果正數(shù)(Axis Value)和負(fù)數(shù)(Scale)相乘,按鍵輸出就是負(fù)數(shù)。
因此我們點(diǎn)擊修改按鍵S和A的Scale字段文本為-1。
接著,有趣的部分來了:讓角色動(dòng)起來!關(guān)閉項(xiàng)目設(shè)置面板,雙擊BP_Player打開藍(lán)圖編輯器。
角色移動(dòng)
首先,你需要獲取移動(dòng)映射的事件。在事件圖表空白處點(diǎn)擊右鍵打開節(jié)點(diǎn)列表。從彈出菜單中搜索MoveForward。添加處于Axis Events下的MoveForward節(jié)點(diǎn)。注意我們要添加的是Axis Events下的紅色節(jié)點(diǎn),而非Axis Values下的綠色節(jié)點(diǎn)。
添加MoveRight節(jié)點(diǎn)的步驟同上。
現(xiàn)在,我們需要設(shè)置下MoveForward節(jié)點(diǎn)。
使用變量
為了實(shí)現(xiàn)移動(dòng),我們需要指定角色的運(yùn)動(dòng)速度。最簡單的方法是通過變量保存移動(dòng)速度。
要新建變量,我們點(diǎn)擊My Blueprint頁簽Variable部分的+號(hào)。
選中新建的變量,觀察Details頁簽。將變量名重命名為MaxSpeed。隨后,點(diǎn)擊Variable Type的下拉框選擇Float,將變量類型修改為Float。
接著,需要給變量設(shè)置默認(rèn)值。在這之前,先點(diǎn)擊Toolbar上的Compile按鈕。
保持變量選中,在Details頁簽的Default Value區(qū)域,將MaxSpeed的默認(rèn)值設(shè)為10。
接著,將MaxSpeed變量從My Blueprint頁簽拖拽至Event Graph。并選擇彈出菜單的Get。
我們現(xiàn)在需要將MaxSpeed與Axis Value相乘來得出最終移動(dòng)速度和方向。添加float * float節(jié)點(diǎn),并連接Axis Value和MaxSpeed。
獲取角色朝向
為了向前移動(dòng),首先需要知道角色的朝向。幸運(yùn)地是,Unreal里有這樣的節(jié)點(diǎn)。我們需要添加Get Actor Forward Vector節(jié)點(diǎn)。
接著,添加Add Movement Input節(jié)點(diǎn)。該節(jié)點(diǎn)通過獲取方向和數(shù)值,將其轉(zhuǎn)換成移動(dòng)偏移值。我們按下圖連接各個(gè)節(jié)點(diǎn):
白線代表節(jié)點(diǎn)執(zhí)行順序。換言之,玩家進(jìn)行操作,觸發(fā)相應(yīng)事件并執(zhí)行InputAxis MoveForward節(jié)點(diǎn),隨后執(zhí)行Add Movement Input節(jié)點(diǎn)。
Add Movement Input節(jié)點(diǎn)需要如下輸入:
- Target:默認(rèn)為self,在這里就是玩家角色自己(紅色方塊)。
- World Direction:目標(biāo)移動(dòng)方向,在這里就是玩家角色的朝向。
- Scale Value:玩家移動(dòng)距離,在這里為Max Speed * Axis Value(值范圍為-1~1)。
MoveRight事件的設(shè)置步驟同上,除了要把Get Actor Forward Vector節(jié)點(diǎn)替換為Get Actor Right Vector節(jié)點(diǎn)。試著不對(duì)照前面的操作指引,自己動(dòng)手看看!
添加移動(dòng)偏移
為了讓角色真正動(dòng)起來,我們還需要將Add Movement Input節(jié)點(diǎn)計(jì)算得出的偏移值,累加到角色當(dāng)前位置上。
基本上我們的策略就是讓游戲角色每幀移動(dòng)一點(diǎn)點(diǎn),所以我們需要在Event Tick事件添加運(yùn)動(dòng)節(jié)點(diǎn),每幀進(jìn)行調(diào)用。
現(xiàn)在看看Event Graph有沒有Event Tick節(jié)點(diǎn),它應(yīng)該處于灰化狀態(tài),如果沒有就創(chuàng)建對(duì)應(yīng)節(jié)點(diǎn)。
為了獲取偏移值,創(chuàng)建Consume Movement Input Vector節(jié)點(diǎn)。要累加偏移值到玩家角色上,還需要添加AddActorLocalOffset節(jié)點(diǎn)。隨后如下圖連接節(jié)點(diǎn):
這樣意味著在游戲每幀,你會(huì)獲取角色的移動(dòng)輸入,并將其累加在角色當(dāng)前位置上。
點(diǎn)擊Compile,回到主編輯器并點(diǎn)擊Play。你就能操控紅色方塊四處移動(dòng)了!
這里有個(gè)小問題。高配機(jī)器有可能運(yùn)行幀率更高。由于Event Tick事件每幀調(diào)用,那同等時(shí)間內(nèi)運(yùn)動(dòng)節(jié)點(diǎn)執(zhí)行的次數(shù)更多。導(dǎo)致的結(jié)果就是高配機(jī)器角色移動(dòng)得更快,反之亦然。
為了避免這個(gè)問題,角色運(yùn)動(dòng)必須是幀率無關(guān)的。
注意:我已經(jīng)做了按鍵綁定用于展示幀率有關(guān)會(huì)產(chǎn)生的影響。按下數(shù)字鍵0將幀率調(diào)成60,按下數(shù)字鍵1將重置幀率。控制角色四處移動(dòng),看看不同幀率對(duì)移動(dòng)速度的影響。
幀率無關(guān)
幀率無關(guān)意味著不管幀率是多少,相同時(shí)間的游戲運(yùn)行,會(huì)產(chǎn)生完全一致的結(jié)果。幸運(yùn)地是,在Unreal里要做到這點(diǎn)非常容易。
退出游戲,并打開BP_Player。接著,觀察Event Tick節(jié)點(diǎn)的Delta Seconds字段。
Delta Seconds為當(dāng)前幀的Event Tick調(diào)用與上一幀Event Tick調(diào)用的時(shí)間間隔。通過將偏移值與Delta Seconds相乘,角色運(yùn)動(dòng)就是幀率無關(guān)的。
比如,你的角色最高速度是100。如果距離上一幀Event Tick已經(jīng)過了1秒,則角色移動(dòng)100個(gè)單元。如果只過了0.5秒,則角色運(yùn)動(dòng)50個(gè)單元。
如果角色運(yùn)動(dòng)是幀率相關(guān)的,那就會(huì)產(chǎn)生不過幀率高低,每幀固定移動(dòng)100單元的結(jié)果。
為了將偏移值與Delta Seconds相乘,添加vector * float節(jié)點(diǎn)。之后,如下圖進(jìn)行連線:
由于每幀間隔時(shí)間很短,角色移動(dòng)起來會(huì)很慢,所以可以將MaxSpeed的默認(rèn)值調(diào)大至600。
至此恭喜你,成功解鎖了幀率無關(guān)成就!
你可能注意到了,方塊現(xiàn)在會(huì)穿透其他物體。為了解決這個(gè)問題,我們需要用上碰撞檢測(cè)。
角色碰撞
為了能夠互相碰撞,角色需要一個(gè)代表其碰撞區(qū)域(通常稱之為碰撞體)的東西。你可以使用以下任一種:
- Collision mesh(碰撞網(wǎng)格):這個(gè)通常在網(wǎng)格導(dǎo)入時(shí)就會(huì)生成(如果你勾選了允許)。用戶也可以用3D軟件創(chuàng)建自定義碰撞網(wǎng)格。紅色方塊導(dǎo)入時(shí)就自動(dòng)生成了碰撞網(wǎng)格。
- Collision component(碰撞組件):一般由三種形狀:盒子,膠囊體和球體。你可以通過Components面板進(jìn)行添加。通常用于簡單碰撞。
下面就是一個(gè)人物和其碰撞體的例子。
當(dāng)一個(gè)碰撞體碰到了另個(gè)碰撞體,碰撞就產(chǎn)生了。
設(shè)置碰撞
你可能會(huì)奇怪,方塊有碰撞體,卻沒有檢測(cè)到碰撞。當(dāng)你移動(dòng)方塊時(shí),Unreal只認(rèn)為方塊的根組件可產(chǎn)生碰撞。由于方塊的根組件并沒有任何碰撞體,所以就穿透了其他物體。
注意:一個(gè)root組件沒有碰撞體的角色,同樣可以擋住其他角色。但如果你移動(dòng)這個(gè)角色,它是不會(huì)與任何物體產(chǎn)生碰撞的。
所以,為了使用碰撞網(wǎng)格,StaticMesh必須作為根組件存在。我們通過在Components面板左鍵拖拽StaticMesh至DefaultSceneRoot。釋放鼠標(biāo),StaticMesh現(xiàn)在就成了根組件了。
最后還要做一件事情。切換到Event Graph頁簽,將AddActorLocalOffset節(jié)點(diǎn)的Sweep輸入勾選為true。
簡單來講,AddActorLocalOffset會(huì)將角色從舊位置瞬移到新位置上。Sweep可以確保舊位置和新位置之間的物體都能與角色進(jìn)行碰撞檢測(cè)。
回到主編輯器并點(diǎn)擊Play。現(xiàn)在方塊能與關(guān)卡場(chǎng)景產(chǎn)生碰撞了!
創(chuàng)建道具
任何東西都能成為供玩家觸碰拾取的道具。這里我們使用BP_Banana作為道具。
為了檢測(cè)方塊是否碰到了道具,我們需要一個(gè)在產(chǎn)生碰撞時(shí),觸發(fā)執(zhí)行的事件節(jié)點(diǎn)。我們可以使用碰撞響應(yīng)來生成事件。
碰撞響應(yīng)也決定了角色之間的碰撞后行為。有以下三類碰撞響應(yīng):Ignore,Overlap和Block。以下是它們互相之間的作用結(jié)果:
雖然可以使用Overlap或Block的任一種,本篇教程只展示如何使用Overlap。
設(shè)置碰撞響應(yīng)
退出游戲并打開BP_Banana。選擇StaticMesh組件并觀察Details面板,Collision部分可以設(shè)置碰撞響應(yīng)。
如圖所示,大部分設(shè)置都是灰置的。為了編輯它們,左鍵點(diǎn)擊Collision Presets的下拉框,選擇Custom選項(xiàng)。
現(xiàn)在,你需要指定道具和方塊之間的碰撞響應(yīng)。
組件有一項(xiàng)屬性稱之為對(duì)象類型。對(duì)象類型是一種給角色進(jìn)行簡單分類的方法。你可以在這里了解更多關(guān)于對(duì)象類型的內(nèi)容。
由于方塊的類型是WorldDynamic,我們需要修改該類型對(duì)象的碰撞響應(yīng)。在Collision Responses設(shè)置下,左鍵點(diǎn)擊WorldDynamic中間的勾選框,將碰撞響應(yīng)改成Overlap。
碰撞處理
為了獲取碰撞情況并進(jìn)行處理,我們需要用到overlap事件。在Components面板右鍵點(diǎn)擊StaticMesh。從彈出菜單中,選擇Add Event\Add OnComponentBeginOverlap。
Event Graph界面就會(huì)出現(xiàn)OnComponentBeginOverlap (StaticMesh)節(jié)點(diǎn)。
最后,添加DestroyActor節(jié)點(diǎn),并連接OnComponentBeginOverlap (StaticMesh)節(jié)點(diǎn)。顧名思義,該節(jié)點(diǎn)會(huì)將目標(biāo)角色從游戲中移除。由于我們沒有顯式指定Target,所以它會(huì)銷毀調(diào)用該節(jié)點(diǎn)的角色。
放置道具
關(guān)閉藍(lán)圖編輯器,并確保Content Browser打開了Blueprints文件夾。
通過左鍵拖拽 BP_Banana至Viewport界面來在關(guān)卡放置香蕉道具。
點(diǎn)擊Play按鈕,開始收集香蕉吧!
后續(xù)學(xué)習(xí)
你可以在這里下載完整項(xiàng)目。
你現(xiàn)在距離成為Unreal Engine專家又近了一步了。希望這篇教程沒有難倒你。
如果你還想繼續(xù)學(xué)習(xí)Unreal Engine 4引擎,點(diǎn)擊下篇教程,我會(huì)進(jìn)一步講解Unreal Engine 4引擎的材質(zhì)系統(tǒng)。