# godot_game_tutorials **Repository Path**: tpig/godot_game_tutorials ## Basic Information - **Project Name**: godot_game_tutorials - **Description**: 用游戏学 Godot - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-14 - **Last Updated**: 2026-09-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 用游戏学 Godot ## 这个项目是什么 用一串**由浅入深的小游戏**,帮已经具备中/高级编程经验(熟悉任何一门语言的变量、函数、面向对象)的朋友,快速、扎实地掌握 **Godot 4.x(本项目使用 4.7,GDScript)** 游戏开发。 我们**不教编程基础**,只讲 Godot 特有的东西:场景树与节点、生命周期回调、信号、实例化、物理体、2D/3D 工作流等。每一章都是一个可以独立运行的小游戏,只引入少量新概念,并通过一个**启动器主场景**在各章之间切换。 > 选型依据 Godot 官方入门路径(*Your first 2D game: Dodge the Creeps*、*Your first 3D game: Squash the Creeps*),并在前面补上两章更轻的铺垫(Pong、太空射击),把官方两章之间较大的坡度拆细。 ## 适合谁 / 不适合谁 - **适合**:会写代码、但没接触过 Godot,想在几小时到几天内建立完整心智模型的人。 - **不适合**:完全没写过代码的初学者;想学 C# 或 GDScript 语法细节的人(本项目只用 GDScript,且默认你能边看边查语法)。 ## 环境与运行 - 安装 **Godot 4.7**(标准 Forward+ 版本即可)。Windows 下 Godot 通常是绿色单文件,可执行文件未加入 PATH。 - 启动器:双击打开项目后按 **F5**(首次会提示选择主场景,主场景固定为 `res://main_menu/main_menu.tscn`)。 - 不打开编辑器运行 / 命令行检查: ```bash godot # 运行项目(进入启动器) godot --editor # 打开编辑器 godot --headless --import # 非交互导入资源、校验工程 godot --headless --check-only --script res://path/x.gd # 仅做语法/解析检查 ``` - Godot 没有独立的编译/构建步骤,GDScript 在编辑器导入和运行时解析;用编辑器或 `--check-only` 发现错误。 ## 学习路径总览 | 章 | 游戏 | 维度 | 核心知识点 | 关键节点 | |---|---|---|---|---| | 0 | 心智模型(无游戏,约 10 分钟) | — | Node / Scene / SceneTree / Resource、实例化 | Node | | 1 | **Pong(弹球对战)** | 2D | 场景树、生命周期回调、输入、`delta`、内置信号、碰撞体初体验 | `Node2D` `CharacterBody2D`/`StaticBody2D` | | 2 | **Dodge the Creeps(俯视角躲避)** | 2D | 自定义信号、三种信号连接、Autoload 事件总线、组、定时器、运行时实例化、HUD、重开 | `Area2D` `Timer` `Label`/Control | | 3 | **Space Shooter(太空射击)** | 2D | 子弹生成与对象池、`Vector2` 数学、简单有限状态机、音频、计分/难度、碰撞层 | `CharacterBody2D` `Area2D` `AudioStreamPlayer` | | 4 | **2D Platformer(平台跳跃)** | 2D | `CharacterBody2D.move_and_slide`、TileSet/TileMap、相机、精灵动画、碰撞层/掩码、跳跃手感 | `TileMapLayer` `Camera2D` `AnimatedSprite2D` | | 5 | **Squash the Creeps(3D 踩怪)** | 3D | 3D 坐标系、光照、3D 相机、`CharacterBody3D`、`Area3D` 判定盒、glTF 模型导入与动画、Jolt | `Node3D` `CharacterBody3D` `Area3D` `DirectionalLight3D` `Camera3D` | > 进阶可选(暂不在主线):小型 Roguelike/RPG —— `NavigationAgent2D` 寻路、`Resource` 存档、程序化生成;3D 第三人称控制器 + `AnimationTree`。 --- ## 第 0 章 · 心智模型(先读,约 10 分钟) 写给有经验的程序员,建立四句话的世界观: 1. **一切皆 Node**。Node 是树上的一个对象,有 `_ready()` / `_process(delta)` 等回调;它本身不可见,靠子类表现行为(绘制、物理、声音、UI)。 2. **Scene 是一棵可复用的子树**,存成 `.tscn`。一个玩家、一颗子弹、一整个关卡都是场景。 3. **实例化(Instancing)是组合的核心手段**:场景 A 可以把场景 B 作为节点放进来,也可以在运行时 `instantiate()` 出任意多个 B(敌人、子弹)。优先用「组合小场景」,而不是深继承。 4. **Resource 是可序列化的数据资产**(贴图、音频、形状、甚至自定义 `.tres` 数据表),通过 `res://` 引用;存档用 `user://`。 **GDScript 速记(用到再查,不背)**:动态类型、缩进语法、`class_name X` 给类起全局名、`@onready var x = $Child` 在 `_ready` 前取子节点、`@export` 把变量暴露到检视面板、`signal` 声明信号。数据类型(Variant、值/引用语义、Vector2 等结构体、Array/Dictionary、Object)见独立参考:[`docs/gdscript-types.md`](docs/gdscript-types.md)。 完成第 0 章后,你应该能回答:场景和节点的关系?`.tscn` 和脚本 `.gd` 怎么挂在一起? --- ## 第 1 章 · Pong:游戏循环与生命周期 ✅ **游戏**:左右两块挡板、一个来回反弹的球;左侧玩家用 W/S,右侧可由简单 AI 或第二个玩家控制;先得若干分者胜,可重开、可返回启动器。 **你将学到** - 工程如何从主场景启动;`SceneTree` 主循环;节点回调的**触发顺序**: | 回调 | 时机 | 典型用途 | |---|---|---| | `_enter_tree()` | 节点进入树(子节点可能尚未就绪) | 极少用 | | `_ready()` | 自身与所有子节点就绪,**仅一次** | 取引用、初始化 | | `_process(delta)` | 每帧 | 非物理逻辑、UI、补间 | | `_physics_process(delta)` | 每个物理帧(固定步长) | 移动、碰撞相关逻辑 | | `_unhandled_input(event)` | 有未被 UI 消费的输入时 | 按键/菜单操作 | - `delta` 的意义与「按帧率无关」移动;为什么物理移动放 `_physics_process`。 - 通过 **InputMap**(项目设置里定义动作)读取输入,而不是硬编码按键。 - **内置信号第一次出现**:按钮 `pressed`、碰撞体 `body_entered` / `area_entered`;在编辑器里连接信号。 - 物理体三兄弟的最小区别:`StaticBody2D`(挡板/墙)、`CharacterBody2D`(可控移动)、`Area2D`(只检测不阻挡,球的得分区)。 - 场景切换:`get_tree().change_scene_to_file(...)`、`reload_current_scene()`、暂停 `get_tree().paused`、退出 `quit()`。 **建议场景树** ``` Pong (Node2D, pong.gd) ├── WallTop / WallBottom (StaticBody2D + CollisionShape2D) ├── ScoreZoneLeft / ScoreZoneRight (Area2D) ├── PaddlePlayer (CharacterBody2D, 自场景 paddle.tscn) ├── PaddleAI / PaddlePlayer2 (CharacterBody2D) ├── Ball (CharacterBody2D 或 Area2D, 自场景 ball.tscn) ├── HUD (CanvasLayer → Label 比分 / “按 Esc 返回”) └── ReturnHint(监听 Esc,change_scene 回启动器) ``` **完成标准**:帧率无关的移动与反弹、W/S 控制、出界得分并重置球、Esc 返回启动器、能从启动器再次进入。 --- ## 第 2 章 · 信号与事件:Dodge the Creeps ✅ **游戏**:你控制一个小人在场地里移动,敌人从四边随机刷新并直线冲来,碰到即游戏结束;坚持越久分数越高,可重开。 **本章是「解耦」专题**,你将学到: - **自定义信号** `signal hit` / `signal scored(n)`,以及三种连接方式:编辑器面板连接、代码 `signal.connect(callable)`、`emit` 触发。 - 为什么用信号:发出方不需要知道接收方是谁 → 玩家、敌人、HUD、主场景互不直接引用。 - **Autoload 单例**:注册一个全局事件总线 `EventBus`(`[autoload]`),跨场景广播游戏级事件;顺带理解单例的生命周期(早于所有场景、切换场景不销毁)。 - **组(Groups)**:`add_to_group` / `get_tree().get_nodes_in_group()`,按标签批量操作节点。 - `Timer` 驱动的刷怪节奏、随机出生位置与方向。 - 运行时**实例化**:`var mob = preload(...).instantiate()` 后 `add_child()`。 - `Area2D` 的 `body_entered` 做碰撞判定;HUD(Control)与游戏逻辑分离;游戏结束 → 重开当前场景。 **建议场景拆分**(每个可独立运行测试的小场景):`player.tscn`、`mob.tscn`、`hud.tscn`、`main.tscn`(组装 + 刷怪)。 **完成标准**:敌人持续随机刷新、碰撞即结束并显示重开按钮、分数随时间增长;玩家、敌人、HUD 之间**只通过信号/事件总线通信,无硬引用**。 --- ## 第 3 章 · Space Shooter:实例化、对象池与向量数学 🔲 **游戏**:飞船在底部移动并向上射击,敌舰从顶部出现,击毁得分,被撞失败;难度随时间提升。 **你将学到** - 频繁生成/销毁子弹用 **对象池**(预实例化一组,用完回收 `queue_free` 的替代)对比直接 `instantiate/queue_free`,理解各自代价。 - **`Vector2` 数学**:方向、归一化 `normalized()`、朝目标 `look_at` / `rotation`、`move_toward`、线性插值 `lerp`。 - 一个简单**有限状态机**(菜单 / 进行中 / 暂停 / 结束),可以是枚举 `match` 写法,先不用上节点式 FSM 框架。 - `AudioStreamPlayer`(一次性音效)与统一的 `AudioManager` 单例思路。 - 计分、难度曲线、`Tween` 做简单反馈(爆炸、闪白)。 - 开始严格使用**碰撞层 / 掩码**(见下方约定表)。 **完成标准**:子弹用对象池复用、移动/瞄准基于向量、状态切换正确、有音效和计分、难度递增。 --- ## 第 4 章 · 2D Platformer:物理移动、瓦片地图与动画 🔲 **游戏**:一张多平台关卡,角色跑动、跳跃、踩怪或躲怪,相机跟随,到达终点过关。 **你将学到** - `CharacterBody2D.velocity` + `move_and_slide()` 的标准移动范式;`is_on_floor()`、`get_slide_collision()`。 - 重力、起跳、土狼时间(coyote time)、跳跃缓冲、可变跳跃高度等「手感」细节。 - **TileSet / TileMapLayer**:绘制碰撞、单面斜坡/单向平台;`Camera2D` 跟随与边界。 - `AnimatedSprite2D` 帧动画(idle/run/jump/fall),用状态驱动动画切换。 - 碰撞层(layer)与掩码(mask)的正确配对;`Area2D` 做踩怪判定盒(hitbox/hurtbox 模式)。 - 关卡即场景,主场景 `instance` 进多个关卡,过关切场景。 **完成标准**:扎实的跑跳手感、瓦片关卡碰撞正确、相机平滑跟随、动画随状态切换、踩怪判定可靠。 --- ## 第 5 章 · Squash the Creeps:进入 3D 🔲 **游戏**:控制一个小人在 3D 场地移动、跳起砸扁四处游荡的怪物;被撞到则结束,可重开(对标 Godot 官方 *Your first 3D game*)。 **你将学到** - 2D → 3D 的概念映射:`Node2D→Node3D`、`CharacterBody2D→CharacterBody3D`、`Area2D→Area3D`、多出的 Z 轴、3D 向量与旋转(`Vector3`、四元数/欧拉角只需会用)。 - 3D **场景观感**:`DirectionalLight3D`(带阴影)、`WorldEnvironment`(环境光/背景)、`Camera3D` 与跟随。 - 用 CSG/基本体搭占位场景;后续**导入 glTF/glb 模型**、骨架动画与 `AnimationPlayer` / `AnimationTree`。 - `Area3D` 做落地踩怪判定盒;`CharacterBody3D` 在地面的移动与重力。 - 本项目 3D 物理使用 **Jolt Physics**(已在项目设置启用),留意与默认 GodotPhysics 的参数差异。 **完成标准**:第三人称相机跟随、地面移动与跳跃、跳砸怪物、碰撞结束与重开、最终换成带骨骼动画的模型。 --- ## 项目框架与目录约定 ### 目录结构 ```text res:// ├── project.godot # 工程配置(主场景、InputMap、Autoload、物理引擎) ├── main_menu/ # 启动器(= 主场景) │ ├── main_menu.tscn │ └── main_menu.gd ├── games/ # 每章一个自包含文件夹(场景/脚本/资源/章节笔记) │ ├── 01_pong/ │ │ ├── pong.tscn / .gd │ │ ├── paddle.tscn / .gd │ │ ├── ball.tscn / .gd │ │ ├── assets/ # 仅本章使用的美术/音频 │ │ └── README.md # 本章图文笔记与要点 │ ├── 02_dodge_the_creeps/ │ ├── 03_space_shooter/ │ ├── 04_platformer/ │ └── 05_squash_3d/ ├── shared/ # 跨章复用(确认在 ≥2 章用到后才提取,避免过早抽象) │ ├── components/ # 如:返回菜单组件、hitbox/hurtbox 基类 │ └── ui/ # 通用按钮、计分板样式 ├── autoload/ # 全局单例(按章节需要逐个引入,不前置堆砌) │ ├── event_bus.gd # 第2章引入:跨场景信号 │ ├── game_manager.gd # 第2/3章:场景导航常量、全局状态 │ └── audio_manager.gd # 第3章引入:统一播放音效 └── assets/ # 真正全局共享的字体/通用音效(尽量少) ``` 原则:**每一章尽量自包含、可单独阅读和运行**;只有被至少两章共用的东西才提到 `shared/` 或 `autoload/`。教学代码以「直白、能对应到引擎概念」为最高优先级,不做企业式分层。 ### 命名 - 文件/文件夹用 `snake_case`(Godot 惯例,也对 .tscn 引用更稳);GDScript 类名用 `PascalCase` 并配 `class_name`。 - 场景与主脚本同名:`pong.tscn` ↔ 根节点挂 `pong.gd`。 - 节点名用语义化英文名(`Player`、`ScoreZoneLeft`),脚本里用 `$Player` 引用。 ### 主场景与导航 - **主场景固定为启动器** `res://main_menu/main_menu.tscn`(在 `project.godot` 的 `run/main_scene` 设置)。 - 启动器是一个 `Control` 菜单:每个章节一个按钮,点击调用 `get_tree().change_scene_to_file("res://games/01_pong/pong.tscn")`。 - 每个游戏内监听 **Esc** → 返回启动器,提供重开(`reload_current_scene()`)。启动器按钮在第 1 章直接硬编码路径(此时还没讲 Autoload);第 2 章引入 `game_manager` 后再把路径集中管理。 ### InputMap 动作约定(在项目设置里统一定义) | 动作 | 按键 | 出现章节 | |---|---|---| | `p1_up` / `p1_down` | W / S | 1 | | `move_left/right/up/down` | A/D/W/S 或方向键 | 2、5 | | `jump` | Space / W | 4、5 | | `shoot` | Space / 鼠标左键 | 3 | | 菜单/暂停/返回沿用 Godot 内置 `ui_accept`、`ui_cancel`(Esc) | — | 全部 | ### 碰撞层 / 掩码约定(第 1 章先用默认,第 3 章起严格执行) | Layer | 归属 | |---|---| | 1 | 世界 / 静态地形 | | 2 | 玩家 | | 3 | 敌人 | | 4 | 玩家子弹 | | 5 | 敌人子弹 / 道具 | 规则:一个节点设置自己所在的 **layer**,以及它要检测谁的 **mask**;能不勾就不勾,保持判定最小化。 ## 进度约定 章节标题后的 🔲 = 未开始,🚧 = 进行中,✅ = 已完成。每完成一章:补全该章 `games/xx/README.md` 图文笔记、更新本表状态,并保证从启动器可进入、可返回。 ### 当前进度 - ✅ **第 0 步 · 框架搭建**:目录树、启动器主场景 `main_menu/`(已设为 `run/main_scene`)、各章占位。现在 F5 可直接运行进入启动器;未实现章节自动置灰,随章节完成自动解锁。 - ✅ **文档查阅面板**(启动器 →「📖 查阅 Godot 文档」,`main_menu/docs_browser.tscn`):用 `ClassDB` 离线实时过滤全部引擎类(约 1000+,双击/回车打开类参考),支持关键字全站搜索、中/英文档切换、以及与课程配套的常用教程入口;通过 `OS.shell_open` 调系统浏览器打开(运行时不含 HTML 渲染器)。 - ✅ **第 1 章 · Pong**:玩家(W/S)vs AI,上下墙反弹、左右出界得分,先到 7 分胜,R 重开、Esc 返回。覆盖生命周期回调、InputMap(`p1_up/down`)、内置信号 `body_entered`、三类 2D 物理体;启动器已自动解锁本章。详见 `games/01_pong/README.md`。 - ✅ **第 2 章 · Dodge the Creeps**:俯视角躲避,存活秒数即得分。覆盖自定义信号三种连接方式(编辑器/代码/emit)、Autoload 事件总线 `EventBus`(主场景不持有 HUD 引用)、导航单例 `GameManager`(场景路径集中管理,Pong 的 Esc 已回溯接入)、组批量清场、三个 `Timer` 驱动节奏、运行时 `instantiate()` 刷怪与 `VisibilityNotifier2D` 回收、`Area2D` 玩家 + `RigidBody2D` 敌人。输入动作 `move_up/down/left/right`(WASD + 方向键)。详见 `games/02_dodge_the_creeps/README.md`。 - 🔲 第 3~5 章:未开始(见上方路径总览表与各 `games/0x_*/README.md`)。 - ⏸️ 刻意留空:`shared/`(出现 ≥2 章复用后再提取);`autoload/` 已按计划在第 2 章引入 `EventBus`、`GameManager`,`AudioManager` 留到第 3 章。