Files
fallingshrimp f4c829bf8d docs: update and reorganize the project specification document
1. rename "命名规范" to "通用命名规范"
2. adjust the order of naming specification items
3. add code writing specification, pattern style and node reference related content
2026-07-31 13:44:39 +08:00

5.4 KiB
Raw Permalink Blame History

开发规范

注意:

  1. 本项目是godot46创建的,虽说附近版本号可以向下兼容,但是最好不要改编辑器版本。
  2. 你可以写一个AGENTS.md指向该文件,但是注意最好不要用MCP,AI会把场景改得乱七八糟。
  3. 建议要用agent就装一个godot skills,要么就古法编程(No-vibe-coding万岁!!!)。

目录该放什么

  • components/ 游戏中的所有场景,除了world主场景,不要有其他场景散在工作区里
    • Abstracts/ 抽象场景,虽然说godot的场景不能抽象但是看做抽象!
    • Bullets/ 子弹,其下所有场景都继承于BaseBullet
    • Characters/ 角色,其下所有场景都继承于BaseCharacter
    • Interactables/ Menus/ 同理
  • resources/ 资源文件,注意.tres .res不属于资源,这里更应该说是assets,就是Unity生态里的资产概念,就是媒体(图片、视频、音频)、字体、骨骼
  • scripts/ 所有脚本,不要把脚本散在工作区
    • Content/ 游戏内容的高层实现,比如交互体、角色等的AI
    • Statemachine/ 状态机,不一定是某个模式FSM或者UtilityAI才算
      • Abstract/ 抽象对象,但不一定是抽象类,比如说所有“角色”都有的复用代码
        • BaseXXX.gd 比如BaseCharacter BaseMenu
      • Component/ UI组件的状态机
      • Data/ 继承RefCounted的类,就是纯数据不和引擎交互
    • Struct/ 数据结构,但和Statemachine/Data不同,指的是可以作为游戏内容但是本身不参与节点树,也没有状态机说法的数据
    • Util/ 这个就是工具类了
      • [T].gd 类名就是class_name [T]Util,仅静态类,提供一些最底层的工具,比如随机从数组里选择
      • Manager/ 管理器,一般要和节点树交互,也可以不交互
        • [T]Manager.gd 类名就是class_name [T]Manager,只能继承Node(或者不继承),不能更深,否则请作为Statemachine

通用命名规范

  1. 对于一切符号,用小驼峰命名法,就是写js用的那种,常量除外,采用全大写
  2. 对于游戏内容[T extends Character|Bullet|Menu|...],其行为脚本的类名写成“内容名+[T]”,比如角色A的类名就是ACharacter
  3. 对于资源文件,用连字符命名
  4. 对于脚本文件,大多数情况下可以直接写类名,但是游戏内容[N][T]也可以写成N.gd
  5. 对于着色器文件,用小驼峰写清楚实现的特效是什么

代码排序规范

对于行为类

  1. extends
  2. class_name 空行
  3. @export 空行
  4. @onready
  5. 普通var 空行
  6. 节点的虚方法_ready、_physics_process等 空行
  7. 抽象方法(或者对基类抽象方法的实现) 空行
  8. 工具方法(但不是工具类里的底层方法!!!是这个对象的高层实现,比如BaseCharacter里的getHealthPercent方法,而不要在这个类里写getRandomInt

对于管理器

如果这个管理器是一个Node而且是单例,推荐写一个static var instance: XXManager,然后在ready时赋值,注意单例类不要写其他静态变量

  1. extends Node
  2. class_name 空行
  3. static var instance 空行
  4. 其他变量 空行
  5. 方法

代码编写规范

  1. 必须用静态类型声明,禁止动态类型或者是用:=的语法糖
  2. 少用as,如果你是已经确定一个对象的类型,但是编译器推不出来直接用if is,除非是编译器推断错了再用as
  3. 对于节点名字或者Signal的名字,可以用StirngName特化性能,比直接用Stirng好一点
  4. 缩进用Tab,不要用空格

模式风格

  1. 对于一个函数有多个返回值通过数组或者字典返回,可以用Pattern Match(match data:[var a,var b])来解构,就可以少一点变量了
  2. 保持函数的纯度,尽量多写纯函数,少点副作用
  3. 解耦,这个很好理解,就是把数据逻辑和UI逻辑分离开之类的

关于节点

引用

注意:我这里指的是狭义的Node.get_node方法或者$的速记写法。

  • 节点的命名规范:场景根节点用大驼峰,下面的树用小驼峰,虽然可以用中文和连字符以及一些乱七八糟的其他字符,但是最好还是不要出现,就用英文字母+数字
  • 在脚本里获取节点
    • 场景里原本就有的,仅唯一的节点,请给一个unique id,不要在@onready时用绝对路径获取,就是写成@onready var colorRect: ColorRect = $%colorRect
    • 对于要出现很多次的节点,比如角色,那就不用unique id了,直接get_node

Best Practice

  1. 所有直接继承Object或者没写继承的类不许去new,要么就继承RefCounted,不然会内存泄漏
  2. 游戏对象的分类有很多,比如说角色A就写一个场景A.tscn,脚本就是A.gdclass ACharacter extends BaseCharacter(这个只是伪代码,建议写成一个单独的文件)
  3. 比如玩家的技能(Skill),应该放在Struct里写成Skill.gd,类名BaseSkill,因为这个类只负责表示玩家的技能卡对应的行为,并不耦合于节点树和角色的行为类

冷知识

  1. godot没有try-catch或者try-except语句,尽量少用assert除非你在调试
  2. godot的异步函数不需要声明,但是他的Signal和Coroutine都可以用await等待,把Signal也看做是Coroutine就行了
  3. 不要在@export变量里写Gradient等资源,而是用GradientTexture,否则编辑器会直接爆炸
  4. godot的_ready顺序是先子节点再父节点,注意时序问题