代码风格规范

在给 Godot 的源代码做贡献时,你需要遵循下面概述的样式规范。其中一些是通过持续集成过程进行检查的,评审人员将要求你修复潜在的问题,因此最好按照下面概述的方式设置系统,以确保所有提交都遵循规范。

C++ 和 Objective-C

没有书面的规范,但是开发人员默认的代码风格是通过 clang-format 代码美化器强制执行的,它可以满足我们所有的约定。举几个例子:

  • 缩进和对齐都是基于制表符的(分别是一个和两个制表符)

  • 数学和赋值运算符以及逗号后面有一个空格

  • 指针和引用运算符附加到变量标识符,而不是类型名称

  • 有关头文件的引入,请参见下文

Clang 格式使用的规则在 Godot 仓库的 .clang-format 文件中进行了概述。

只要你确保你的样式与周围的代码匹配, 并且你没有引入尾随空格或基于空格的缩进, 就应该没问题. 但如果你计划定期贡献, 我们强烈建议你在本地设置clang-format以检查并自动修复所有提交.

警告

Godot的代码风格 不应该 适用于第三方代码, 即包含在Godot的源代码树中, 但不是专门为我们的项目编写的. 这样的代码通常来自不同的上游项目, 有他们自己的风格指南(或缺乏风格规则), 我们不想引入差异, 使其与上游仓库的同步更加困难.

第三方代码通常包含在 thirdparty/ 文件夹中, 因此可以很容易地从格式化脚本中排除. 在极少数情况下, 第三方代码片段需要直接包含在Godot文件中, 你可以使用 /* clang-format off *//* clang-format on */ 来告诉clang-format忽略某块儿的代码.

参见

这些规范只涉及代码的格式化。拉取请求中所允许的语言特性列表请参阅 C++ 使用规范

在本地使用 clang-format

首先,您需要安装 clang-format。截至目前,您需要使用 clang-format 13 才能与 Godot 的格式兼容。后续版本可能也能用,但更早的版本就可能无法支持所有用到的选项,或者使用不同的格式,导致拉取请求存在样式问题。

安装

以下是如何安装 clang-format:

  • Linux: 通常会随您的发行版打包的clang工具链一起提供. 如果您的分发版本不是必需的版本, 您可以从 LLVM 网站 下载预编译的版本, 或者, 如果您使用的是Debian衍生版本, 请使用 上游仓库.

  • macOS和Windows: 您可以从 LLVM 网站 下载预编译的二进制文件. 您可能需要将二进制文件的文件夹的路径添加到系统的 PATH 环境变量中, 以便能够直接调用 clang-format.

然后, 你就有不同的可能性将clang-format应用于你的更改:

手动使用

你可以使用以下命令手动将 clang-format 应用于一个或多个文件:

  1. clang-format -i <path/to/file(s)>
  • -i 表示更改应直接写入文件(默认情况下,clang-format只会将固定版本输出到终端).

  • 该路径可以指向几个文件, 一个接一个, 也可以使用如在典型的Unix shell中的通配符. 在通配时要小心, 以免对Godot树中的已编译对象(.o和.a文件)运行clang格式. 因此, 最好使用 core/*. {cpp,h} 而不是 core/*.

预提交钩子

为了易于使用, 我们为Git提供了一个预提交钩子, 它将在你的所有提交上自动运行clang-format来检查它们, 并允许你在最终提交中应用其更改.

这个“钩子”(hook)是一个可以在 misc/hooks 中找到的脚本,安装说明请参阅该文件夹的 README.md。

如果你的clang-format不在 PATH 中, 你可能需要编辑 pre-commit-clang-format 来指向正确的二进制格式才能工作. 钩子在Linux和macOS上测试过, 但也应该在Windows上的Git Shell中运行.

IDE插件

大多数IDE或代码编辑器都有美化插件, 可以配置为自动运行clang-format, 例如每次保存文件时.

以下是一些IDE的美化插件的非详尽列表:

(欢迎拉取请求以使用测试过的插件来扩展此列表.)

标头引入

当添加新的C++或Objective-C文件或在现有文件中引入新的标头时, 应遵循以下规则:

  • 文件中的第一行应该是Godot的版权标头和MIT许可证, 从另一个文件复制粘贴. 确保调整文件名.

  • .h 头文件中, 引入防护应该与 FILENAME_H 形式一起使用.

  • .cpp 文件(如 filename.cpp )中, 第一个引入应该是声明类的那个(例如 #include "filename.h"), 然后使用空行分隔.

  • 然后来自Godot自己的代码库的标头, 按字母顺序(由 clang-format 强制)引入, 并具有相对于根文件夹的路径. 这些引入应该用引号来完成, 例如 #include "core/object.h". 然后,Godot标头引入的块应用一个空行以进行分隔.

  • 最后, 第三方头文件(无论是来自 thirdparty 还是来自系统的包含路径)接下来, 应该用 < and > 符号包含, 例如 #include <png.h> . 第三方头文件块的后面也应该有一个空行来分隔.

  • Godot和第三方标头应包含在需要它们的文件中, 即, 如果在声明性代码中使用, 则在 .h 标头中;如果仅在命令性代码中使用, 则在 .cpp 中.

示例:

  1. /*************************************************************************/
  2. /* my_new_file.h */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifndef MY_NEW_FILE_H
  31. #define MY_NEW_FILE_H
  32. #include "core/hash_map.h"
  33. #include "core/list.h"
  34. #include "scene/gui/control.h"
  35. #include <png.h>
  36. ...
  37. #endif // MY_NEW_FILE_H
  1. /*************************************************************************/
  2. /* my_new_file.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "my_new_file.h"
  31. #include "core/math/math_funcs.h"
  32. #include "scene/gui/line_edit.h"
  33. #include <zlib.h>
  34. #include <zstd.h>

Java

Godot的Java代码(主要在 platform/android 中)也是通过 clang-format 来执行的, 所以请看上面的说明来设置它. 请记住, 本风格规则只适用于Godot编写和维护的代码, 而不是第三方代码, 如 java/src/com/google 子文件夹.

Python

Godot的SCons构建系统是用Python编写的, 源代码树中包含的各种脚本也使用Python.

对于这些, 我们遵循 黑色风格指南 . 使用 Black使Python 更改变黑 .

本地使用黑色

首先, 您需要安装black.Black需要python3.6.0+才能运行.

安装

下面介绍如何安装black:

  1. pip3 install black --user

然后, 您有不同的可能性将黑色应用于您的更改:

手动使用

您可以使用以下命令将 black 手动应用于一个或多个文件:

  1. black -l 120 <path/to/file(s)>
  • -l 120 表示每行允许的字符数为 120。这个数字是经过开发者们商定的。

  • 该路径可以指向多个文件, 可以一个接一个, 也可以像典型的unixshell一样使用通配符.

预提交钩子

为了便于使用, 我们为Git提供了一个预提交钩子, 它将在您的所有提交上自动运行以检查您的提交, 并让您在最终提交中应用其更改.

这个 “hook” 是一个脚本, 可以在 misc/hooks 中找到. 请参考该文件夹的 README.md , 了解安装说明.

编辑器集成

许多集成开发环境或代码编辑器都有美化插件, 可以配置为自动运行black, 例如每次保存文件时. 有关详细信息, 可以查看 black 编辑器集成 .

评论风格指南

本注释风格指南适用于Godot代码库中使用的所有编程语言.

  • 以空间字符开始注释, 以将其与禁用代码区分开来.

  • 注释使用句子大小写. 注释以大写字母开头, 并始终以句号结束.

  • 使用反引号引用变量和函数名和值.

  • 将注释控制在~100个字符。

  • 你可以在需要的时候使用 TODO: , FIXME: , NOTE: , HACK: 作为强调.

示例:

  1. // Compute the first 10,000 decimals of Pi.
  2. // FIXME: Don't crash when computing the 1,337th decimal due to `increment`
  3. // being negative.

不要在注释中重复代码的内容. 解释 为什么 而不是 如何 .

错误做法:

  1. // Draw loading screen.
  2. draw_load_screen();

你可以在函数或宏定义上面使用Javadoc风格的注释. 建议只对不公开给脚本的方法使用Javadoc风格的注释. 这是因为公开的方法应该在 class reference XML 中进行记录.

示例:

  1. /**
  2. * Returns the number of nodes in the universe.
  3. * This can potentially be a very large number, hence the 64-bit return type.
  4. */
  5. uint64_t Universe::get_node_count() {
  6. // ...
  7. }

对于成员变量, 不要使用Javadoc式的注释, 而是使用单行注释:

  1. class Universe {
  2. // The cached number of nodes in the universe.
  3. // This value may not always be up-to-date with the current number of nodes
  4. // in the universe.
  5. uint64_t node_count_cached = 0;
  6. };