Godot Engine 4.7 全景:开源游戏引擎的黄金时代——从入门到精通的十级台阶
这是本系列的总纲。此后十篇回复,一级台阶一级台阶,带你从「没装过引擎」走到「能读懂引擎源码」。每篇配一张动态图卡,全部基于 Godot 4.7 稳定版(2026 年 6 月 18 日发布)撰写,兼述 4.5、4.6 的关键演进,末章前瞻 4.8。
这是本系列的总纲。此后十篇回复,一级台阶一级台阶,带你从「没装过引擎」走到「能读懂引擎源码」。每篇配一张动态图卡,全部基于 Godot 4.7 稳定版(2026 年 6 月 18 日发布)撰写,兼述 4.5、4.6 的关键演进,末章前瞻 4.8。
一、为什么是 Godot,为什么是现在
2026 年,如果你还没听过 Godot,大概率只是因为你不在独立游戏圈。几个硬数字,皆有出处:
- Steam 上的 Godot 游戏爆发式增长:2019 年全年只有 56 款,2025 年达到 1229 款,六年约 22 倍;而 2026 年才过半,已超 700 款新游戏上 Steam(官方 4.7 发布公告数据)。
- itch.io 每周新增超 1000 款 Godot 游戏——这是开发者基数在膨胀的直接证据。
- 《Battlefield 6》(战地 6)的 Portal 用户生成内容平台用 Godot 构建——3A 项目开始把开源引擎当工具用,这在五年前不可想象。
- 《Slay the Spire 2》(杀戮尖塔 2)从 Unity 整体迁移到 Godot,因为 Unity 的运行时收费风波;《Brotato》销量破千万份、收入超 1070 万美元;《Buckshot Roulette》两周卖出 100 万份。
二、Godot 是什么:三个反直觉的设计
很多教程上来就「下载、新建项目」,跳过了最重要的心智转变。Godot 和 Unity/Unreal 有三处根本不同:
- 没有「GameObject + Component」,只有「节点(Node)+ 场景(Scene)」。一个角色是一个场景,一把武器是一个场景,连 UI 按钮都是一个场景。场景可以互相嵌套,像乐高一样。理解了这一条,Godot 就懂了一半。
- 引擎是「模块化的服务器集合」。渲染是 RenderingServer,物理是 PhysicsServer,音频是 AudioServer……节点只是服务器 API 的「友好封装」。这个设计让 Godot 后来能做出别的引擎做不到的事:把整个引擎作为库嵌入你的程序(4.6 的 LibGodot)。
- 零许可费、零黑盒。MIT 许可证意味着:你的游戏赚一个亿,Godot 一分不抽;引擎源码全部可读,遇到 bug 可以自己改自己编。
三、版本全景表(截至 2026 年 9 月)
| 版本 | 发布时间 | 支持状态 | 关键词 |
|---|---|---|---|
| 4.4 | 2025-03 | 已停止更新 | Jolt 物理(实验)、Ubershaders、内嵌游戏窗口 |
| 4.5 | 2025-09 | 仅安全补丁 | Stencil 缓冲、WASM SIMD、GDScript 变参与抽象类、visionOS 导出、着色器烘焙 |
| 4.6 | 2026-01 | 维护中(4.6.3) | LibGodot 引擎即库、Modern 新主题、Jolt 转正默认、新 IK 框架、D3D12 成 Windows 默认 |
| 4.7 | 2026-06 | 当前推荐稳定版 | HDR 输出、AreaLight3D、DrawableTexture2D、Asset Store、GABE 安卓全流程 |
| 4.8 | dev6(2026-09-14) | 开发中 | 屏幕空间接触阴影、对象属性访问提速 1.6 倍、多图层 XR 相机 |
四、十级台阶:本系列的行军路线
- 第一级 · 起手式:装引擎、认界面、跑通第一个场景。重点建立「节点树」直觉。
- 第二级 · 节点与场景:深入 Godot 世界观——场景实例化、信号、生命周期。
- 第三级 · GDScript 精要:静态类型、信号与 await、4.5 的变参与抽象类,以及最容易踩的坑。
- 第四级 · 2D 实战:CharacterBody2D 移动手感、TileMapLayer、相机跟随,做一个能跑能跳的小平台游戏。
- 第五级 · 动画与状态机:AnimationPlayer、AnimationTree 状态机,让角色「活」起来。
- 第六级 · 3D 入门:坐标与朝向、导入模型、光照与相机,看清 3D 与 2D 的同构。
- 第七级 · 渲染与着色器:三大渲染方法怎么选、HDR 与 AreaLight3D 实战、着色器语言入门。
- 第八级 · UI 与架构:Control 体系、主题、信号总线与自动加载,写出不腐化的项目结构。
- 第九级 · 性能与导出:Profiler、批处理、对象快照查泄漏;一路从 Windows 导出到 Web 与 Android,说清主机平台的实情。
- 第十级 · 精通之路:GDExtension 与 C# 选型、编辑器插件、读源码的门径,以及 4.8 与更远的未来。
五、怎么学最有效:给三类人的路线
- 从零开始的新手:第一级到第四级按顺序走,每级都动手敲,不要只用眼睛看。第四级结束时你会拥有一个自己写的完整小游戏——这是最重要的里程碑。
- 从 Unity/UE 转过来的老兵:先读第二级(节点 vs GameObject)和第三级(GDScript vs C#),对应关系建好之后,第五级到第九级可以按需跳跃。
- 后端/客户端工程师(不做游戏):直接看第六级的 3D 数学、第八级的架构、第九级的性能,第十级的 LibGodot 和 GDExtension 对你可能是真需求——嵌入式 3D 可视化正变得常见。
六、本系列的考证纪律
凡进入正文的 API 名称、类名、特性,全部核对过官方文档或发布公告原文;不确定的地方,明说「未查到」或「截至发稿」。官方文档入口是 docs.godotengine.org(4.7 中文文档已相当完整),本系列每级末尾都会给出对应的官方章节链接。
下一篇,第一级台阶:起手式——十分钟装好引擎,写出你的第一个「Hello, Godot」。
*本篇配图:十级台阶全景图。*
讨论回复(10)
本系列基于 Godot 4.7 稳定版。本篇目标:装好引擎、认全界面、理解「节点树」这个最核心的直觉,亲手搭出第一个可运行的场景。全程不写一行代码。
一、下载与安装:一个 zip 就是一个引擎
去 godotengine.org/download 下载 Windows 版。你会看到一个选择:Standard 版和 .NET 版。
- Standard 版:内置 GDScript 与 GDExtension 支持,约 50 MB,解压即用。
- .NET 版(旧称 mono):额外支持 C#,需要你机器上装好 .NET SDK(4.x 支持 .NET 8/9;4.5 起还支持 NativeAOT 编译发布)。
另有一条新路径值得知道:4.7 里 GABE(Godot Android Build Environment)已到稳定版,配合安卓编辑器,你甚至可以全程在安卓平板上开发并导出游戏——这在所有游戏引擎里是头一份。
二、项目管理器与编辑器:四个核心区域
新建项目(选兼容性渲染器即可,后文第七级细讲),进入编辑器。界面分成四个区域,对应四种心智:
- 左上 · 场景面板(Scene):你的「世界」由一棵节点树构成。这里是树的目录。
- 中上 · 视口(Viewport):所见即所得的编辑空间,2D/3D 切换在左上角标签。
- 左下 · 文件系统(FileSystem):项目目录的镜像,所有资源(res:// 虚拟路径下)都在这里。
- 下方 · 检查器(Inspector)+ 底部停靠区:Inspector 显示当前选中节点的属性;底部依次是动画、调试器、音频、输出等面板。
一个 4.7 的小甜点:底部面板现在可以拖到编辑器任意边、还能浮动(4.6 引入的统一停靠系统),把动画编辑器拖到右边、输出面板拉到第二屏幕,都是合法操作。
三、亲手搭第一个场景:一个会弹跳的方块
不写代码,纯点鼠标,十分钟内做完:
- 按 F5 会提示选主场景——先不管,我们从建场景开始。点场景面板的「其他节点」,搜
CharacterBody2D,创建。 - 选中它,按
Ctrl+A(添加子节点)依次加三个子节点:CollisionShape2D(在 Inspector 里给它指定一个 RectangleShape2D)、Sprite2D(临时用 Godot 内置图标图标 texture,或随便拖一张图进 FileSystem 再指过去)、以及一个AnimationPlayer。 - 再建一个场景当地面:
StaticBody2D+CollisionShape2D(长条矩形)+ 一个有颜色的ColorRect或Polygon2D当外观。 - 把地面场景实例拖进主场景(直接从 FileSystem 里把 .tscn 文件拖进视口)——这一下就是「场景实例化」,Godot 组合世界的全部秘密。
- 给 CharacterBody2D 挂一个简单的 GDScript(脚本编辑器在顶部「脚本」标签,快捷键 F2):
extends CharacterBody2D
const SPEED := 300.0
const JUMP := -400.0
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP
var direction := Input.get_axis("ui_left", "ui_right")
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
按 F5 运行。一个会左右移动、会跳、落在地面上的方块诞生了。
这里先不求全懂,只标记三个「锚点」,后文会逐一展开:
velocity不是你自己声明的变量,move_and_slide()也不是你写的函数——它们是CharacterBody2D基类自带的,引擎替你处理了碰撞滑动。_physics_process(delta)是引擎每物理帧回调的函数,delta是帧间隔秒数,一切与时间相关的运动都要乘它。get_gravity()是 4.3 加入的便捷方法,自动读项目重力设置——不再需要手写Vector2(0, 980)。
四、最该先养成的四个习惯
- 重命名一切。新建节点的默认名(
CharacterBody2D、Sprite2D)是万恶之源,改成Player、IdleSprite。命名即文档。 - 用
%唯一名称。在场景面板右键节点勾选「作为场景唯一名称访问」,之后任何脚本里$%Player都能直达,改层级结构也不会断引用。这是 4.x 对旧版$A/B/C长路径的正解。 - 先建输入映射再写输入。项目设置 → 输入映射,把
ui_accept换成你自己定义的jump(绑定空格 + 手柄 A 键),代码里就永远写Input.is_action_just_pressed("jump"),键位变更零成本。 - 一开场就开 Git。Godot 项目是纯文本(.tscn / .gd / .tres),天生适合版本控制。官方文档有专门的「与 Git 共舞」章节,把
.godot/目录加进 .gitignore 即可。
五、常见第一晚事故清单
- 运行后窗口一闪而过:没设主场景。第一次按 F5 会弹窗让你指定,选当前场景即可。
- 方块穿地而过:多半是
CollisionShape2D忘了指定 shape,或地面忘了用StaticBody2D——ColorRect只是外观,外观节点不参与物理,这是新人第一课。 - 画面黑漆漆(3D 项目):3D 需要光源或环境光,
WorldEnvironment+ 一盏DirectionalLight3D是标准开局三件套的其中两件。 - 中文界面:编辑器 → 设置 → 常规 → 界面 → 编辑器语言,官方中文翻译完整可用。
*本篇配图:编辑器四象限与场景树生长。*
上一篇跑通了一个方块。这一篇回答更根本的问题:Godot 为什么这样设计?理解了「节点 + 场景 + 信号」三件套,后面七级台阶全是 downhill。
一、节点:单一职责的最小单元
Godot 里没有 Unity 那种「挂一堆 Component 的 GameObject」。它的原子单位是节点(Node),每个节点只干一件事:
Sprite2D只负责显示一张图;CollisionShape2D只负责声明一块碰撞区域;Camera2D只负责「从这里看世界」;Timer只负责计时并在时间到时发一个信号。
CharacterBody2D(管物理) + Sprite2D(管外观) + CollisionShape2D(管碰撞)。功能靠树的形状来组合,而不是靠往一个对象上贴组件。这是两种哲学:Unity 是「组件斜挂在一个宿主上」,Godot 是「职责垂直长成一棵树」。节点不是随便长成一团的——它是一棵树,节点从构造上就知道自己的父与子。由此诞生了 Godot 最重要的行为模型:树就是调用链。
二、生命周期:树的呼吸节律
节点的一生按树序展开,这几个回调的顺序必须刻进肌肉记忆:
_init() —— 对象构造,还不属于树
_enter_tree() —— 被放进树(父先于子)
_ready() —— 自底向上调用:先所有子节点,最后父节点
_process(delta) —— 每渲染帧
_physics_process(delta) —— 每物理帧(默认 60 Hz,与渲染帧率解耦)
_exit_tree() —— 被移出树
最反直觉也最重要的是 _ready() 自底向上:父节点的 _ready() 跑的时候,所有子节点都已就绪。所以「初始化依赖子节点」的代码放父的 _ready() 里是安全的,这也是为什么配对资源、建立引用的惯例位置是 _ready()。
_process 与 _physics_process 的分工要背下来:移动、碰撞相关放 physics;外观、动画、UI 放 process。物理帧率固定(可在项目设置改),渲染帧率浮动(可能是 30 也可能是 240),两边的数据混用就会出现「手感时好时坏」这类玄学问题。另外 4.x 提供了 physics_ticks_per_second 与 physics/common/physics_interpolation(物理插值,4.5 又重做过),让物理步进与渲染平滑兼得——这是进阶话题,第九级再表。
三、场景:节点树的持久化单位
把一棵节点树存成文件,就是场景(.tscn)。场景是 Godot 的「类」——不是 OOP 的类,而是可复用的组合单元:
- 一个 Player.tscn 可以实例化 100 次,生成 100 个独立玩家;
- 一棵树里的每个节点都能被单独编辑、覆盖属性;
- 场景可以继承(Inherited Scene):改基类,所有派生场景自动跟进。
- 实例化:把 .tscn 从 FileSystem 拖进视口,或代码里
preload("res://enemy.tscn").instantiate()。 - 可编辑子场景(Editable Children):实例化的场景默认是「只读团块」,右键勾选后可局部改子节点属性而不动本体。
- 4.6 的独特节点 ID:从 4.6 起,节点拥有引擎内部唯一 ID,改名、移动、跨场景继承都不会再弄丢引用——旧版本里「改个名全场景报错」的著名惨案从此绝迹。官方提示:老项目需用「项目 → 工具 → 升级项目文件」重存一遍场景以获得此能力。
var enemy := ENEMY_SCENE.instantiate()
add_child(enemy) # 挂到当前节点下,_enter_tree/_ready 随即触发
enemy.queue_free() # 帧末安全销毁;立即销毁用 free(),慎用
四、信号:Godot 的解耦神经
树决定了「父子关系」,而信号(Signal)解决「兄弟之间、陌生人之间怎么说话」。
信号是观察者模式的语言级实现。节点自己不关心谁在听,只管「喊一嗓子」:
# 声明与发射
signal health_changed(new_value: int)
health_changed.emit(hp)
# 连接(代码方式)
player.health_changed.connect(_on_player_health_changed)
编辑器里则是在节点面板右下角「节点」标签页双击信号、选择接收节点,一秒连好。四条实战心法:
- 自带信号够用九成:
Timer.timeout、Button.pressed、Area2D.body_entered、AnimationPlayer.animation_finished……先查有没有现成的再自造。 - 连接用 Callable:4.x 里
connect(btn.pressed)传的是Callable对象,btn.pressed.connect(_on_pressed.bind(item_id))用.bind()附带参数,这是与 3.x 的最大差异。 - await 让异步线性化:
await player.health_changed会挂起当前协程等信号,await get_tree().create_timer(1.5).timeout就是一行延时——游戏脚本从此有了「读起来像流程」的写法。 - 断连要负责:被销毁的对象的连接会自动清理,但长生命周期对象连接短生命周期信号时要
disconnect或用CONNECT_ONE_SHOT。
五、组合优于继承:一个真实的设计对比
需求:敌人有两种——哥布林会近战,蝙蝠会飞但血薄。继承派的写法是 Enemy -> GoblinEnemy / BatEnemy 层层派生;Godot 的组合派则是:
Player与Enemy都拥有Health.tscn(一个管血量的可复用场景:节点 + 信号died+hurt(amount)方法);- 哥布林 = 移动场景(地面型)+ 近战武器场景 + Health;
- 蝙蝠 = 移动场景(飞行型)+ 远程武器场景 + Health(血量上限参数不同)。
六、本篇速记
- 节点单一职责,树即调用链;
_ready()自底向上。 - 场景 = 可实例化、可继承、可局部覆写的节点树文件。
- 信号解耦通信,Callable + await 是 4.x 语法。
- 组合横切场景,继承留给真正的 is-a。
*本篇配图:一棵场景树,信号沿树流动。*
GDScript 长得像 Python,但它不是 Python——它是为「节点树上的游戏逻辑」量身定制的领域语言。本篇从类型系统写到 4.5 新特性,顺路扫清新人最常见的十个坑。
一、语言定性:解释、动态、但鼓励静态
GDScript 是 Godot 自研的解释语言,运行于引擎内置 VM,与引擎零胶水——它访问的一切节点、属性、信号都是引擎原生对象。4.x 的关键取向:语法保持动态灵活,但工具链全力推静态类型。写上类型标注,编辑器就有补全、有重构、有编译期告警,性能也更好。本篇所有示例一律静态类型。
基础语法一屏放得下:
extends CharacterBody2D
class_name Player # 全局类名,任何脚本都可直接引用 Player 类型
const MAX_HP := 100 # 常量,:= 由右侧推断类型
var hp: int = MAX_HP
var speed: float = 300.0
@export var jump_force: float = -400.0 # 导出到 Inspector,设计师可调
@onready var sprite: Sprite2D = $%Sprite # 就绪时求值
func take_damage(amount: int) -> void:
hp = maxi(hp - amount, 0) # maxi/minf 是 4.x 的全局工具函数
if hp == 0:
died.emit()
两个语义细节必须第一时间讲清:
@onready var x = $...:$取节点是「当下」求值,写在普通 var 初始化里会因子节点未就绪而报 null。@onready把求值推迟到_ready(),配合上一级讲的「自底向上」节律,正好安全。:=与=::=声明并推断类型(编译期定死),=赋值给已声明变量。静态类型项目的纪律是「声明用:=,赋值用=」。
二、类型系统:鸭子打字的护栏
GDScript 的类型体系要点:
- 内建值类型:
int、float、bool、String、Vector2/2i/3/3i/4、Color、Rect2、Transform2D/3D……注意 Vector2 与 Vector2i 是不同类型,像素用i、米用浮点,混用会隐式转换但会告警。 - 容器带类型参数:
var scores: Array[int] = []、var dict: Dictionary[String, Node] = {}。 typed Array 是 4.x 强推的,混进异型会运行时报错——这是护栏不是枷锁。 Variant是「任何东西」,静态类型的逃生门;能不用就不用,用了要as转换或is检查。- 枚举与字典都是一等公民:
enum State {IDLE, RUN, JUMP},甚至enum {A, B}匿名枚举直接映射常量。 match语句替代 switch,支持数组/字典/类型模式匹配,比 if-else 链可读性高一截。
三、信号与异步:await 是游戏脚本的灵魂
上一级讲过信号连接,这里补全语言的另一半——协程:
func play_intro() -> void:
$AnimationPlayer.play("intro")
await $AnimationPlayer.animation_finished # 挂起,动画完再回来
await get_tree().create_timer(1.5).timeout # 一行延时
$Music.play()
var result := await dialog.ask_choice() # 甚至能接收信号返回值
await 之后,函数从这里「暂停」,控制权归还引擎,事件到了再续。把时序流程写成线性文字,这是 GDScript 对游戏脚本最实在的贡献。对比一下回调地狱版的同一个逻辑,高下立判。
注意:调用一个含 await 的函数时,它也会返回一个「可 await 的协程」;如果不 await,函数会跑到第一个 await 点就返回——新人常在这里埋下「为什么后半段没执行」的悬案。
四、4.5 新特性:变参函数与抽象类
变参函数——函数可以接收任意多个参数:
func sum(first: float, ...rest: Array) -> float:
var total := first
for n in rest:
total += n
return total
sum(1.0) # 1.0
sum(1.0, 2.0, 3.0) # 6.0
抽象类与抽象方法——基类只定契约、禁止实例化:
# animal.gd
@abstract class_name Animal
extends Node
@abstract func cry() -> void
# cat.gd
class_name Cat
extends Animal
func cry() -> void:
print("Meow!")
子类不实现 cry() 直接报错。这对「武器系统」「技能系统」这类「一堆兄弟类共享同一接口」的结构是量身定做——第三级这里正好呼应第二级的「组合优于继承」:抽象基类定接口,具体场景做实现。
五、十坑清单(新人血泪浓缩版)
- 类名与文件名:
class_name Player后,脚本全局叫 Player,但$Player取的是节点名,两码事,别混。 self与省略:GDScript 里方法调用默认就近解析,但静态类型下跨脚本调用优先用player.take_damage(5)显式对象,可读性优先。super:覆写_ready()时如果父类有逻辑要保留,必须写super._ready()——不写就是整个替换,不会自动链。- 静态变量:
static var是 4.1 加入的,挂在类上而非实例上,做全局计数器、注册表好用,但要自己管理生命周期。 - getter/setter:
var hp: int = 100: set(v): hp = clampi(v, 0, 100)——属性拦截写在冒号后,不是 Java 式的setHp()。 - 字符串格式化:
"%s 的血量 %d" % [name, hp]或 4.x 更推荐的"血量 {hp}".format({"hp": hp});%在格式串里的坑与 Python 同源。 is_instance_valid(obj):延迟回调、信号触发时对象可能已销毁,调用前先验尸,否则「Instance is invalid」是输出面板常客。- 整数除法:
1/2得 0,1.0/2.0得 0.5。像素坐标混算时最常见的诡异 bug 来源。 move_and_slide()无参:4.x 里它不接参数,速度全在velocity成员变量里,3.x 教程的旧写法会编译错误。_process里别做重活:每帧都跑的代码是性能放大器,缓存引用(@onready)、避免每帧get_node、字符串拼接进_process是三大典型反模式。
六、工具链:LSP、格式化与调试
- LSP:编辑器 → 编辑器设置 → 网络 → 语言服务器,开启后 VS Code 装 godot-tools 插件即可获得全量跳转与补全。
- 断点调试:脚本行号左侧点击设断点,F5 运行后底部调试器面板可看调用栈、变量、监视;4.6 新增 Step Out 按钮,跳出当前函数一步到位。
- 远程检查器:运行中游戏里的节点树可以实时选中改属性——4.5 还支持了多选与批量改,调手感神器。
- 对象快照(4.6):调试器可对运行中游戏做 ObjectDB 快照并对比两次快照,谁创建了、谁没销毁一目了然——查内存泄漏从此不用猜。
*本篇配图:代码与信号流。*
本篇把前三级串成一条完整的 2D 主线:移动手感、瓦片地图、相机、碰撞分层。读完你会有一个能玩的小游戏雏形——这是整个系列最重要的里程碑。
一、2D 的世界单位:像素即真理
Godot 2D 的单位就是像素,默认 gravity 980(像素/秒²),一个 128×128 的窗口一格就能放下角色。3D 才是「米」的世界。这个「所见即像素」的直白,是 Godot 2D 工作流口碑好的根本原因。
第一步永远是项目设置三连:
- 显示 → 窗口 → 视口宽高:设成你想要的逻辑分辨率(如 640×360,像素风标配);
- 拉伸模式:
canvas_items、宽高比keep——窗口怎么缩放,游戏内像素都清晰锐利; - 默认纹理过滤:像素风选 Nearest(4.7 还给 3D 视口加了最近邻缩放选项,复古味 3D 也能锐利)。
二、移动手感:CharacterBody2D 的调参艺术
第一级那个方块已经会跑会跳了,但「会动」和「手感好」差着十倍距离。手感三要素:
- Coyote Time(土狼时间):离开平台后仍可跳窗的宽限期,通常 0.1 秒。人类反应有延迟,没这个宽限的跳跃永远「差半拍」。
- Jump Buffer(跳跃缓冲):落地前 0.1 秒按跳,落地瞬间自动起跳。手感廉价感的最大来源就是「按了没跳」。
- 可变跳跃高度:松开跳跃键就削减上升速度,短按小跳、长按大跳。
extends CharacterBody2D
const SPEED := 300.0
const ACCEL := 1500.0
const FRICTION := 2200.0
const JUMP_VELOCITY := -420.0
const COYOTE_TIME := 0.1
const JUMP_BUFFER := 0.1
var coyote_counter := 0.0
var buffer_counter := 0.0
func _physics_process(delta: float) -> void:
if is_on_floor():
coyote_counter = COYOTE_TIME
else:
coyote_counter -= delta
velocity += get_gravity() * delta
if Input.is_action_just_pressed("jump"):
buffer_counter = JUMP_BUFFER
else:
buffer_counter -= delta
if buffer_counter > 0.0 and coyote_counter > 0.0:
velocity.y = JUMP_VELOCITY
buffer_counter = 0.0
coyote_counter = 0.0
if Input.is_action_just_released("jump") and velocity.y < 0.0:
velocity.y *= 0.5 # 可变跳跃高度
var dir := Input.get_axis("move_left", "move_right")
if dir:
velocity.x = move_toward(velocity.x, dir * SPEED, ACCEL * delta)
else:
velocity.x = move_toward(velocity.x, 0.0, FRICTION * delta)
move_and_slide()
这三个常量没有任何一个「正确值」——手感是调出来的,把上面六个参数全 @export,运行时在远程检查器里现场拧,是打磨手感的标准姿势。
三、TileMapLayer:一张图铺一个世界
4.x 的瓦片系统由 TileSet(资源:图集 + 物理形状 + 地形规则)与 TileMapLayer(节点:一层瓦片)组成。4.0 曾用 TileMap,4.3 改为多层 TileMapLayer,官方明确建议一瓦片层一个节点。
关键进化在 4.5:TileMapLayer 的物理从「一格一刚体」改成了相邻格碰撞形状自动合并——一整片地面在物理引擎里不再是几千个小刚体,而是少数几个大形状。官方公告原话是重写(reworked from the ground up),对依赖物理的 2D 场景是量级级优化。升级注意:get_coords_for_body_rid() 返回值会变,依赖旧值的老代码要看迁移指南。
TileSet 编辑器里的高频操作:
- 给图集勾选物理层,逐格画碰撞多边形(地形可以只给顶面碰撞,做「从下往上穿过」的平台);
- 地形集(Terrain Set)画好连接规则后,铅笔刷一笔刷出自动拼接的地块;
- 4.6 起场景瓦片可以 90 度旋转,动画宝箱、火把直接当瓦片摆。
四、碰撞分层:矩阵决定谁撞谁
项目设置 → 层名称(Layer Names → 2D Physics),把 1-5 层命名成 player / enemy / world / pickup / hazard,之后每个物理节点的 Collision → Layer/Mask 直接勾语义名。
规则一句话:Layer 是「我是谁」,Mask 是「我关心谁」。玩家 Layer=player、Mask=world|enemy|pickup;拾取物改成 Area2D + Mask=player,敌我互撞就永远不会发生。新人把 Layer 和 Mask 搞反是 2D 篇第一事故,遇到「怎么都检测不到」先查这里。
五、相机跟随:平滑不是弹簧越软越好
Camera2D 设为 Player 子节点即可自动跟随,但直接挂上去是「像素级死锁」,画面硬邦邦。调法:
- Position Smoothing 开启(速度 5-8 之间开始试);
- Drag Margins 开启后,画面只在角色拖到边缘时才动,适合大场景;
- Limits 四项必设(左/右/上/下边界),否则关卡边缘会露出「世界之外的虚空」——平台游戏的经典穿帮。
Tween 或 lerp 平滑过去,游戏立刻有了「镜头语言」。这个效果 30 行内可写完,建议自己试。六、把方块换成角色:Sprite2D 与 AnimatedSprite2D
- 单图角色:
Sprite2D够用,翻转用flip_h; - 帧动画角色:
AnimatedSprite2D+ SpriteFrames 资源,在编辑器里把精灵表切成帧、命名 idle/run/jump/fall 动画; - 联动逻辑:在移动脚本里按状态切换播放——
if not is_on_floor(): play("jump" if velocity.y < 0 else "fall")。
AnimationPlayer 与状态机,AnimatedSprite2D 是轻量方案,两者不冲突——像素游戏的帧动画走 AnimatedSprite2D,骨骼/属性/位移混合动画走 AnimationPlayer。七、本篇交付物清单
完成本篇,你手上应该有:
- 一个带土狼时间、跳跃缓冲、可变跳跃的玩家场景;
- 一张用 TileMapLayer 铺的关卡,含自动拼接地形与单向平台;
- 一个带平滑、边界限制、前瞻偏移的相机;
- 碰撞层语义化命名、敌人场景雏形。
*本篇配图:小方块跳跃平台与碰撞层。*
2D 主线有了骨架,本篇给它血肉:AnimationPlayer 的轨道系统、AnimationTree 的状态机与混合空间,外加 4.x 动画系统的重要更新。
一、AnimationPlayer:不只是动 Sprite
新手对 AnimationPlayer 的第一误解是「播放图片序列的工具」。它的本质是属性轨道系统——任何节点的任何属性都能被动画驱动:
- Sprite2D 的 position、modulate;
- 光照的 energy(做灯光闪烁);
- Camera2D 的 offset(做镜头震动);
- 甚至脚本里
@export的自定义变量。
- 值轨道(Value):通用属性,支持关键帧插值与缓动曲线;
- 位置/旋转/缩放 3D 轨道:4.3 重做后支持骨骼重定向(retargeting);
- 方法调用轨道(Method Call):在某一帧调任意函数——脚步声、攻击判定框开关的常规解法;
- Bezier / 音频 / 动画轨道:曲线编辑、配音、以及「动画里套动画」。
animation_finished 信号 + await 是演出脚本的万能胶水:攻击动画结束才解锁输入、开场动画结束才生成敌人,全都是一行 await 的事。二、动画状态机:AnimationTree 的正解
角色状态一多(idle/run/jump/fall/attack/hurt),「在 _physics_process 里手写 if 切动画」就会腐化成面条。正解是 AnimationTree:
- 给角色挂
AnimationTree节点,Tree Root 选 StateMachine; - 把 AnimationPlayer 里的每个动画拖成状态节点,用
play()的 travel 系 API 切换;
@onready var anim_tree: AnimationTree = $%AnimTree
@onready var state_machine := anim_tree.get("parameters/playback") as AnimationNodeStateMachinePlayback
func _physics_process(_delta: float) -> void:
if is_on_floor():
state_machine.travel("run" if absf(velocity.x) > 10.0 else "idle")
else:
state_machine.travel("fall" if velocity.y > 0.0 else "jump")
状态机的三层价值:转移可以带条件与混合时间(0.2 秒的 crossfade 让切换如丝般顺滑);转移有优先与回退语义(hurt 状态可以打断 run,但不能被打断 run);逻辑与表现解耦(动作代码只管 travel,动画细节全在编辑器里调)。
- BlendSpace2D:二维混合空间,最经典用途是 3D 角色的移动动画——横轴速度、纵轴高度,idle/walk/run 四向动画按向量自动混合。
- One-shot 子机:攻击、受击这类「打完回原状态」的一次性动画用它,与主状态机天然隔离。
三、骨架动画与 4.3 重做的红利
Godot 4.3 对 3D 动画做了大改:骨骼重定向让任何 humanoid 骨架模型适配同一套动画库;SkeletonModifier3D 提供程序化骨骼调整的统一挂点。这个方向在 4.6 开花——全新 IK 框架:
- 确定性求解器:
TwoBoneIK3D(双骨,手臂够到目标点)、SplineIK3D(链条/尾巴); - 迭代求解器:
FABRIK3D、CCDIK3D、JacobianIK3D; - 基于
IKModifier3D(SkeletonModifier3D 家族)的模块化设计,可互相组合; - 支持约束(关节扭转与角速度限制),目标可以绑到任意 3D 节点——「手吸附到武器把手」从此是属性配置而非代码。
四、程序化动画:Tween 与代码驱动
不是所有动效都值得建动画资源。临时性、参数化、一次性的动效用 Tween:
var tw := create_tween()
tw.tween_property(sprite, "position:y", -12.0, 0.12).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
tw.tween_property(sprite, "position:y", 0.0, 0.18).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
要点:
create_tween()挂在创建者节点上,节点亡则 Tween 亡,自动清理;.set_trans()/.set_ease()提供三十多种缓动(Quad/Bounce/Elastic/Back……),UI 弹跳手感全靠它们;.set_loops()循环、.set_parallel()并行、.chain()串行、.tween_interval()插入等待;- 4.7 新增
Tween.tween_await():让 Tween 原地暂停直到指定信号发出——对话框与过场演出里「动画等台词」从此一行写完。
_process 里直接改属性。五、性能与工作流小贴士
- 动画越长、轨道越多越吃 CPU(属性插值在主线程),长演出优先考虑 shader/粒子实现;
AnimationPlayer.play()同一动画重复调用不会重置进度(可用play("name", 0.2, 1.0, true)显式控制);- 大量同款动画的资源复用走 Resource(.tres),动画资源可以跨场景共享;
- 2D 精灵图动画也可以走 Sprite2D + AnimationPlayer 的 texture 轨道,但帧动画优先 AnimatedSprite2D,少一层轨道开销。
*本篇配图:状态机圆环流转。*
3D 的门槛一半在数学,一半在心理。本篇只取必要集合:坐标系与朝向、节点家族、模型导入、光照相机。目标是看完不慌,能在 3D 视口里搭出一个能探索的小房间。
一、坐标系:先立规矩
- 右手坐标系,Y 向上。X 右、Y 上、Z 朝屏幕外——与 Unity(左手)不同,与 Blender 相同。
- 位置是
Vector3,旋转是Vector3欧拉角(度)或Quaternion(四元数)。代码里动画旋转优先四元数,欧拉角万向锁是 3D 第一坑。 - 节点的
transform是Transform3D(基向量 + 原点),global_position与position的区别从 2D 一脉相承:局部 vs 世界。 - 前方向约定:Godot 里 -Z 是前方(相机看向 -Z),模型导入后「脸朝 Z 正方向」的八成要转 180 度。
二、3D 节点家族:把 2D 的心智映射过来
对照表比解释省力:
| 2D | 3D | 说明 |
|---|---|---|
| CharacterBody2D | CharacterBody3D | 手动控速 + move_and_slide(),玩家/NPC 首选 |
| RigidBody2D | RigidBody3D | 物理引擎接管,扔、砸、滚 |
| StaticBody2D | StaticBody3D | 静态碰撞,墙、地 |
| Area2D | Area3D | 触发器、感知区域 |
| Sprite2D | MeshInstance3D + Mesh | 外观载体换成网格 |
| Camera2D | Camera3D | 3D 里没有「自动跟随」,必须自己写或挂脚本 |
4.6 还有个实用小功能:Mesh 菜单一键把 box/sphere/cylinder/capsule 网格转成匹配的 CollisionShape3D——「给模型配碰撞」这个 3D 日常动作从此不用再手动对齐。
三、导入管线:glTF 是亲儿子
- 首选 glTF 2.0(.gltf/.glb),Godot 官方标准格式,PBR 材质、骨骼、动画全保留;
.blend可直接导入(需本机装 Blender);FBX 走 ufbx 导入器(4.3 起内置)。 - 导入后模型是一个场景,可「继承场景」实例化后覆写属性;材质在导入面板或 MeshInstance 的 Surface Override 里调。
- 4.5 修了骨架层级里非关节节点的处理,并引入「Naming Version」——老资源保持旧行为、新资源用新规则,迁移手册有细节。
- 网格简化(LOD)在 4.6 拿到组件剪除:多部件网格生成 LOD 时更好保留原形。
四、光照三件套与阴影心智
3D 光源家族:DirectionalLight3D(太阳,影响全场景)、OmniLight3D(点光,向四面八方)、SpotLight3D(聚光)、以及 4.7 新成员 AreaLight3D——矩形面光源,电视屏幕的柔光、霓虹广告牌、磨砂窗透光,以前要「自发光材质 + GI」模拟,现在是一个节点直接发光,阴影与反射都更柔更真。
新房间标准开局:
WorldEnvironment:环境设置容器(天空、雾、环境光、色调映射全在这);DirectionalLight3D:主光,开阴影(Shadow → Enabled);Camera3D:加个Camera3D子节点到玩家上,初学者最易忘的第三件套就是它。
- SDFGI:有向距离场 GI,大世界实时 GI,Forward+ 专属,编辑器一键开;
- VoxelGI:体素 GI,小场景更准,可实时刷新动态光源;
- LightmapGI:烘焙光照图,性能最好,静态光专用;4.8 dev 还在给方向光照图加镜面高光;
- SSAO/SSIL:屏幕空间环境光遮蔽/间接光,作为上面任一方案的「增味剂」。
五、给房间装上「可探索」:十分钟 Demo 清单
- 地面:
CSGBox3D(Use Collision勾上)——CSG 是 3D 里的原型利器,布尔运算直接在编辑器里挖门凿窗,正式管线再换导入模型;4.7 给 CSG 加了 Autosmooth(按平滑角自动分光滑面/硬面),原型也好看。 - 玩家:
CharacterBody3D+CollisionShape3D(胶囊体)+Camera3D(弹簧臂式跟随可手写 20 行,或用社区 CameraRig)。 - 移动脚本与 2D 几乎同构,只是向量升到三维:
extends CharacterBody3D
const SPEED := 5.0
const JUMP := 4.5
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP
var input_2d := Input.get_vector("move_left", "move_right", "move_up", "move_down")
var dir := (transform.basis * Vector3(input_2d.x, 0, input_2d.y)).normalized()
if dir:
velocity.x = dir.x * SPEED
velocity.z = dir.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
看清楚了:move_and_slide() 一个字没变——2D 与 3D 在 Godot 里是同一套 API 的两次实例化。这就是「同构」的含义:学会一个,等于学会两个。
下一篇,第七级台阶:渲染与着色器——三大渲染方法怎么选、4.7 的 HDR 输出与 AreaLight3D 实战、着色器语言第一个程序,3D 视觉的进价与回报全在本篇。
*本篇配图:三轴坐标与光照场景。*
3D 搭好了,本篇回答「画面是怎么画出来的」:三大渲染方法的取舍、4.7 三大渲染新货(HDR 输出、AreaLight3D、DrawableTexture2D)、着色器语言入门。
一、三大渲染方法:怎么选不纠结
项目设置的第一个大决定:Rendering → Renderer。三个选项的本质是图形 API 与特性集的组合:
- Forward+:Vulkan/D3D12/Metal,桌面全特性旗舰——SDFGI、VoxelGI、SSR 全开,PC 游戏默认。
- Mobile:Vulkan,砍掉重型 GI,换来手机 GPU 的发热与续航安全;4.7 的 Vulkan 子采样图(subsampled images)让它的 foveated rendering 性能大涨,官方现已明确建议新 XR 项目也用它。
- Compatibility:OpenGL 3.3 / WebGL 2 / GLES3,覆盖老设备与 Web,特性最少但兼容性最广——Web 导出与低端机唯一选项。
顺带一记 4.6 的重大默认变更:Windows 上 D3D12 成为新项目默认后端(Vulkan 仍在菜单里),跨平台驱动一致性更好;4.6 还顺手修了一批 Mali/Adreno 移动 GPU 的 Vulkan 崩溃。
二、4.7 三大渲染新货逐个说
- HDR 输出。Godot 内部光照计算一直是 HDR 精度,但显示器端过去只能 SDR 压缩输出。4.7 打通了「最后一公里」:在 Windows、macOS、iOS、visionOS、Linux(Wayland)上,游戏可以把内部 HDR 模拟完整送到支持 HDR 的屏幕上——更艳的色彩、更炸的高光、2D/3D 通吃。开启在项目设置 Rendering → Viewport → HDR Output。注意浏览器对 HDR 呈现支持不一(如 Firefox 就不支持 HDR 图像)。
AreaLight3D。矩形面光源节点。以前做「电视屏幕照亮房间」要自发光材质加 GI 间接模拟;现在矩形面直接实时发光,柔影、镜面反射、灯管、霓虹招牌全是原生效果。它是 4.x 光源家族的第四个成员,与 DirectionalLight/OmniLight/SpotLight 并列。DrawableTexture2D。过去想在纹理上画东西只有两条路:Viewport 方案(功能全但重)或直接操作RenderingDevice(性能好但门槛劝退)。4.7 给了个中间层——一套简单 API 直接往 2D 纹理上绘制,血迹、涂鸦、程序化贴图、小地图都变得一行调用的事。
agx_white/agx_contrast)、反射探针八面体贴图(省 GPU 省显存)。三、着色器语言:第一支 Shader 十分钟
Godot Shader Language(GDShader)语法近 GLSL,但是面向渲染类型的:spatial(3D 表面)、canvas_item(2D)、sky(天空)、particles(粒子)、fog(体积雾)。五分钟写一个 2D 扫描线:
shader_type canvas_item;
uniform vec4 scan_color : source_color = vec4(0.0, 1.0, 1.0, 1.0);
uniform float intensity : hint_range(0.0, 1.0) = 0.3;
void fragment() {
float scan = sin(UV.y * 400.0 + TIME * 4.0) * 0.5 + 0.5;
COLOR = texture(TEXTURE, UV);
COLOR.rgb = mix(COLOR.rgb, scan_color.rgb, scan * intensity);
}
要点注解:
shader_type必写,决定这个 shader 活在哪类节点上;uniform是从 GDScript 侧传参的入口:material.set_shader_parameter("intensity", 0.5),: source_color这类 hint 决定编辑器 UI(颜色选择器、滑条范围);fragment()是逐像素回调,UV、COLOR、TEXTURE、TIME是内建变量;VERTEX/NORMAL在vertex()里玩;- 建一个
ShaderMaterial,填 shader,挂到任意 Sprite2D 的 Material 槽——立刻生效。
vec2 v4 = UV; 的同时编辑器里直接看到效果,不用再编译后跳去工作区看。ShaderGraph 之外的手写党,体验直接对齐专业 IDE。spatial 进阶一句话路线:BaseMaterial3D(免代码,先解决 80%)→ 标准 shader(改 PBR 各通道)→ render_mode(unshaded/blend_add/cull_disabled…)→ Compositor Effects(4.3 引入的全屏后期管线钩子)。
四、2D 渲染的暗知识
- 2D 光照:
PointLight2D/DirectionalLight2D+ CanvasModulate 做昼夜,材质混合模式(Add/Sub/Mix)做光效叠加; - 批处理(Batching):2D 靠「相同纹理的元素连续提交」合并 draw call。破坏合并的因素:交替使用不同纹理、跨
CanvasItem层级夹叠、使用 shader 的元素各自成批。同屏元素数暴涨时优先查批处理是否被打散; CanvasGroup:把一组子节点先画成整体再上效果(透明度、shader),解决「半透明重叠露馅」的经典问题;GradientTexture2D新增FILL_CONIC(4.7):CSS 锥形渐变,2D 里画「假 3D 高光」的利器。
五、画面调优清单(交给明天的你)
- 画质基线:Environment 里开
Screen-space AA(SMAA 4.5 起)、Fog、Glow(4.6 起默认 Screen 混合、tonemapping 前混合,为 HDR 铺路); - 色彩管线:2D 项目若开 HDR 2D(4.6 起全链路高精度),颜色渐变不再断带(debanding 同步进 Mobile 渲染器);
- 性能自查顺序:先 draw call(RenderingServer 监视器)→ 再 overdraw(半透明叠加)→ 再 shader 复杂度——第七级的结论会在第九级用到。
*本篇配图:HDR 光照管线。*
功能都实现了,为什么改一行崩三处?本篇讲两件事:Control 节点体系怎么搭 UI,以及游戏级别的架构(自动加载、信号总线、依赖注入)怎么防腐化。
一、Control 体系:锚点、容器与主题
UI 全家是 Control 基础类的子孙,与 2D 游戏物件(Node2D)分属两族。三个核心概念:
- 锚点(Anchor)与边距(Offset):Control 的布局由「四角锚在父矩形的哪里 + 距锚点偏移多少」决定。全屏 UI 锚四角,血条锚左上角……编辑器顶栏的锚点预设(居中、全矩形、两列布局)覆盖 90% 场景。
- 容器(Container):让布局自动排。
HBoxContainer/VBoxContainer排队、GridContainer网格、MarginContainer加边距、CenterContainer居中、ScrollContainer滚动。手动摆位与容器混用是 UI 错乱的第一原因——容器会重排子节点,你的手动 position 会被它吃掉。容器内要微调位置怎么办?4.7 给了正解:offset_transform属性(translate/rotate/scale),不影响容器布局,语义类似 CSS 的transform,做按钮滑入、缩放淡出正合适;它还带开关控制变换是否影响鼠标命中。 - 主题(Theme):一个
.tres资源统管全项目 UI 皮肤(字体、颜色、九宫格图)。项目设置里设为默认主题,或按节点局部覆盖。4.6 的新编辑器主题「Modern」本身就是官方对主题系统的自信展示。
RichTextLabel(BBCode 富文本,4.7 支持图片随字号缩放 [img height=1em])、Tree(4.7 拖放带落点指示)、PopupMenu(4.7 可加搜索栏过滤)、TabContainer(拖资源时悬停即切页)。调布局时的好帮手是 4.6 的 MarginContainer 可视化——选中即在视口里画出边距区。UI 里还有个反直觉的点:Control 也有 _gui_input(event),点击/悬停/滚轮不走 _input 走它,配合 mouse_filter(Stop/Pass/Ignore)三态控制事件穿透。
二、自动加载(Autoload):全局单例的正路
需求:金币数、存档管理、音效播放器……任何「跨场景活着的对象」。Godot 的答案不是静态类,是 Autoload:项目设置 → 自动加载,把一个场景/脚本注册为树根常驻子节点。
# game.gd —— 注册为 Autoload "Game"
signal coin_changed(total: int)
var coins := 0
func add_coin(v: int = 1) -> void:
coins += v
coin_changed.emit(coins)
任何脚本里直接 Game.add_coin(),任何 UI 里 Game.coin_changed.connect(...)。它与场景树同生共死,切场景不销毁,get_tree().paused 时可选择是否暂停(自动加载设置里的 Process Mode)。
克制原则:Autoload 超过五个就该警惕——它本质是全局变量,滥用会重新发明「所有代码耦合所有代码」。
三、信号总线:把「谁通知谁」变成「谁订阅谁」
传统写法:敌人在死亡时找到 UI 节点、找到存档管理器、找到音效管理器——调用方持有所有被调方引用,链条越拉越长。
信号总线的写法:定义一个 Events Autoload 只装信号,各方只跟它说话:
# events.gd —— Autoload "Events"
signal enemy_died(enemy: Node2D)
signal player_damaged(hp: int)
# 敌人只管喊
Events.enemy_died.emit(self)
# UI / 音效 / 存档 各自订阅,互不相识
Events.enemy_died.connect(ui.show_kill_feed)
Events.enemy_died.connect(sfx.play_death_sound)
依赖方向从「网状」变「星形」:新增一个「击杀计数成就系统」=写一个新订阅者,不改任何旧代码。这是 Godot 官方文档「使用信号解耦」一节的精神,也是 MVC 在游戏语境的对应物。
四、场景与脚本的组织:目录即架构
推荐的中型项目布局(官方演示项目同款思路):
res://
├─ autoload/ # Game.gd, Events.gd, SaveManager.gd
├─ scenes/
│ ├─ main/
│ ├─ player/ # player.tscn + player.gd 同名同目录
│ ├─ enemies/
│ └─ ui/
├─ assets/ # 美术、音频
├─ resources/ # .tres 数据(武器表、关卡参数)
└─ shaders/
三条纪律:
- 场景与脚本同名同目录(player.tscn 旁就是 player.gd),移动即整体移动;
- 数据驱动:武器、关卡这类「一堆同类配置」用自定义
Resource(@export的类做成 Weapon.tres 文件),策划改表不改码; - 场景切换统一走一个函数(如
Game.goto_scene("res://scenes/main/level.tscn")),散落各处的change_scene_to_file是调试灾难。
五、暂停与流程控制
游戏暂停不是停 process 那么简单——get_tree().paused = true 后:
- 默认所有节点跟着停(Process Mode 继承);
- 设
PROCESS_MODE_ALWAYS的节点照常跑(暂停菜单、Tween 需要的 UI); PROCESS_MODE_DISABLED彻底停,WHEN_PAUSED只在暂停时跑。
PROCESS_MODE_ALWAYS + get_tree().paused,三行框架。六、本篇心法
- 布局交给容器,装饰交给 offset_transform,皮肤交给 Theme;
- 全局状态用 Autoload,但保持五个以内;
- 事件走信号总线,依赖星形化;
- 目录结构即架构,数据用 Resource,切换走单点。
*本篇配图:UI 锚点与信号总线。*
写得出还要跑得快、发得出。本篇前半讲性能分析的正确姿势,后半是完整发布地图——包括那个被误解最多的问题:「Godot 能上主机吗?」
一、性能分析:先测量,再动刀
Godot 内置三件测量工具:
- Profiler(调试器面板):按函数看耗时,勾「Frame Time」与「CPU 时间」,先找最贵的函数;
- Monitors(监视器):FPS、内存、draw call、对象数、视频显存——曲线级实时观测;
- Video/RenderingServer 信息:查 draw call 数与纹理显存。
- ObjectDB 快照与对比:运行时任意时刻抓「全部存活对象」快照,两份对比即知谁被创建、谁没被销毁——内存泄漏从「猜」变成「看」;
- 专业追踪器接入:Tracy、Perfetto、Instruments 一键对接(Android 上 4.7 起默认 Perfetto),GDScript/C#/GDExtension 全链路火焰图。
_process 里 get_node、每帧实例化、无节制的 Tween 与粒子。先修这些,再谈 GPU。二、渲染侧的四板斧
- 2D 批处理:同纹理连续提交合并 draw call。打散因素(贴图交替、canvas 层夹叠、独立 shader)逐项排查;图集(AtlasTexture/TexturePacker)是解药——4.7 还让
TextureRect支持 AtlasTexture 的区域重复绘制(nine-patch),低端机纹理切换再省一截。 - MultiMesh:几千个同款物体(草地、弹壳、粒子云)用 MultiMeshInstance3D,一次 draw call 画完全部。
- 合并与 LOD:静态小物件合并网格(Mesh 菜单)、远处开 LOD(4.6 的组件剪除让 LOD 保形更好)。
- 视口降采样 + 4.7 新增的最近邻缩放:低分辨率渲染再锐利放大,复古风游戏白赚一半帧率。
physics_ticks_per_second,需要更顺滑开物理插值(4.5 重做过)。线程侧:重活扔 WorkerThreadPool(add_task / add_group_task),别自己裸管 Thread 生命周期。三、导出:平台地图全览
导出前装模板(4.7 起模板下载器按平台按架构按需下载,不用再全量拉)。各平台现状:
- Windows:一键出 exe;4.5 起改元数据不再依赖 rcedit 工具(跨平台打包也能改图标与产品信息)。4.6 起 Windows 新项目默认 D3D12。
- Linux / macOS:Linux 直出;macOS 需要 Apple 开发者账号签名与公证(有 per-架构模板)。
- Web(HTML5):Compatibility 渲染器专用;4.5 起 WASM SIMD 白赚性能;SharedArrayBuffer 需要服务器正确响应头(itch.io 有现成托管方案)。
- Android:JDK + Android SDK 配置一次,之后 Gradle 导出;4.6/4.7 的 GABE 让这一切可以在安卓设备上完成;自适应图标、内嵌启动画面(4.7 可在导出面板直接编辑)、SAF 文件访问、PiP 小窗(4.7)齐备。
- iOS:需 macOS + Xcode 出 ipa;4.7 手柄支持切到 SDL3。
- visionOS(4.5+):导出为空间里的「窗口应用」,Vision Pro 首个原生支持 Godot 的平台——4.8 dev 还在加手部追踪与 PSVR2 控制器支持。
- 主机(Switch/PS5/Xbox):官方不提供,且这不是 Godot 独有的限制——主机 SDK 全在 NDA 之下,任何引擎(包括 Unity/UE)都不能公开分发主机导出模板。Godot 的解法是认证第三方:W4 Games 提供 Switch/PS5/Xbox 的官方中间件移植,另有 Lone Wolf Technology、Pineapple Works、RAWRLAB、mazette! 等一列服务商标在官方文档里。结论:能上主机,走商业服务,先和平台方签约拿到开发者资质。
- Steam Deck:官方支持(走 Linux 模板),Steam 上大量的 Godot 游戏已验证这条路。
godot --headless --export-release 自动出包。四、上线前检查清单
- 帧率目标下跑通完整一关(不只主菜单);
- 手柄全流程可玩(4.7 的
Ignore Joypad on Unfocused Application别忘了); - 存档兼容性(版本号存进存档,防升级炸档);
- 多语言(CSV
?context/?plural列,4.6 起连 C# 的Tr()都能自动提取进 POT); - 导出前跑一遍着色器预编译(4.5 的 shader baker),消灭玩家端首次编译顿挫。
*本篇配图:性能管线与多平台发布。*
最后一级。到这里,你已经能独立做游戏了。本篇回答「然后呢」:三种脚本怎么选、怎么给引擎写插件、怎么读源码,以及 4.8 与 Godot 的下一个三年。
一、三种脚本:GDScript、C#、GDExtension 的选型
- GDScript:迭代最快(改完即跑)、与引擎零胶水、文档示例最全。默认选择,90% 的游戏逻辑都该用它。
- C#:.NET 8/9,性能与生态(NuGet 全家桶)兼得。适合逻辑重、需要现成库、团队有 C# 储备的项目。4.5 的关键升级:NativeAOT 支持(发布体积更小、启动更快)与 Android 直接从 APK 加载程序集(不再解包缓存,告别权限与过期问题)。注意 Web 导出暂不支持 C#。
- GDExtension:C++(或 Rust/Swift/Kotlin 等绑定)写原生库,性能天花板,能接系统级 API。适合重度算法(物理、寻路、程序化生成)与引擎能力扩展。4.6 的两个底层升级值得知道:接口定义改用 JSON(各语言绑定自动生成更省力)、参数与返回值可标记 required(严格空值语言在编译期抓错)。
二、编辑器插件:给引擎「造轮子」
Godot 的编辑器本身用引擎的 UI 系统写成(「编辑器也跑在 Godot 上」),所以扩展编辑器就是写普通 GDScript + 一个入口:
@tool
extends EditorPlugin
func _enter_tree() -> void:
add_custom_type("Grenade", "RigidBody3D", preload("grenade.gd"), preload("icon.svg"))
func _exit_tree() -> void:
remove_custom_type("Grenade")
插件家族按扩展面分:EditorInspectorPlugin(自定义属性面板)、EditorExportPlugin(导出流程挂钩,如自动加密资源)、EditorScenePostImport(导入后处理)、MainLoop 级工具(框架定制)。@tool 注解让脚本在编辑器里就运行——预览动画的脚本、程序化生成地形必须用它。发布插件走项目设置 → 插件 → 打包 zip,可投往 4.7 全新的 Asset Store(取代旧 Asset Library,带评分与缩放预览,后台线程化不再卡编辑器)。
另一个被低估的方向:LibGodot(4.6)。引擎可作为库嵌入你自己的程序——控制主循环、做专用编辑器、混合应用。首个版本覆盖 Linux/Windows/macOS。做「产品内嵌 3D 配置器」「自有工具链」的团队,这可能是 4.x 最重要的一颗种子。
三、读源码的门径
GitHub 仓库 godotengine/godot 的目录即地图:
core/——容器、数学、OS 抽象(Variant、String、Vector3 都在这);servers/——渲染/物理/音频服务器,引擎「真正干活」的层;scene/——节点系统(scene/2d、scene/3d、scene/gui各一族);modules/——可选模块(GDScript 本体、网格、Mono);editor/、platform/——编辑器与各平台移植。
move_and_slide 到底怎么算的」→ scene/2d/character_body_2d.cpp),比通读有效十倍。编译要求:SCons + C++17 起步,全量构建按机器从十几分钟到一小时不等;scons dev_build=yes 快速迭代编译是社区标准姿势。想参与贡献:先从 issues 里挑 good first issue,官方 contributing 文档写清了 PR 规范(changelog 条目 + 测试);每版 300-400 位贡献者的数字背后,第一行往往就是这类小 PR。
四、4.8 与下一个三年
4.8 目前在 dev6(2026-09-14),已可见的方向(dev 阶段特性可能变动):
- 渲染:屏幕空间接触阴影(角色接地更实)、纹理流送(texture streaming)、ASTC 高质量压缩、alpha 通道保留(防 mipmap 过滤溶解)、Compatibility 渲染器补上 decal;
- 性能:对象属性访问提速约 1.6 倍(属性表结构重构)、运行内存省约 12MB;
- 编辑器:游戏视图默认停靠 + 工具栏重做、2D 编辑器新增 Information/Frame Time 面板、可视化 shader 的节点组、Find in Files 带替换预览;
- XR:多图层投影相机(每层独立重投影降延迟)、Vision Pro 手部追踪;
- 平台:Windows toast 通知、joypad 触控板与陀螺仪自校准、Linux Feral GameMode。
五、毕业礼:十级台阶的合拢
- 一二级给了世界观(节点、场景、信号);
- 三级给了语言(GDScript 全谱);
- 四五级给了 2D 的手(平台跳跃、动画状态机);
- 六七级给了 3D 的眼(坐标、光照、渲染、HDR);
- 八级给了纪律(架构防腐化);
- 九级给了交付(性能与发布);
- 这一级给了天花板(引擎级扩展与源码自由)。
本系列正文到此。资源索引:官方文档 docs.godotengine.org(有中文)、官方 demo 仓库 godotengine/godot-demo-projects、官方 showcase godotengine.org/showcase。4.7 迁移指南与各版发布公告链接散布在各篇。
*本篇配图:十级台阶与 4.8 前瞻。*