GDScript 速查表
最后更新
基础与输出
脚本继承某个节点类型,Godot 会替你调用它的函数。
| 操作 | 语法 |
|---|---|
| 把脚本挂到某种节点类型上 | extends Node |
| 节点启动时运行的代码 | func _ready() -> void:
print("Hello, World!") |
| 输出多个值,不加分隔符 | print("HP: ", hp) |
| 输出多个值,用空格分隔 | prints("a", "b", 3) |
| 注释 | # This is a comment |
| 文档注释 | ## Shown in the editor's help |
| 多行字符串 | var text := """Line one
Line two""" |
| 报告错误 | push_error("Health is negative") |
| 报告警告 | push_warning("Old save file") |
变量、常量与类型
类型是可选的。加上类型,可以获得编辑器检查、自动补全和更快的代码。
| 操作 | 语法 |
|---|---|
| 变量(动态类型) | var score = 0 |
| 带静态类型的变量 | var speed: float = 200.0 |
| 推断静态类型 | var lives := 3 |
| 常量 | const MAX_HP = 100 |
| 枚举 | enum State { IDLE, RUN, JUMP } |
| 使用枚举值 | var state: State = State.IDLE |
| 向量和颜色值 | var pos := Vector2(10, 20)
var tint := Color(1, 0, 0) |
| 空的对象引用 | var target: Node = null |
| 转换为文本、整数或浮点数 | str(42), int("42"), float("3.5") |
| 浮点数转整数(直接去掉小数) | int(3.9) # 3 |
| 检查类型 | value is int, node is Sprite2D |
| 转换为某个类型 | var sprite := node as Sprite2D |
运算符
熟悉的数学运算,逻辑运算则用英文单词。
| 操作 | 语法 |
|---|---|
| 加、减、乘、除 | a + b, a - b, a * b, a / b |
| 整数除法(int / int) | 7 / 2 # 3 |
| 取余 | 7 % 3, fmod(7.5, 2.0) |
| 乘方 | 2 ** 10 # 1024 |
| 复合赋值 | x += 1, x -= 1, x *= 2, x /= 2 |
| 比较 | ==, !=, <, >, <=, >= |
| 逻辑运算 | a and b, a or b, not a |
| 逻辑运算(符号写法) | a && b, a || b, !a |
| 行内 if | var label := "win" if score > 10 else "lose" |
| 是否在集合中 | "sword" in inventory |
| 位运算 | a & b, a | b, a ^ b, ~a, a << 1, a >> 1 |
流程控制
代码块由缩进决定,和 Python 一样。Godot 默认用制表符缩进。
| 操作 | 语法 |
|---|---|
| if、elif、else | if hp <= 0:
die()
elif hp < 20:
print("Low HP")
else:
print("OK") |
| 单行 if | if hp <= 0: die() |
| 遍历一个范围 | for i in range(5):
print(i) # 0 to 4 |
| 指定起点、终点和步长的范围 | for i in range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2 |
| 重复 n 次 | for i in 3:
print(i) # 0, 1, 2 |
| 遍历数组 | for item in items:
print(item) |
| 带类型的循环变量(Godot 4.2+) | for n: String in names:
print(n.to_upper()) |
| while 循环 | while hp > 0:
hp -= 10 |
| 跳出循环或跳过本次 | break, continue |
| 空代码块占位 | pass |
模式匹配(match)
match 会执行第一个模式匹配成功的分支,不会贯穿到下一个分支。
| 操作 | 语法 |
|---|---|
| 匹配值 | match state:
State.IDLE:
print("idle")
State.RUN:
print("run") |
| 一个分支匹配多个值 | match key:
"w", "up":
move_up() |
| 默认分支(通配符) | match n:
0:
print("zero")
_:
print("other") |
| 把值绑定到一个名字 | match cmd:
"quit":
get_tree().quit()
var other:
print("Unknown: ", other) |
| 数组模式 | match pos:
[0, 0]:
print("origin")
[var x, 0]:
print("on the x axis at ", x) |
| 数组后面可以有任意元素 | match args:
["move", ..]:
print("move command") |
| 字典模式 | match item:
{"type": "coin", "value": var v}:
gold += v |
| 用 when 加条件(Godot 4.4+) | match score:
var s when s >= 90:
print("A")
var s when s >= 75:
print("B")
_:
print("C") |
函数与 lambda
函数也是值:可以存起来、传来传去,还能给它绑定参数。
| 操作 | 语法 |
|---|---|
| 带类型的参数和返回值 | func add(a: int, b: int) -> int:
return a + b |
| 无返回值 | func reset() -> void:
score = 0 |
| 默认参数 | func greet(who := "player") -> void:
print("Hi, ", who) |
| 静态函数 | static func double(x: int) -> int:
return x * 2 |
| 单行 lambda | var square := func(x): return x * x |
| 调用 Callable | square.call(4) # 16 |
| 把函数当作值 | var on_done := reset
on_done.call() |
| 绑定参数 | var add_ten := add.bind(10)
print(add_ten.call(5)) # 15 |
| 多行 lambda | var greet_all := func(names: Array) -> void:
for n in names:
print("Hi, ", n) |
| 等待计时器 | await get_tree().create_timer(1.0).timeout |
| 等待协程 | var data = await fetch_data() |
字符串
字符串方法返回新的字符串,从不修改原字符串。
| 操作 | 语法 |
|---|---|
| 用 % 格式化 | "%s has %d HP" % [name, hp] |
| 保留两位小数 | "%.2f" % 3.14159 # "3.14" |
| 用命名占位符格式化 | "{a} vs {b}".format({"a": 1, "b": 2}) |
| 用 + 拼接 | "Score: " + str(score) |
| 长度 | text.length() |
| 转大写或小写 | text.to_upper(), text.to_lower() |
| 拆分 | "a,b,c".split(",") # ["a", "b", "c"] |
| 连接多个部分 | ", ".join(["a", "b", "c"]) |
| 去除首尾空白 | " hi ".strip_edges() # "hi" |
| 替换文本 | text.replace("cat", "dog") |
| 查找位置 | text.find("lo") # -1 if missing |
| 以某内容开头或结尾 | text.begins_with("Hi"), text.ends_with("!") |
| 截取子串 | text.substr(0, 5) |
| 是否包含 | "ell" in "Hello" # true |
数组
数组可以变长也可以变短。带类型的数组只接受指定类型的元素。
| 操作 | 语法 |
|---|---|
| 数组字面量(混合类型) | var items = [1, "two", 3.0] |
| 带类型的数组 | var scores: Array[int] = [10, 20, 30] |
| 按索引读取(负数从末尾开始数) | scores[0], scores[-1] |
| 添加到末尾 | scores.append(40), scores.push_back(40) |
| 在指定索引处插入 | scores.insert(0, 5) |
| 移除并返回最后一个元素 | var last = scores.pop_back() |
| 按值或按索引移除 | scores.erase(20), scores.remove_at(0) |
| 是否包含、查找索引 | scores.has(30), scores.find(30) |
| 长度、是否为空 | scores.size(), scores.is_empty() |
| 排序 | scores.sort() |
| 按自定义规则排序 | enemies.sort_custom(func(a, b): return a.hp < b.hp) |
| 映射(map) | scores.map(func(x): return x * 2) |
| 筛选(filter) | scores.filter(func(x): return x > 15) |
| 归约(reduce) | scores.reduce(func(acc, x): return acc + x, 0) |
| 切片(不含结束位置) | scores.slice(1, 3) |
字典
键值对。键可以是任何类型,最常用的是字符串。
| 操作 | 语法 |
|---|---|
| 字典字面量 | var stats = {"hp": 100, "mp": 30} |
| 带类型的字典(Godot 4.4+) | var prices: Dictionary[String, int] = {"sword": 50} |
| 读取或写入键 | stats["hp"], stats["xp"] = 50 |
| 带默认值读取 | stats.get("luck", 0) |
| 是否有某个键 | stats.has("hp"), "hp" in stats |
| 删除键 | stats.erase("mp") |
| 所有键和所有值 | stats.keys(), stats.values() |
| 条目数量 | stats.size() |
| 合并另一个字典(true 表示覆盖) | stats.merge({"luck": 5}), stats.merge(bonus, true) |
| 遍历键 | for key in stats:
print(key, " = ", stats[key]) |
类与注解
每个脚本都是一个类。注解以 @ 开头。
| 操作 | 语法 |
|---|---|
| 给类一个全局名称 | class_name Player
extends CharacterBody2D |
| 构造函数 | func _init(start_hp := 100) -> void:
hp = start_hp |
| 创建实例 | var p := Player.new() |
| 内部类 | class Item:
var name := ""
var price := 0 |
| 调用父类中的同名方法 | func _ready() -> void:
super()
print("child ready") |
| 调用父类的其他方法 | super.take_damage(10) |
| 静态变量(Godot 4.1+) | static var count := 0 |
| 显示在检查器中 | @export var speed := 300.0 |
| 以滑块范围显示 | @export_range(0, 100) var volume := 50 |
| 就绪时获取子节点 | @onready var sprite: Sprite2D = $Sprite2D |
| setter 和 getter | var hp := 100:
set(value):
hp = clampi(value, 0, 100)
get:
return hp |
| 在编辑器中运行脚本 | @tool |
信号
信号是一等公民:声明之后,就能直接发出、连接和等待它们。
| 操作 | 语法 |
|---|---|
| 声明信号 | signal died |
| 带类型参数的信号 | signal health_changed(old_hp: int, new_hp: int) |
| 发出信号 | died.emit() |
| 带参数发出信号 | health_changed.emit(100, 80) |
| 连接到方法 | player.died.connect(_on_player_died) |
| 连接 lambda | button.pressed.connect(func(): print("Clicked")) |
| 传递额外参数 | button.pressed.connect(_on_pressed.bind("start")) |
| 只触发一次 | timer.timeout.connect(_on_timeout, CONNECT_ONE_SHOT) |
| 断开连接 | player.died.disconnect(_on_player_died) |
| 检查是否已连接 | player.died.is_connected(_on_player_died) |
| 等待信号 | await player.died |
节点与生命周期
Godot 会在你的节点上调用的回调,以及你对场景树发起的调用。
| 操作 | 语法 |
|---|---|
| 对象已创建(加入场景树之前) | func _init() -> void:
print("created") |
| 节点及其子节点已就绪 | func _ready() -> void:
print("ready") |
| 每一帧 | func _process(delta: float) -> void:
position.x += 100.0 * delta |
| 每个物理帧 | func _physics_process(delta: float) -> void:
velocity.y += 980.0 * delta
move_and_slide() |
| UI 没有处理的输入 | func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
jump() |
| 按路径获取节点 | get_node("Sprite2D"), $Sprite2D |
| 带空格的路径、唯一名称 | $"UI/Health Bar", %HealthBar |
| 检查输入动作 | Input.is_action_pressed("move_right") |
| 创建场景的实例 | var enemy := preload("res://enemy.tscn").instantiate()
add_child(enemy) |
| 安全地删除节点 | queue_free() |
| 父节点和子节点 | get_parent(), get_children() |
| 切换场景 | get_tree().change_scene_to_file("res://main.tscn") |
开发 Godot 游戏时最常用的 GDScript 语法,全都在这一页。这份 GDScript 速查表是 Godot 4 的快速参考:变量和静态类型、运算符、流程控制和 match、函数和 lambda、字符串、数组和字典、类、信号,以及 Godot 每帧都会调用的节点回调。
这里全部是 Godot 4 的语法,所以你会看到 @export、@onready、died.emit() 和 await,而不是 Godot 3 的写法。把需要的内容复制到你的脚本里,或者在 GDScript 在线编辑器里直接试运行这些语言片段:把它们放进 _ready(),就能在浏览器中运行,无需安装 Godot。
GDScript 速查表常见问题
这份 GDScript 速查表免费吗?
免费。这份 GDScript 速查表完全免费,无需注册。把它加入书签,需要查信号、match 模式或数组方法的准确写法时随时回来看。
这份速查表适用于 Godot 4 还是 Godot 3?
@export 和 @onready 注解代替 export 和 onready 关键字,用 died.emit() 和 died.connect(callable) 代替 emit_signal("died") 和基于字符串的 connect,用 await 代替 yield,用 super() 代替 .method()。标有 4.1+、4.2+ 或 4.4+ 的行至少需要对应版本的 Godot。GDScript 中 = 和 := 有什么区别?
var x = 5 创建一个动态变量,之后可以存放任何类型。var x := 5 根据值推断类型(这里是 int)并固定下来,之后再赋值字符串就会报错。var x: int = 5 则显式写明类型。静态类型能带来编辑器报错提示、更好的自动补全和更快的代码。GDScript 中的信号是怎么工作的?
signal died 声明信号,用 died.emit() 发出信号,在另一个节点中用 player.died.connect(_on_player_died) 响应它。你也可以连接 lambda 而不是方法,用 .bind() 绑定额外参数,或者用 await player.died 让函数暂停,直到信号触发。GDScript 和 Python 像吗?
for ... in、if/elif/else,以及 and、or、not 这样的英文单词。但 GDScript 是专为 Godot 打造的独立语言,它有可选的静态类型、信号、@export 这样的注解,还能用 $ 直接访问节点。可以在线练习 GDScript 吗?
_ready() 中的代码会运行一次。想系统地学,Coddy 免费的交互式 GDScript 课程会带你一步步从变量和函数学到类和信号。