Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

常見引擎方法與巨集

Godot 的 C++ 原始碼中使用了數十種自定方法與巨集,且幾乎所有檔案中都有用到。本頁主要是提供給剛開始參與貢獻的人看,但對於撰寫自定 C++ 模組的人來說應該也很實用。

格式化字串

vformat() 函式會回傳經過格式化的 String 。其行為與 C 的 sprintf() 類似:

vformat("My name is %s.", "Godette");
vformat("%d bugs on the wall!", 1234);
vformat("Pi is approximately %f.", 3.1416);

// Converts the resulting String into a `const char *`.
// You may need to do this if passing the result as an argument
// to a method that expects a `const char *` instead of a String.
vformat("My name is %s.", "Godette").c_str();

大多數情況下,使用 vformat() 來代替字串串接可以提升程式碼的可讀性。

將整數或浮點數轉為字串

使用 print_line() 列印數字時不需要這樣做,但您可能仍需要對其他一些用例執行手動轉換。

// Stores the string "42" using integer-to-string conversion.
String int_to_string = itos(42);

// Stores the string "123.45" using real-to-string conversion.
String real_to_string = rtos(123.45);

在地化字串

在 Godot 的程式碼中有兩種方法來進行在地化:

  • TTR(): 編輯器 ("Tools") 翻譯 - Tools TRanslation 只能在編輯器中實用。若使用者在專案中使用了相同的文字,若沒有提供用於該文字的翻譯,就不會被翻譯。在參與引擎貢獻時,用來翻譯字串的巨集通常都是這個。

  • RTR(): 執行階段翻譯 - Run-time TRanslations 檔有提供給定字串的翻譯時,會在專案內自動翻譯。這種翻譯通常不會用在編輯器程式碼內。

// Returns the translated string that matches the user's locale settings.
// Translations are located in `editor/translations`.
// The localization template is generated automatically; don't modify it.
TTR("Exit the editor?");

若要在可翻譯字串內插入預留位置,請如下範例以 vformat() 呼叫包住在地化巨集:

String file_path = "example.txt";
vformat(TTR("Couldn't open \"%s\" for reading."), file_path);

備註

當將 vformat() 與翻譯巨集一起使用時,請務必將翻譯巨集包在 vformat() 內,而不要反過來。否則產生的字串永遠不會有對應的翻譯,因為在傳給 TranslationServer 時,字串的預留位置已經被換掉了。

鉗制數值

Godot 提供了用來將數值鉗制在最小值 (MAX) 與最大值 (MIN) 以及同時鉗制 (CLAMP) 的巨集:

int a = 3;
int b = 5;

MAX(b, 6); // 6
MIN(2, a); // 2
CLAMP(a, 10, 30); // 10

這幾個巨集可以用在所有能互相比較的型別內 (如 intfloat)。

微型效能評定 (Microbenchmarking)

若想對一小部分的程式碼進行效能評定,但不知道要如何實用分析工具,則可以使用下列程式碼片段:

uint64_t begin = OS::get_singleton()->get_ticks_usec();

// Your code here...

uint64_t end = OS::get_singleton()->get_ticks_usec();
print_line(vformat("Snippet took %d microseconds", end - begin));

這個程式會印出介於 begin 宣告與 end 宣告間所花費的時間。

備註

若程式碼中沒有 #include "core/os/os.h" ,則需要包含這行程式。

如果一開始沒有這段程式碼的話,請確定在開啟 Pull Request 時有移除這段程式。

取得專案或編輯器設定

有四種可用於取得設定的巨集:

// Returns the specified project setting's value,
// defaulting to `false` if it doesn't exist.
GLOBAL_DEF("section/subsection/value", false);

// Returns the specified editor setting's value,
// defaulting to "Untitled" if it doesn't exist.
EDITOR_DEF("section/subsection/value", "Untitled");

如果有在其他地方指定預設值的話,則請不要指定預設值以避免重複:

// Returns the value of the project setting.
GLOBAL_GET("section/subsection/value");
// Returns the value of the editor setting.
EDITOR_GET("section/subsection/value");

建議每個設定只使用一次 GLOBAL_DEF/EDITOR_DEF ,然後在其他參照的地方使用 GLOBAL_GET/EDITOR_GET

錯誤巨集

Godot 提供了許多能讓錯誤回報更方便的錯誤巨集。

警告

在錯誤巨集中的條件式與 GDScript 的內建 assert() 函式運作的方法 相反 。錯誤會在其中的條件式為 true 時跑出,而非 false

備註

這裡只寫了幾種自定訊息的變體,因為我們建議所有新的貢獻者都應該只使用這些型別的訊息。請確保自定訊息有包含足夠的訊息來讓使用者即使不瞭解 C++ 也能診斷問題。當將無效的參數傳給某個方法時,可以將無效的值印出以讓除錯過程更簡單。

對於不需要顯示人類可讀取訊息的內部錯誤檢查,可以移除巨集後方的 _MSG ,然後不提供訊息參數。

另外,也請務必回傳可處理的資料,以讓引擎繼續執行。

// Conditionally prints an error message and returns from the function.
// Use this in methods which don't return a value.
ERR_FAIL_COND_MSG(!mesh.is_valid(), vformat("Couldn't load mesh at: %s", path));

// Conditionally prints an error message and returns `0` from the function.
// Use this in methods which must return a value.
ERR_FAIL_COND_V_MSG(rect.x < 0 || rect.y < 0, 0,
        "Couldn't calculate the rectangle's area.");

// Prints an error message if `index` is < 0 or >= `SomeEnum::QUALITY_MAX`,
// then returns from the function.
ERR_FAIL_INDEX_MSG(index, SomeEnum::QUALITY_MAX,
        vformat("Invalid quality: %d. See SomeEnum for allowed values.", index));

// Prints an error message if `index` is < 0 >= `some_array.size()`,
// then returns `-1` from the function.
ERR_FAIL_INDEX_V_MSG(index, some_array.size(), -1,
        vformat("Item %d is out of bounds.", index));

// Unconditionally prints an error message and returns from the function.
// Only use this if you need to perform complex error checking.
if (!complex_error_checking_routine()) {
    ERR_FAIL_MSG("Couldn't reload the filesystem cache.");
}

// Unconditionally prints an error message and returns `false` from the function.
// Only use this if you need to perform complex error checking.
if (!complex_error_checking_routine()) {
    ERR_FAIL_V_MSG(false, "Couldn't parse the input arguments.");
}

// Crashes the engine. This should generally never be used
// except for testing crash handling code. Godot's philosophy
// is to never crash, both in the editor and in exported projects.
CRASH_NOW_MSG("Can't predict the future! Aborting.");

也參考

有關各個錯誤巨集的更多資訊,請參考 Godot 原始碼中的 core/error_macros.h

有些函式會回傳錯誤程式碼 (具體化為使用 Error 回傳型別)。該錯誤程式碼的值可以直接在錯誤巨集中回傳。有關可用的錯誤程式碼列表,請參考 core/error_list.h