Menu
CoddyTech

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
行内 ifvar 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、elseif hp <= 0: die() elif hp < 20: print("Low HP") else: print("OK")
单行 ifif 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
单行 lambdavar square := func(x): return x * x
调用 Callablesquare.call(4) # 16
把函数当作值var on_done := reset on_done.call()
绑定参数var add_ten := add.bind(10) print(add_ten.call(5)) # 15
多行 lambdavar 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 和 gettervar 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)
连接 lambdabutton.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?
Godot 4。两个版本的差异足以让复制过来的代码报错:Godot 4 用 @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 吗?
可以。打开 GDScript 在线编辑器,就能在浏览器里运行这份速查表中的代码片段:在线编辑器会把你的脚本挂到一个节点上,所以 _ready() 中的代码会运行一次。想系统地学,Coddy 免费的交互式 GDScript 课程会带你一步步从变量和函数学到类和信号。
Coddy 编程语言插图

在 Coddy 学习 GDScript

开始