建立測試專案
接上文的準備工作,雙擊生成的UE4Editor.exe,選擇建立測試C++空專案Hello(以後的原始碼分析都會基於該最簡單的專案)
專案檔案結構
VS專案和檔案目錄:
可以看到,Config目錄裡帶著3個最主要的配置,Editor,Engine,Game。程式碼方面自動生成了用於編譯系統的3個.cs檔案,C++程式碼方面生成了一個Hello "Game Module",和HelloGameMode。
檔案目錄:
- Binaries:存放編譯生成的結果二進位制檔案。該目錄可以gitignore,反正每次都會生成。
- Config:配置檔案。
- Content:平常最常用到,所有的資源和藍圖等都放在該目錄裡。
- DerivedDataCache:“DDC”,儲存著引擎針對平臺特化後的資源版本。比如同一個圖片,針對不同的平臺有不同的適合格式,這個時候就可以在不動原始的uasset的基礎上,比較輕易的再生成不同格式資源版本。gitignore。
- Intermediate:中間檔案(gitignore),存放著一些臨時生成的檔案。有:
- Build的中間檔案,.obj和預編譯頭等
- UHT預處理生成的.generated.h/.cpp檔案
- VS.vcxproj專案檔案,可通過.uproject檔案生成編譯生成的Shader檔案。
- AssetRegistryCache:Asset Registry系統的快取檔案,Asset Registry可以簡單理解為一個索引了所有uasset資源頭資訊的登錄檔。CachedAssetRegistry.bin檔案也是如此。
- Saved:儲存自動儲存檔案,其他配置檔案,日誌檔案,引擎崩潰日誌,硬體資訊,烘培資訊資料等。gitignore
- Source:程式碼檔案。
編譯型別
很多人在使用UE4的時候,往往只是依照預設的DevelopmentEditor,但實際上編譯選項是非常重要的。
UE4本身包含網路模式和編輯器,這意味著你的工程在部署的時候將包含Server和Client,而在開發的時候,也將有Editor和Stand-alone之分;同時你也可以單獨選擇是否為Engine和Game生成除錯資訊,接著你還可以選擇是否在遊戲裡內嵌控制檯等。
依照官方介紹
每種編譯配置包含兩種關鍵字。第一種表明了引擎以及遊戲專案的狀態。第二個關鍵字表明正在編譯的目標。
狀態 | Engine | Game | 其他 |
---|---|---|---|
Debug (除錯) | Debug | Debug | 必須在編輯器上加-debug引數才能反射檢視程式碼更改 |
DebugGame (除錯遊戲) | Release | Debug | 適合只除錯遊戲程式碼 |
Development (開發) | Release | Release | 允許編輯器反射檢視程式碼更改 |
Shipping (發行) | Release | Release | 無控制檯命令,統計資料和效能分析 |
Test (測試) | Release | Release | 啟用了一些控制檯命令,統計資料和效能分析 |
目標 | 描述 |
---|---|
[empty] (空白) | 不帶編輯器的一個獨立可執行版本,需要提前打包烘培內容資源 |
Editor (編輯器) | 直接在編輯器裡開啟遊戲專案 |
Client (客戶端) | 多人聯機專案,生成客戶端版本,需要提供 <Game>Client.Target.cs 檔案 |
Server (伺服器) | 多人聯機專案,生成伺服器版本,需要提供 <Game>Server.Target.cs 檔案 |
組合的各種情況:
Debug | DebugGame | Development | Shipping | Test | ||
---|---|---|---|---|---|---|
[empty] | ✓ | ✓ | ✓ | ✓ | ✓ | |
Editor | ✓ | ✓ | ✓ | |||
Client | ✓ | ✓ | ✓ | ✓ | ✓ | |
Server | ✓ | ✓ | ✓ | ✓ | ✓ |
所以為了我們的除錯程式碼方便,我們選擇DebugEditor來載入遊戲專案,當需要最簡化流程的時候用Debug來執行獨立版本。
命名約定
客觀來說,相比其他引擎的原始碼,UE4的原始碼還是非常清晰的,模組組織也比較明瞭。但閱讀原始碼的學習曲線依然陡峭,我想有以下原因:
- UE4包含的模組眾多,攏共有幾十個模組,雖然採用了Module架構來解耦,但難免還是要有依賴交叉的地方,在閱讀的時候就很難理清各部分的關係。
- UE4的功能優秀,作為業界頂尖的成熟遊戲引擎,在一些具體的模組內部實現上就脫離了簡單粗暴,而是採用了各種設計模式和權衡。同時也需要閱讀的人有相關的業務知識。比如材質編輯器編譯生成Shader的過程就需要讀者擁有至少差不多的圖形學知識。
- 被魔改後的C++,UE4為了各平臺的編譯和其他考量(具體以後說到編譯系統的時候再細討論),對標準的C++和編譯,進行了相當程度的改造,在UHT程式碼生成和各種巨集的巢狀之後,讀者就很難一下子看清背後的各種的機制了。
但萬丈高樓平地起,我們們也可以從最簡單的一步步開始學起,直到了解掌握整個引擎的內部結構。
在閱讀程式碼之前,就必須去了解一下UE4的命名約定,具體的自己去檢視官網文件,下面是一些基本需要知道的:
- 模版類以T作為字首,比如TArray,TMap,TSet
- UObject派生類都以U字首
- AActor派生類都以A字首
- SWidget派生類都以S字首
- 抽象介面以I字首
- 列舉以E開頭
- bool變數以b字首,如bPendingDestruction
- 其他的大部分以F開頭,如FString,FName
- typedef的以原型名字首為準,如typedef TArray
FArrayOfMyTypes; - 在編輯器裡和C#裡,型別名是去掉字首過的
- UHT在工作的時候需要你提供正確的字首,所以雖然說是約定,但你也得必須遵守。(編譯系統怎麼用到那些字首,後續再討論)
- 在討論某個類的時候,如果我加上字首,代表我想強調這個類的繼承體系,否則就只關注這個類本身。如AController代表我想強調它從Actor繼承下來,而Controller代表我只想討論這個概念本身。
基礎概念
和其他的3D引擎一樣,UE4也有其特有的描述遊戲世界的概念。在UE4中,幾乎所有的物件都繼承於UObject(跟Java,C#一樣),UObject為它們提供了基礎的垃圾回收,反射,後設資料,序列化等,相應的,就有各種"UClass"的派生們定義了屬性和行為的資料。
跟Unity(GameObject-Component)有些像的是,UE4也採用了元件式的架構,但細品起來卻又有些不一樣。在UE中,3D世界是由Actors構建起來的,而Actor又擁有各種Component,之後又有各種Controller可以控制Actor(Pawn)的行為。Unity中的Prefab,在UE4中變成了BlueprintClass,其實Class的概念確實更加貼近C++的底層一些。
Unity中,你可以為一個GameObject新增一個ScriptComponent,然後繼承MonoBehaviour來編寫遊戲邏輯。在UE4中,你也可以為一個Actor新增一個藍圖或者C++ Component,然後實現它來直接組織邏輯。
UE4也支援各種外掛。
其他的下篇再一一細說。
編譯系統
UE4支援眾多平臺,包括Windows,IOS,Android等,因此UE4為了方便你配置各個平臺的引數和編譯選項,簡化編譯流程,UE4實現了自己的一套編譯系統,否則我們就得接受各個平臺再單獨配置一套專案之苦了。
這套工具的編譯流程結果,簡單來說,就是你在VS裡的執行,背後會執行UE4的一些命令列工具來完成編譯,其他最重要的兩個元件:
UnrealBuildTool(UBT,C#):UE4的自定義工具,來編譯UE4的逐個模組並處理依賴等。我們編寫的Target.cs,Build.cs都是為這個工具服務的。
UnrealHeaderTool (UHT,C++):UE4的C++程式碼解析生成工具,我們在程式碼裡寫的那些巨集UCLASS等和#include "*.generated.h"都為UHT提供了資訊來生成相應的C++反射程式碼。
一般來說,UBT會先呼叫UHT會先負責解析一遍C++程式碼,生成相應其他程式碼。然後開始呼叫平臺特定的編譯工具(VisualStudio,LLVM)來編譯各個模組。最後啟動Editor或者是Game.
更細的留待“編譯系統”再細細討論
引用
知乎專欄:InsideUE4
UE4深入學習QQ群: 456247757(非新手入門群,請先學習完官方文件和視訊教程)
個人原創,未經授權,謝絕轉載!