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 已经完成了从「玩具引擎」到「商业引擎」的惊险一跃,而且是靠 MIT 许可证 + 社区捐助(基金会月收入仅约 2 万欧元)完成的——这本身就是软件工程史上的奇观。

二、Godot 是什么:三个反直觉的设计

很多教程上来就「下载、新建项目」,跳过了最重要的心智转变。Godot 和 Unity/Unreal 有三处根本不同:

  • 没有「GameObject + Component」,只有「节点(Node)+ 场景(Scene)」。一个角色是一个场景,一把武器是一个场景,连 UI 按钮都是一个场景。场景可以互相嵌套,像乐高一样。理解了这一条,Godot 就懂了一半。
  • 引擎是「模块化的服务器集合」。渲染是 RenderingServer,物理是 PhysicsServer,音频是 AudioServer……节点只是服务器 API 的「友好封装」。这个设计让 Godot 后来能做出别的引擎做不到的事:把整个引擎作为库嵌入你的程序(4.6 的 LibGodot)。
  • 零许可费、零黑盒。MIT 许可证意味着:你的游戏赚一个亿,Godot 一分不抽;引擎源码全部可读,遇到 bug 可以自己改自己编。

三、版本全景表(截至 2026 年 9 月)

版本发布时间支持状态关键词
4.42025-03已停止更新Jolt 物理(实验)、Ubershaders、内嵌游戏窗口
4.52025-09仅安全补丁Stencil 缓冲、WASM SIMD、GDScript 变参与抽象类、visionOS 导出、着色器烘焙
4.62026-01维护中(4.6.3)LibGodot 引擎即库、Modern 新主题、Jolt 转正默认、新 IK 框架、D3D12 成 Windows 默认
4.72026-06当前推荐稳定版HDR 输出、AreaLight3D、DrawableTexture2D、Asset Store、GABE 安卓全流程
4.8dev6(2026-09-14)开发中屏幕空间接触阴影、对象属性访问提速 1.6 倍、多图层 XR 相机
选型建议一句话:新项目直接上 4.7.x,别犹豫;已有项目在 4.6 及以上,按迁移指南升级即可;4.4 及更早的,先看官方迁移文档再动手。

四、十级台阶:本系列的行军路线

  • 第一级 · 起手式:装引擎、认界面、跑通第一个场景。重点建立「节点树」直觉。
  • 第二级 · 节点与场景:深入 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」。

*本篇配图:十级台阶全景图。*

Godot 4.7 从入门到精通:十级台阶全景图

暂无表态

想参与讨论或点赞?登录后使用完整功能

讨论回复(10)

Q
本系列基于 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 编译发布)。
新手一律先拿 Standard 版。Godot 没有「安装程序」——下载的是一个压缩包,解压出单个 exe,双击就进编辑器。它甚至可以放进 U 盘随身携带。这种「绿色软件」气质,正是它作为开源项目的底色。

另有一条新路径值得知道:4.7 里 GABE(Godot Android Build Environment)已到稳定版,配合安卓编辑器,你甚至可以全程在安卓平板上开发并导出游戏——这在所有游戏引擎里是头一份。

二、项目管理器与编辑器:四个核心区域

新建项目(选兼容性渲染器即可,后文第七级细讲),进入编辑器。界面分成四个区域,对应四种心智:

  • 左上 · 场景面板(Scene):你的「世界」由一棵节点树构成。这里是树的目录。
  • 中上 · 视口(Viewport):所见即所得的编辑空间,2D/3D 切换在左上角标签。
  • 左下 · 文件系统(FileSystem):项目目录的镜像,所有资源(res:// 虚拟路径下)都在这里。
  • 下方 · 检查器(Inspector)+ 底部停靠区:Inspector 显示当前选中节点的属性;底部依次是动画、调试器、音频、输出等面板。
4.6 把社区广受欢迎的「Modern」主题设为了默认,界面更中性、灰度配色更护眼;如果你偏好旧观感,编辑器设置里可切回「Classic」。

一个 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 圈流行一句话:「组合优于继承」。

*本篇配图:编辑器四象限与场景树生长。*

第一级 · 起手式:编辑器四象限与场景树

暂无表态
Q
上一篇跑通了一个方块。这一篇回答更根本的问题: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,改名、移动、跨场景继承都不会再弄丢引用——旧版本里「改个名全场景报错」的著名惨案从此绝迹。官方提示:老项目需用「项目 → 工具 → 升级项目文件」重存一遍场景以获得此能力。
代码侧建树与拆树只有一对最常用的 API:

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 精要——把这门语言从「能跑」写到「优雅」,含 4.5 新增的变参函数与抽象类。

*本篇配图:一棵场景树,信号沿树流动。*

第二级 · 节点与场景:信号沿树流动

暂无表态
Q
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 实战——用 CharacterBody2D、TileMapLayer 与相机,把「能跑能跳的方块」升级成「有手感的平台跳跃游戏」。

*本篇配图:代码与信号流。*

第三级 · GDScript 精要:代码与信号流

暂无表态
Q
本篇把前三级串成一条完整的 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 四项必设(左/右/上/下边界),否则关卡边缘会露出「世界之外的虚空」——平台游戏的经典穿帮。
再进阶一步是给相机加「朝向前瞻」:角色朝右跑时视野先偏右 40 像素,用 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 铺的关卡,含自动拼接地形与单向平台;
  • 一个带平滑、边界限制、前瞻偏移的相机;
  • 碰撞层语义化命名、敌人场景雏形。
下一篇,第五级台阶:动画与状态机——AnimationPlayer 的轨道、AnimationTree 的状态机与混合空间,让角色从「能播放动画」进化到「动画与逻辑互不打架」。

*本篇配图:小方块跳跃平台与碰撞层。*

第四级 · 2D 实战:平台跳跃

暂无表态
Q
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 节点——「手吸附到武器把手」从此是属性配置而非代码。
实操路径:选中 Skeleton3D → 添加 BoneEffect/IKModifier → Inspector 里指目标节点。用动画库解决 80% 的动作,用 IK 解决「贴世界」的 20%——脚踩楼梯、手扶墙壁这些贴合感全靠它。

四、程序化动画: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 原地暂停直到指定信号发出——对话框与过场演出里「动画等台词」从此一行写完。
选型口诀:重复播放且要多轨道混合 → AnimationPlayer;状态切换频繁 → AnimationTree 状态机;一次性属性过渡 → Tween;每帧都变的程序化效果 → _process 里直接改属性。

五、性能与工作流小贴士

  • 动画越长、轨道越多越吃 CPU(属性插值在主线程),长演出优先考虑 shader/粒子实现;
  • AnimationPlayer.play() 同一动画重复调用不会重置进度(可用 play("name", 0.2, 1.0, true) 显式控制);
  • 大量同款动画的资源复用走 Resource(.tres),动画资源可以跨场景共享;
  • 2D 精灵图动画也可以走 Sprite2D + AnimationPlayer 的 texture 轨道,但帧动画优先 AnimatedSprite2D,少一层轨道开销。
下一篇,第六级台阶:3D 入门——从 2D 的像素世界跨进「米」的世界:坐标系、模型导入、光照与相机,你会发现 3D 没有传说中那么陡。

*本篇配图:状态机圆环流转。*

第五级 · 动画与状态机

暂无表态
Q
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 编辑器 gizmo 之外,4.6 给了第四个旋转手柄(绕视线旋转);4.7 的 3D 编辑器更是武装到牙齿——顶点吸附(按住 B)让模型摆放严丝合缝、Path3D 可吸附到碰撞体、双击 F 跟随运动物体、Trackball 式旋转(按 U)、标尺工具支持按轴测量并显示各分量。从 Blender/CAD 转过来的手会舒服很多。

二、3D 节点家族:把 2D 的心智映射过来

对照表比解释省力:

2D3D说明
CharacterBody2DCharacterBody3D手动控速 + move_and_slide(),玩家/NPC 首选
RigidBody2DRigidBody3D物理引擎接管,扔、砸、滚
StaticBody2DStaticBody3D静态碰撞,墙、地
Area2DArea3D触发器、感知区域
Sprite2DMeshInstance3D + Mesh外观载体换成网格
Camera2DCamera3D3D 里没有「自动跟随」,必须自己写或挂脚本
4.6 起默认物理引擎是 Jolt(4.4 引入时是实验选项,4.6 转正)——这个物理引擎来自《死亡搁浅 2》等项目验证,速度与稳定性皆优。新建 3D 项目无需任何操作;老项目想切换在项目设置 → 物理 → 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 子节点到玩家上,初学者最易忘的第三件套就是它。
GI(全局光照)方案速览,4.x 的菜单是四选一组合:
  • 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 入门:坐标系与光照

暂无表态
Q
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 导出与低端机唯一选项。
选型口诀:PC 独立游戏 Forward+,手游与 XR 用 Mobile,要上浏览器用 Compatibility。2D 项目差异很小,Compatibility 也完全够。

顺带一记 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 纹理上绘制,血迹、涂鸦、程序化贴图、小地图都变得一行调用的事。
再看 4.5/4.6 铺的路:4.5 引入 Stencil 缓冲(shader 里可用模板缓冲做描边、X 光、卡通渲染,官方演示里连火焰特效都能用 StandardMaterial3D 调出来)、着色器导出时预编译(shader baker)(配合 4.4 的 Ubershaders,把「进新场景卡一下」的着色器编译顿挫基本消灭);4.6 则有 SSR 大翻新(支持全分辨率/半分辨率两档)、AgX 色调映射可调参数(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 槽——立刻生效。
4.7 的编辑器甜点:文本着色器获得内联实时预览——写 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 复杂度——第七级的结论会在第九级用到。
下一篇,第八级台阶:UI 与游戏架构——Control 体系、4.7 的 offset_transform、信号总线与自动加载,把项目结构写成「一年后还敢回来改」的样子。

*本篇配图:HDR 光照管线。*

第七级 · 渲染与着色器:HDR 光照管线

暂无表态
Q
功能都实现了,为什么改一行崩三处?本篇讲两件事: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 只在暂停时跑。
配合暂停菜单套路:暂停层 CanvasLayer + PROCESS_MODE_ALWAYS + get_tree().paused,三行框架。

六、本篇心法

  • 布局交给容器,装饰交给 offset_transform,皮肤交给 Theme;
  • 全局状态用 Autoload,但保持五个以内;
  • 事件走信号总线,依赖星形化;
  • 目录结构即架构,数据用 Resource,切换走单点。
下一篇,第九级台阶:性能与导出——Profiler 与对象快照查泄漏、批处理与 MultiMesh 救帧率,以及从 Windows 到 Web/Android/主机的完整发布地图。

*本篇配图:UI 锚点与信号总线。*

第八级 · UI 与架构:信号总线星形拓扑

暂无表态
Q
写得出还要跑得快、发得出。本篇前半讲性能分析的正确姿势,后半是完整发布地图——包括那个被误解最多的问题:「Godot 能上主机吗?」

一、性能分析:先测量,再动刀

Godot 内置三件测量工具:

  • Profiler(调试器面板):按函数看耗时,勾「Frame Time」与「CPU 时间」,先找最贵的函数;
  • Monitors(监视器):FPS、内存、draw call、对象数、视频显存——曲线级实时观测;
  • Video/RenderingServer 信息:查 draw call 数与纹理显存。
4.6 的两件新武器:
  • ObjectDB 快照与对比:运行时任意时刻抓「全部存活对象」快照,两份对比即知谁被创建、谁没被销毁——内存泄漏从「猜」变成「看」;
  • 专业追踪器接入:Tracy、Perfetto、Instruments 一键对接(Android 上 4.7 起默认 Perfetto),GDScript/C#/GDExtension 全链路火焰图。
优化顺序铁律:先算法、再节点、再渲染。性能问题的 80% 是「每帧做重活」:_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 新增的最近邻缩放:低分辨率渲染再锐利放大,复古风游戏白赚一半帧率。
物理侧:4.6 起 Jolt 是默认物理,速度稳定性双优;需要更准可调 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 游戏已验证这条路。
发布流程的工程化收尾:版本号写进项目设置、用 Patch PCK(4.6 起支持增量编码,补丁只含变化部分)做热更包、CI 里用命令行 godot --headless --export-release 自动出包。

四、上线前检查清单

  • 帧率目标下跑通完整一关(不只主菜单);
  • 手柄全流程可玩(4.7 的 Ignore Joypad on Unfocused Application 别忘了);
  • 存档兼容性(版本号存进存档,防升级炸档);
  • 多语言(CSV ?context/?plural 列,4.6 起连 C# 的 Tr() 都能自动提取进 POT);
  • 导出前跑一遍着色器预编译(4.5 的 shader baker),消灭玩家端首次编译顿挫。
下一篇,第十级台阶:精通之路——GDExtension 与 C# 的选型、编辑器插件开发、读源码的门径,以及 4.8 与开源引擎的未来。

*本篇配图:性能管线与多平台发布。*

第九级 · 性能与导出:从帧率到发布地图

暂无表态
Q
最后一级。到这里,你已经能独立做游戏了。本篇回答「然后呢」:三种脚本怎么选、怎么给引擎写插件、怎么读源码,以及 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(严格空值语言在编译期抓错)。
选型口诀:先 GDScript,热了换 C#,不够下 GDExtension——三者可共存于一个项目,按模块渐进替换,不是单选题。

二、编辑器插件:给引擎「造轮子」

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/——编辑器与各平台移植。
读法建议:从一个 bug 或一个好奇点切入(比如「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。
官方没有公布 5.0 计划表。社区共识(截至发稿的公开信息)是 4.x 仍会按半年节奏推进——4.0 发布三年,Godot 用 4.4→4.7 四个版本完成了「商业引擎完成度」的证明,下一个三年的看点是 XR、移动端全流程与 LibGodot 的生态开花。

五、毕业礼:十级台阶的合拢

  • 一二级给了世界观(节点、场景、信号);
  • 三级给了语言(GDScript 全谱);
  • 四五级给了 2D 的手(平台跳跃、动画状态机);
  • 六七级给了 3D 的眼(坐标、光照、渲染、HDR);
  • 八级给了纪律(架构防腐化);
  • 九级给了交付(性能与发布);
  • 这一级给了天花板(引擎级扩展与源码自由)。
剩下的只有一件事:做一个属于你的游戏,把它发布出去。Godot 官方 showcase 里那些游戏的第一行代码,也都是某个普通人某个晚上敲下的。

本系列正文到此。资源索引:官方文档 docs.godotengine.org(有中文)、官方 demo 仓库 godotengine/godot-demo-projects、官方 showcase godotengine.org/showcase。4.7 迁移指南与各版发布公告链接散布在各篇。

*本篇配图:十级台阶与 4.8 前瞻。*

第十级 · 精通之路:十级台阶与未来

暂无表态
合作

智谱 GLM-5 已上线

在智谱开放平台 BigModel.cn 打造 AI 应用。新一代旗舰模型 GLM-5 在推理、代码、智能体综合能力达到开源模型 SOTA。

领取 2000万 Tokens