目录结构不是洁癖,是协作成本
Godot 项目很容易从一个 Player.tscn 和几个脚本开始。原型阶段,文件放在哪里似乎不重要,能找到就行。几周之后,项目里会出现 NewFolder、test、old、player2.gd、enemy_final_final.tscn。美术资源、运行时场景、编辑器工具、配置 Resource 混在一起,任何改名都可能弄坏引用。
目录结构不是为了看起来专业,而是为了让团队知道一个文件属于哪里、谁能改、什么时候加载、能否复用。Godot 的 .tscn、.tres、.gd 都是文本引用路径,目录混乱会直接影响重构和构建。一个清楚的目录约定,能减少沟通成本,也能让工具更容易写。
flowchart TD
A[res://] --> B[scenes]
A --> C[scripts]
A --> D[resources]
A --> E[assets]
A --> F[addons]
A --> G[tests]
B --> H[gameplay/ui/world]
C --> I[services/domain/components]
D --> J[config/abilities/items]
E --> K[art/audio/fonts]
F --> L[editor/runtime plugins]
先按“用途”而不是“文件类型”分层
有些团队把所有 .gd 放 scripts,所有 .tscn 放 scenes,所有图片放 textures。这样初期清楚,但模块关联会被拆散。另一个极端是按功能完全聚合,一个模块里什么都有。实际项目可以折中:顶层按用途分层,模块内按功能组织。
比如 scenes/gameplay/player/player.tscn 对应 scripts/gameplay/player/player_controller.gd 和 resources/abilities/player_dash.tres。资源路径可读,模块关系也清楚。UI 页面放 scenes/ui/inventory,通用控件放 scenes/ui/common。不要让页面脚本散落到全局 scripts 根目录。
顶层目录建议保持少而稳定:scenes 放可实例化场景,scripts 放纯脚本和服务,resources 放配置型 Resource,assets 放美术音频字体,addons 放插件,tests 放测试。临时实验放 sandbox 或 prototypes,并明确不进入发布。
场景文件要按生命周期归类
Godot 场景是运行时对象蓝图。它们按生命周期和用途归类,比按美术或程序来源归类更有用。常驻根场景、玩法场景、UI 页面、弹窗、可复用组件、特效、测试场景,应该有不同目录。
例如 scenes/app/main.tscn 是入口容器;scenes/world/levels 放关卡;scenes/ui/pages 放全屏页面;scenes/ui/popups 放模态弹窗;scenes/vfx 放可复用特效;scenes/dev 放调试场景。这样资源加载、场景路由和构建扫描都能按目录处理。
不要把测试场景混在正式场景里。测试场景很有价值,但要能被导出规则识别。发布时是否包含,要由构建配置决定。否则某个测试场景引用了临时资源,也会被打进包里。
scripts 不要变成垃圾桶
所有脚本都放 scripts 根目录,会很快失控。脚本至少要区分服务、领域逻辑、组件、工具、编辑器脚本。scripts/services 放 Autoload 服务,scripts/domain 放不依赖场景树的模型和规则,scripts/components 放可挂在节点上的通用行为,scripts/editor 放编辑器工具。
命名上也要表达用途。inventory_model.gd、inventory_view.gd、inventory_service.gd 比 inventory.gd 清楚。Godot 脚本经常和场景同名,这没问题,但服务和模型不要和页面脚本混淆。
脚本依赖方向要固定。UI 脚本可以调用服务和模型,服务不应该反过来依赖具体 UI。编辑器脚本不要进入运行时依赖。目录结构如果和依赖方向一致,代码评审会容易很多。
assets 和 resources 要区分
assets 是原始或导入后的美术音频字体文件,resources 是项目配置数据。比如 assets/art/items/potion.png 是图片,resources/items/potion_small.tres 是道具配置。两者不要混在一起。否则内容人员很难知道改图标还是改数值。
Resource 文件要按系统归档:items、abilities、quests、shops、enemies。大量 Resource 需要命名规范和校验工具。比如道具配置文件名和 item_id 一致,技能配置文件名和 ability_id 一致。构建前扫描不一致项。
原始源文件是否进仓库,要看团队流程。Aseprite、Blender、PSD 可以放 source_assets 或外部资产库,但不要和运行时导入文件混淆。运行时只引用 res://assets 或生成资源。
命名规则保护跨平台
Windows 文件系统不区分大小写,Linux 区分。Godot 导出到 Linux 或 Android 后,大小写问题会突然出现。建议全项目文件名使用小写 kebab-case 或 snake_case,不使用空格和中文文件名。目录也一样。
资源路径一旦被场景引用,改名会影响很多文件。Godot 编辑器内移动通常能更新引用,但批量脚本改名要谨慎。提交前可以跑路径检查,发现大小写冲突、空格、非法字符直接报错。
小结
Godot 项目目录约定是客户端工程的第一层秩序。顶层按用途分层,场景按生命周期归类,脚本按职责归档,assets 和 resources 分开,命名规则跨平台安全。目录不是写给机器看的,先是写给团队看的;团队看得懂,工具才好接上。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
我会把目录规范配套成一个初始化模板和一个检查脚本。模板让新模块从正确位置开始,检查脚本阻止空格文件名、大小写冲突、测试资源误进正式目录。规范只有能自动执行,才不会停留在文档里。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。