2019-07-22 UE4《吃豆人-上》

最近學習虛幻4,先跟著教程學習做個《吃豆人》小游戲,熟悉下引擎里的一些基本概念。

下面回顧一下學習過程。

引擎版本:4.22
visual studio 2019

一、新建項目

啟動引擎后,新建C++基礎項目,包含初學者資源,最后點擊創建項目就可以了。

新建項目

二、新建關卡和地形

選擇 文件->新建關卡 或者 Ctrl+N 呼出新建關卡對話框,選擇Default,這樣就創建好一個默認關卡了。

首先先將默認地板刪掉,然后在左側的模式面板-放置頁簽-Geometry分類下選擇Box,拖拽到場景中,然后在右側的細節面板下找到Brush Settings,將x改為2700,y改為2100,z改為100(為什么?因為喜歡)。這樣就創建好一個地板了。

然后找一張吃豆人的截圖,或者自由發揮,用Box畫刷再造一些墻體,大概就這樣

地形

? ? 最后別忘了保存關卡。

三、美化地形

這個黑白花的地形看起來過于迷惑,趕緊給加上材質。

在右側的世界大綱視圖中,找一個地形的畫刷,右鍵->選擇->選擇所有表面,然后從下面Content Browser中的StarterContent->Materials下挑選一個材質(這個StarterContent就是創建項目時選擇的初學者內容),將材質拖拽給右側細節面板的“表面材質”。這樣就不是黑白花了。

但是我想讓墻和地板的樣子看上去不同,怎么搞?這就簡單了,直接在場景中單擊地板,地板的細節面板已經有了“表面材質”一項,把ContentBrowser下的任意材質拖上去就可以了。

加了材質的地形

四、添加道具

這個游戲唯一的道具就只有豆子了吧。

文件->新建C++類 在彈出的對話框中選擇父類為“Actor”,然后起個類名“Bean”,設置為公有,創建完成。

新建豆子類

因為選擇了新建“公有”類,所以頭文件會被放到Public文件夾下,因此需要修改引入的頭文件路徑,不然會找不到頭文件。在前面加上 Public/ 即可。

在頭文件中有個 #include “XXX.generated.h” ,由于框架的限制,這句一定要放到最后引用

.h文件

而在cpp文件中,對當前類的頭文件的引用,卻要放在最前面

.cpp文件

這里有兩個自動生成的生命周期方法,BeginPlay 和 Tick。要理解一個新框架,了解他的生命周期方法是很重要的,之后會找個時間專門學習生命周期方法,現在只看這兩個。

BeginPlay 是當對象被添加到場景中時調用的,如果想獲取一些在運行時才有的信息,并且要根據獲取的信息在自己出場前進行調整,寫在這個方法中就是最好的選擇。

Tick 這是對象的自更新方法,需要使用?PrimaryActorTick.bCanEverTick = true; 來開啟,開啟后每一幀都會調用此方法。

現在這個豆子放到場景中還只是一個虛無的靈魂,接下來要給它加上表象和實體。

在頭文件中引入"Components/SphereComponent.h"和"Components/StaticMeshComponent.h",記住一定要放在 generated.h 前面。然后聲明兩個變量
USphereComponent* BeanShape;
UStaticMeshComponent* BeanMesh;

UStaticMeshComponent繼承自?UMeshComponent ,用來表示豆子的外貌,用戶可以看見的樣子。
USphereComponent 繼承自?UShapeComponent ,用來表示豆子的實體形狀,是不可見的,但其實這才是本體,參與碰撞檢測。

接下來在構造方法中實例化他們。實例化有兩種方式 UObject::CreateDefaultSubobject 和 NewObject 。如果想在c++編譯時生成,在ue編輯器中可見的話,就要使用UObject::CreateDefaultSubobject,如果在游戲運行后才需要生成,使用NewObject,這里我們用CreateDefaultSubobject。

實例化碰撞體和網格

這里用球形表示豆子了,為了讓豆子的表象和本體一致,需要讓網格也像個球。

先引入"UObject/ConstructorHelpers.h",記得要在"Public/Bean.h"之后引入。

然后使用ConstructorHelpers::FObjectFinder<UStaticMesh> 創建一個網格,創建時需要傳入網格資源的路徑,首先切換到虛幻4編輯器,在新手資源中有個Shapes文件夾,在里面找到球,然后右鍵->復制引用

獲取資源路徑

將復制好的路徑字符串傳給網格對象的構造方法,就可以了。最后還要判斷網格獲取是否成功,因為可能會有資源損壞或者丟失的情況,為了避免空指針錯誤,增強程序的健壯性,這是很有必要的。如果成功獲取,就將獲取的網格設置給BeanMesh。

設置網格

切換到虛幻4編輯器,點擊編譯,編譯完成后在ContentBrowser下C++類中找到剛才新建的Bean,拖拽到場景中。這樣就在場景中添加好一個由C++創建的對象了。

但是通過觀察我們發現,這個對象的Mesh和Sphere的大小和位置是不匹配的,因此還需要進行調整

Bean的Mesh(上)和Shape(下)

這個調起來可就麻煩了,需要在代碼中修改位置,再重新編譯,再重新加到場景中看效果,效果不行再重復修改代碼。。。當然不會是這樣,我們首先在BeanMesh和BeanShape聲明的時候,加上UPROPERTY,讓這兩個屬性再UE4編輯器中可見。

添加UPROPERTY

然后保存編譯,在ContentBrowser中找到Bean的C++類,右鍵->創建基于Bean的藍圖類,起個名字BP_Bean,確定進入藍圖編輯界面。

球網格的默認大小是直徑100,我的地形創建的路寬也是100,有點大,縮小一些。先選中白色球體,在細節面板下找到Transform->Scale 都改成0.3,這樣就是直徑30的球了。

再選中紅線構成的Shape,將半徑改成15,這樣就一樣大了。

再選中白色球體,將z坐標調成 -15,終于靈魂與肉體合而為一,完全重合了。

最后別忘了編譯和保存藍圖

藍圖

將創建好的藍圖拖拽到場景中,調整下位置就好了。只是有點丑。

所以我們來給他點顏色,新建個文件夾,這里起名Materials,在里面右鍵->新建材質

新建材質

起名M_Bean,雙擊打開,彈出材質面板。

在空白處按住V鍵點鼠標左鍵,注意是左鍵,彈出一個小面板,將白色點連接到Base Color,再雙擊黑色區域彈出顏色板,調出豆子的顏色

材質編輯

保存后在場景中選中豆子,將剛剛編輯好的材質拖拽到豆子的 細節面板->Materials->BeanMesh 上,豆子就變色啦。不過,再拖一個豆子藍圖進來,還是白色的,想要拖進來的也是黃色,就需要更改藍圖,將藍圖的BeanMesh設置為M_Bean

這個豆子傻傻的一動不動,這樣是沒有靈魂的,他不是有個自更新函數嗎,我們可以讓他動起來的,這個比較簡單,用sin函數和DeltaTime的累計值去計算一個偏移量,加在原始位置上就可以平滑的上下漂浮了。但是考慮到滿屏幕幾百個豆子,動起來都一個節奏,也挺怪異的,所以我又用隨機數給他一個初始的Timer值。

豆子漂浮邏輯

編譯后在場景中再拖入幾個豆子藍圖,點擊播放

豆子漂浮效果

可以,下面可以用豆子鋪滿整個場景了。因為這里豆子的初始Z值都是相同的,建議使用頂端視圖來進行操作

切換到頂端視口

這個體力活做完大概是這樣

全道具頂視圖

五、創建玩家

新建一個C++文件,繼承Character,起名PacmanPlayer。

相比豆子類,多了一個方法?SetupPlayerInputComponent 。這是干什么用的呢?這也是個由框架調用的方法,會傳入一個UInputComponent參數,我們可以通過這個參數來綁定用戶的輸入事件和Character的響應函數。

如何綁定用戶輸入事件?首先,切換到UE4,打開 編輯->項目設置 ,然后找到 引擎->輸入 ,點擊輸入后在右側找到Bindings,可以看到兩個映射

自定義輸入事件

其中 Action Mappings 表示點擊或抬起時會觸發的事件,Axis Mappings 表示按住就會連續觸發的事件,這里想按住方向鍵讓玩家一直走,所以選擇第二種。

新建兩個移動事件 moveX 和 moveY 。通過觀察場景中的Player Start可以知道,X軸的正方向是前,Y軸的正方向是右。因此,用A、D鍵表示左右移動,W、S鍵表示上下移動。

場景中的Player Start


添加軸映射事件

回到Visual studio,在PacmanPlayer中聲明一個 FVector 對象,用來表示移動的方向。聲明兩個函數,用來綁定moveX和moveY事件。

具體實現如下

綁定移動事件

虛幻4有個強大功能,除了用C++編寫游戲,還能用藍圖編寫游戲。之前的豆子用C++設置了外形,這次我們使用藍圖來創建玩家的形象。

先創建基于PacmanPlayer的藍圖,在左上角的Components標簽下找到AddComponent,添加一個Sphere(沒錯,玩家也是個球。。)然后設置球的Scale為0.8,玩家大概就是一個直徑80的球了。這里有個默認的碰撞體,是膠囊狀的,把他的高和半徑改成40,就神形合一了。當然,別忘了在藍圖的細節面板中給球換個材質

Pacman藍圖

接下來打開C++類下的Pacman文件夾,找到一個PacmanGameModeBase文件。這是用來定義游戲模式的,可以在里面進行涉及游戲性的各種設定。我們找他是為了設置玩家為剛剛創建的BP_PacmanPlayer。

藍圖真香,完全不想寫代碼了。創建個基于PacmanGameModeBase的藍圖,在里面找到細節面板的Classed下的Default Pawn Class ,把值改為PacmanPlayer的藍圖類

游戲模式藍圖

編譯保存后,再打開 項目設置 ,找到 項目->地圖&模式->Default Modes 將Default Game Mode改為剛剛創建的游戲模式藍圖。

*也可在在這里更改Default Maps為新創建的關卡,這樣下次打開項目時,就不是那兩把椅子的關卡啦。

設置默認游戲模式

這時在播放游戲,就可以用剛剛設置的按鍵來控制主角移動了。但是這是第一人稱視角,而吃豆游戲是上帝視角的。

所以我們來創建一個上帝視角的攝像機。

首先在左側模式面板下搜索Camera,然后將攝像機拖到場景中,就會在場景右下放展示出攝像機的視角,通過對攝像機的旋轉和平移,調整好視角。

在場景面板上面的按鈕中,找到藍圖Blueprints,在里面選擇打開關卡藍圖

添加攝像機&編輯關卡藍圖

我們雖然生成了上帝視角攝像機,但是并沒有設置給游戲,打開關卡藍圖就是要設置攝像機的。

是不是又看到了熟悉的 BeginPlay 和 Tick ?沒錯,藍圖就是代碼的另一種表象形式。

確保你的攝像機是選中狀態,然后在關卡藍圖中右鍵就會出現“創建一個到Camera Actor的引用”選項,點擊就創建了這個攝像機的引用。

我們要把攝像機給玩家,所以還要獲取玩家控制器的引用,右鍵,搜素Get Player Controller。

我們拿到攝像機和控制器之后,還要拿到一個把攝像機設置給控制器的函數,右鍵搜素 Set View Target With Blend。

接下來我們要開始做連線題了。

設置攝像機這個事情,在什么時候觸發呢?在進入場景時,因此嗎BeginPlay的右箭頭連到Set View Target With Blend的左箭頭。

設置方法是由誰來調用呢?由player Controller調用,因此將Get Player Controller的返回值連接到Set View Target With Blend的Target。

最后要設置誰為新的ViewTarget呢?就是我們新創建的攝像機了。將Camera Actor連接到New View Target。

編譯保存

設置默認攝像機

這是在播放游戲,就是上帝視角了。

游戲播放截圖

然后發現豆子是不能吃的。那我們接下來就做吃豆子.

切換到Visual Studio,打開PacmanPlayer,因為Character默認的碰撞體是個膠囊體,那我們就在BeginPlay中獲取膠囊體組件,給他設置一個碰撞監聽。

碰撞監聽有兩種,Hit 和?Overlap。Hit 適用于物理碰撞,例如走路撞到石頭。Overlap 是區域重疊,例如走進一個魔法陣。我們這里不希望豆子被玩家撞飛,也不需要影響玩家行動,所以使用了Overlap。

可能需要先include膠囊體組件。然后用GetCapsuleComponent獲取膠囊體,用里面的OnComponentOverlap對象.AddDynamic來添加監聽器,但是監聽器的定義是什么樣的呢?我們Ctrl點進OnComponentOverlap,發現他是個FComponentBeginOverlapSignature類型的對象點,進這個類又看到一個宏DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams,再點進這個宏......對不起打擾了。回到上一頁,可以看出這個監聽器是需要6個參數的,后面已經列出了參數類型,抄一份走。

在PacmanPlayer中聲明一個碰撞監聽函數,叫OnCollision,形參就是剛復制來的6個參數,很重要的一點是,要在這個函數上一行寫上UFUNCTION(),不然運行時會提示錯誤。然后在cpp中實現他,并將這個函數綁給膠囊體組件。

注冊碰撞監聽

接下來實現碰撞監聽。先判斷是誰撞過來了,如果是豆子,就吃掉他。需要先include豆子類。

碰撞邏輯

修改碰撞預設值。

打開項目設置->引擎->Collision ,新建兩個對象通道,起名 Bean 和 Pacman 。然后展開Preset列表,新建兩個描述文件,同樣起名Bean和Pacman,對象類型選擇剛剛新建的兩個對象通道。注意把Bean描述文件的碰撞響應中的Pacman勾選為Overlap,同樣Pacman中的Bean也勾選為Overlap。

Pacman描述文件
Bean描述文件

然后分別打開Pacman和Bean的藍圖,選中碰撞體(這里Pacman是Capsule,Bean是Sphere),在細節面板中找到Collision,將碰撞預設值改為剛剛新建的描述文件Pacman和Bean

修改碰撞預設值

點擊播放,就可以吃豆了

吃豆

六、添加敵人

在原游戲中,中間的空地是給敵人的出生點,所以這里先把玩家移到他該在的位置。選擇一個適合的位置,把Player Start移過去。

圈地

這個地方看著不錯,就在這挖個空地當玩家出生點吧。選擇Box畫刷,勾選下面的挖空型,然后去墻上打洞就可以了。

挖空型畫刷

為敵人新建幾不同顏色的材質M_Enemy1~4,新建一個敵人碰撞通道Enemy,設置敵人與敵人,敵人與豆子之間的碰撞響應為忽略。

新建敵人類Enemy繼承Character,在頭文件中聲明一個UstaticMeshComponent對象來定義敵人的形象,加上UPROPERTY(EditAnywhere)以便在UE4中調整他。因為敵人在玩家吃到超級豆子后,會有冰凍減速的效果,所以再聲明兩個UMaterialInterface對象,用來更換敵人的材質。這次我們把敵人設置為圓柱體的形象。

圓柱體的敵人

新建敵人的藍圖,調整好Mesh和Shape的大小,設置好碰撞通道,就可以把敵人拖進場景了,然后給他們加上不同的材質。

添加敵人

再回到C++,在構造方法中用ConstructHelpers找到冰凍材質賦值給EnemyMaterialIce

在BeginPlay中用EnemyMesh->GetMaterial(0) 獲取當前的材質,賦值給EnemyMaterialNormal

獲取材質

超級豆、敵人攻擊、被攻擊的事情先放一放,我們先讓這個敵人走動起來。

要讓敵人自動尋路,首先添加個導航網格。在 模式->體積 下找到Nav Mesh Bounds Volume,拖拽到場景中。調整尺寸,跟地圖一樣大(x:2700,y:2100,z:20),按P鍵顯示導航。綠色的就是可到達的范圍,一開始可能不會太順利,我反復調整了導航網格的高度和位置,還在項目設置->引擎->導航網格物體->Generation 下調整了Cell Size 和Cell Height,最終才得到想要的效果。

反復調整導航網格

可以先編輯敵人的藍圖,對網格做個簡單的測試。如果敵人不能移動,可以將玩家,敵人,地板,網格的Z坐標升高,避開一切障礙物再測試。動了就說明邏輯沒問題,需要繼續調整參數。。。

敵人跟隨玩家的測試邏輯

測試沒問題后刪掉新增的4個邏輯塊,我們用C++來實現敵人的移動。

新建C++類EnemyAIController,繼承AIController,選擇父類時找不到這個類可以點擊右上角的“顯示所有類”然后搜素AIController

然后打開項目的Pacman.Build.cs 文件,在PublicDependencyModuleNames 的Range里追加一個 “NavigationSystem” 。在4.22版本是需要手動引入導航系統模塊的。

接下來實現EnemyAIContorller,聲明一個SearchNextPosition函數,用來查找并移動到下一個目標點,重寫OnMoveCompleted方法,這是當移動完成時的回調,我們在這里繼續調用SearchNextPosition。

最后實現SearchNextPosition。

敵人AI控制器

接下來修改Enemy類

首先在構造方法中,設置將控制權自動交給AI控制器?AutoPossessAI = EAutoPossessAI::PlacedInWorldOrSpawned;

然后用反射的方式綁定AI控制器?AIControllerClass = AEnemyNewController::StaticClass();

最后,在BeginPlay中獲取控制器,并開始移動。

給敵人添加AIController

保存、編譯、播放,敵人已經開始四處亂竄了。注意敵人與敵人,敵人與豆子之間的碰撞響應要設為忽略,不然他們會撞到一起的。

動起來的敵人

七、走向勝利

沒想到已經寫了這么多,這篇日記就先到這里吧,下篇接著寫。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。