開發
本文皆在教您如何對 DDNet 開發 ,因為這是一款開源遊戲(原始碼公開),它依賴於一些善良的人們在空餘時間的貢獻。
開發環境
截至目前,基於以下原因,我們強烈推薦使用Linux系統進行DDNet開發:
- 大多數DDNet貢獻者使用Linux,使用Linux與之前的開發者交流起來更加方便。
- 軟件包管理更簡單,您可以輕鬆地安裝所有需要的庫。
- 本文專注於Linux,還沒有涉及Windows。
首先,DDNet由 C++ 語言編寫,開發者需要對它相當熟悉,但您也可以在只有基礎知識的情況下慢慢學習深入。
學習C++的一些有用資源:
- learncpp.com
- cppreference.com
- 瀏覽器搜素引擎。
DDNet的原始碼使用Git託管,這是一個版本控制系統,也是與多人協作開發的重要工具。
如果您的Linux發行版中還沒有git,請安裝它,例如在大多數基於debian/ubuntu的發行版中,您可以打開終端,輸入:sudo-apt-install git
。
獲取原始碼
原始碼位於Github,您沒有帳戶的情況下可以通過Clone獲得原始碼,但如果想更改官方原始碼,則需要登錄賬號。
如果您不熟悉git/github,可以在這裏學習基礎知識: Hello World - Github
安裝依賴項
如果您在Linux上,您可以通過閱讀DDNet github頁面上的自述文件來安裝所有需要的依賴項:https://github.com/ddnet/ddnet#dependencies-在linux上--macos
對於Arch Linux:
控制台輸入
sudo pacman -S --needed base-devel cmake curl ffmpeg freetype2 git glew glslang gmock libnotify libpng opusfile python rust sdl2 spirv-tools sqlite vulkan-headers vulkan-icd-loader wavpack x264
對於Debian:
控制台輸入
sudo apt install build-essential cargo cmake git glslang-tools google-mock libavcodec-extra libavdevice-dev libavfilter-dev libavformat-dev libavutil-dev libcurl4-openssl-dev libfreetype6-dev libglew-dev libnotify-dev libogg-dev libopus-dev libopusfile-dev libpng-dev libsdl2-dev libsqlite3-dev libssl-dev libvulkan-dev libwavpack-dev libx264-dev python rustc spirv-tools4
編譯DDNet
我們使用CMake來控制編譯進程,如果你安裝完成所有的依賴項,之後只需要簡單輸入這些命令(確保你在DDNet文件夾下):
mkdir build
cd build
cmake ..
make -j$(nproc)
基本信息
以下是一些基本信息:
- 目前,原始碼是使用C++17標準編譯的,但您會看到代碼的許多部分更像C,因為只有大多數新代碼使用C++17。
std::string
很少使用,字符數組加system.h
方法才是常態。- 大多數輸入輸出代碼、格式化和Print都是使用
system.h
提供的方法完成的。
原始碼佈局
現在你可以構建DDNet並開始編輯它了。
src/base 目錄
由於DDNet是一個跨平台遊戲,需要一個抽象層來簡化開發,因此該目錄包含許多有用的函數來處理這一問題。
src/engine 目錄
遊戲引擎所在位置,它處理大多數與玩法無關的東西,比如圖形、聲音、網絡等。
src/game 目錄
所有玩法的代碼所在位置,分為客戶端和伺服器。
伺服器端
這個遊戲使用自己的面向對象的實體分級系統,所有其他實體源於主類CEntity
,位於src/game/server/e
ntity.h
目錄。
遊戲世界在src/game/server/gameworld.h
路徑下,管理這些實體。
一些重要實體有:
- CCharacter: 代表一個活着的Tee , 當一個Tee生成時會被實例化,當它死亡時會被刪除。有關玩家在死亡之間的信息,請參閱CPlayer。
客戶端
客戶端由許多組件構成,都是繼承CComponent
的類:這些組件通過實現視覺方法來提供功能,例如OnInit
,OnMessage
等等。
網絡
網絡協議幾乎由python腳本生成並輸出c++代碼,例如說,datasrc/network.py
定義了所有網絡包。
代碼規範
代碼規範的討論還在持續:ddnet#2945
目前已經應用了下面的部分:
縮進格式
採用Allman 風格。
此風格將控制語句關聯的大括號放在下一行並且縮進到相同位置,內部語句則縮進到下一級。
while(x == y)
{
Something();
SomethingElse();
}
FinalThing();
類和結構體
必須帶有前綴C
(由於歷史遺留原因有一些結構體沒有遵循,例如圖形代碼部分)或者代表接口的I
。新的結構體需要帶前綴S
。
示例:
class CCharacter : public CEntity
{
// ...
}
枚舉和常量
應該採用大蛇式命名法(所有單詞大寫並且用下劃線間隔),例如MAX_PLAYERS
enum
{
FAKETUNE_FREEZE = 1,
FAKETUNE_SOLO = 2,
FAKETUNE_NOJUMP = 4,
FAKETUNE_NOCOLL = 8,
FAKETUNE_NOHOOK = 16,
FAKETUNE_JETPACK = 32,
FAKETUNE_NOHAMMER = 64,
};
變量命名
- 變量命名有三個部分:修飾和前綴、名字。
- 變量命名應該以大寫字母開始,除非是單字符例如:
i
,x
,y
。 - 變量可以有多於一個的修飾或前綴,也可以沒有。
排列方式:[修饰]_[前缀][名字]
修飾
- 成員變量
m
:m_MyVariable
。 - 靜態變量
s
:s_MyStaticVariable
,ms_MyStaticMemberVariable
。 - 帶外部連接的全局變量
g
:gs_MyGlobalStaticVar
。
前綴
- 指針前綴
p
:pMyPointer
,m_pCharacter
,ppMyPointerToPointer
。 - 數組前綴
a
:aMyArray
,aBuf
。 - 容器(
std::vector
)前綴v
:vMyVector
,vpvMyVectorOfPointersToVectors
。 - 函數前綴
fn
:pfnMyCallback
,m_papfnMyPointerToArrayOfCallbacks
。
常用片段
下面列出經常出現在代碼庫的代碼:
格式文本
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "number: %d", 2);
參閱printf 文檔查看格式提示符列表。
全玩家迭代
for(int i = 0; i < MAX_CLIENTS; i++)
{
// Server-side
CPlayer *pPlayer = GameServer()->m_apPlayers[i];
}
輸出到遊戲控制台
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "wikiprint", "Hello from the ddnet wiki!");
輸出調試結果
int i = 2;
dbg_msg("wikiprint", "Hello from the ddnet wiki: %d", i);
在客戶端翻譯文本
Localize
用於在遊戲客戶端從用戶選定的語言文件中獲取特定字串的翻譯。
DoButton(..., Localize("Connect"), ...);
字符串可以包含格式說明符,翻譯文本必須包含同樣的格式說明符(這可能產生某些排序不一致的問題)。
char aBuf[128];
str_format(aBuf, sizeof(aBuf), Localize("%d of %d servers"), NumServers, TotalServers);
在調用Localize
時依靠一個腳本來掃描識別調用代碼,然後收集字符串上傳翻譯文件。由於此原因,調用Localize
不能包含任何其他代碼,否則腳本無法正確識別文本。
// 请勿这样做:
const char *pStr = Localize(Team == TEAM_RED ? "Red team" : "Blue team");
// 应该这样做:
const char *pStr = Team == TEAM_RED ? Localize("Red team") : Localize("Blue team");
外部資料
- UI Code in DDraceNetwork by Ryozuki
- An intro to the DDraceNetwork game source code by Ryozuki
- Code conventions in DDraceNetwork by Ryozuki
- Implementing a chat command in DDraceNetwork by Ryozuki
- Auto generated docs
- Technical documentation of Teeworlds file formats and network protocol
- The Anatomy of a One Tick Unfreeze
- Teeworlds programming YouTube tutorial by ChillerDragon