第一个 TypeScript 脚本
创建挂载并运行第一个 TS 节点脚本,理解默认导出继承 Godot 基类与显式导入的规则
上一篇完成了 Gode 插件安装,语言列表里已经能看到 TypeScript。本篇带你走完”新建脚本、编写代码、挂载节点、运行场景”的完整闭环,并讲清楚两条最重要的语言规则:默认导出继承 Godot 基类、Godot 符号必须显式导入。学完本篇,你就能像使用 GDScript 一样自然地用 TypeScript 驱动节点。
学习目标
- 创建一个 TypeScript 脚本,保存为
res://scripts/hello.ts并挂载到节点上运行。 - 逐行理解官方 Hello 示例,掌握默认导出与基类继承的固定写法。
- 记住”Godot 符号不注入全局作用域,必须显式导入”的设计与好处。
- 会写
_ready()、_physics_process(delta)等标准生命周期方法。 - 分清
GD.print()与console.log()的输出去向差异。 - 让 TS 脚本的实例方法被 GDScript 直接调用,并了解静态方法的脚本资源调用方式。
- 用 ESM 语法组织本地模块,并理解”项目脚本只允许 TypeScript”的约定。
- 用代码加载并实例化场景。
创建并运行第一个脚本
操作流程与创建 GDScript 完全一致:
- 在场景中选中一个节点,右键选择”附加脚本”(或通过新建脚本入口)。
- 语言选择
TypeScript。 - 路径保存为
res://scripts/hello.ts(scripts 目录不存在时一并创建)。 - 挂载到节点后,按 F5 或点击运行按钮运行场景。
官方 Hello 示例原文如下:
import { GD, Node } from "godot";
export default class Hello extends Node {
_ready(): void {
GD.print("Hello from Gode");
}
}
运行后,Godot 输出面板会打印 Hello from Gode。下面逐行拆解:
import { GD, Node } from "godot";:从godot模块导入两样东西——GD是工具命名空间(提供打印等全局函数),Node是 Godot 的节点基类。export default class Hello extends Node:默认导出一个名为 Hello 的类,并继承 Node。这是 Gode 的硬性要求,见下一节的”两条铁律”。_ready(): void:Godot 标准生命周期方法,节点进入场景树并就绪时被调用一次。显式标注返回类型void是良好习惯。GD.print("Hello from Gode"):把文本输出到 Godot 输出面板,等价于 GDScript 的print()。
两条铁律
第一,脚本必须默认导出(export default)一个继承 Godot 基类的类。Godot 的脚本系统需要在挂载脚本时实例化你的类,非默认导出的类、不继承 Godot 基类的类都无法作为节点脚本工作。基类按需选择:挂在普通节点上用 Node,挂在三维节点上用 Node3D,角色控制器用 CharacterBody3D,以此类推。
第二,Godot 符号不注入全局作用域,需要显式导入。你不会像某些框架那样凭空使用 Node、Vector3、GD——它们都必须先 import 自 godot 模块。这个设计有两个直接好处:一是类型安全,编辑器能基于声明文件给出准确的补全与检查;二是可摇树(tree-shaking),未使用的 API 绑定不会进入最终产物,有利于控制体积。
生命周期方法
Godot 的标准虚方法在 TypeScript 中以同名方法出现。最常用的两个:
import { GD, Node } from "godot";
export default class LifecycleDemo extends Node {
_ready(): void {
GD.print("节点就绪,仅调用一次");
}
_physics_process(delta: number): void {
// 每个物理帧调用一次,delta 为帧间隔时间
}
}
_ready() 在节点进入场景树就绪时调用一次;_physics_process(delta: number) 每个物理帧调用一次,参数 delta 的类型是 number(Godot 的浮点数在 TypeScript 侧对应 number)。其余 Godot 标准虚方法同理,按 Godot 文档中的方法名原样书写即可,注意 Gode 保持 Godot 原生 snake_case 命名。
GD.print 与 console.log 的区别
Gode 环境里有两个”打印”:GD.print() 走 Godot 的输出 API,保证出现在 Godot 编辑器的输出面板;console.log 是 Node 的 console API,属于终端诊断用途,Gode 不保证它们一定会镜像到 Godot 输出面板。习惯前端开发的人容易默认 console.log 无处不在,在 Gode 里请把”给引擎看”的日志交给 GD.print()(报错用 GD.printerr()),把 console.log 留给终端排查。调试篇章还会讲到:建议从终端启动 Godot 查看 Node/V8 warning。
公开实例方法自动对 Godot 可见
TypeScript 类上的公开实例方法会自动对 Godot 脚本系统可见,GDScript 可以像调用普通节点脚本方法一样直接调用。官方 Health 示例:
import { Node } from "godot";
export default class Health extends Node {
value = 100;
damage(amount: number): void {
this.value = Math.max(0, this.value - amount);
}
}
GDScript 侧一行即可调用:
$Health.damage(25)
这个例子说明:跨语言调用实例方法时,TS 节点在 Godot 眼中就是普通节点脚本,$Health 取到节点后直接点出方法调用即可。
静态方法:通过脚本资源调用
从 2.4.0 起(这是一个破坏性变更),静态方法不再出现在实例上,而是暴露在脚本资源上,通过脚本资源 API 调用。官方示例:
var script = preload("res://scripts/damage_table.ts")
if script.has_static_method("baseDamage"):
var amount = script.call_static("baseDamage", 3)
流程是:preload 加载 .ts 脚本得到脚本资源,先用 has_static_method 判断静态方法是否存在,再用 call_static 调用并传参。配套 API 还有 get_static_method_argument_count,用于查询静态方法的参数个数。记住这条规则的方向:静态成员在”脚本”上,实例成员在”节点”上。
本地模块的组织
项目内的代码拆分使用标准 ESM 语法,导入本地模块时不写文件后缀:
import { clampHealth } from "./combat/math";
需要特别记住的约定是:项目脚本只允许 TypeScript;.cjs 仅作为 CommonJS 运行时的 sidecar(附属)格式用于互操作场景。换句话说,不要试图在项目里手写 .js 业务脚本,一律写 .ts,由内置编译器负责转译。
场景加载与实例化
最后一个实战片段:在代码中加载场景、实例化并加入场景树。官方 MarkerSpawner 示例逐行讲解:
import { DisplayServer, GD, Node3D, ResourceLoader, Vector3 } from "godot";
export default class MarkerSpawner extends Node3D {
_ready(): void {
GD.print(DisplayServer.get_name());
const scene = ResourceLoader.load("res://scenes/marker.tscn");
const marker = scene.instantiate();
marker.position = new Vector3(0, 1, 0);
this.add_child(marker);
}
}
- 顶部导入了五个符号:
DisplayServer(显示服务器单例)、GD、Node3D(三维节点基类)、ResourceLoader(资源加载单例)、Vector3(三维向量内置类型)——再次印证”所有 Godot 符号都要显式导入”。 GD.print(DisplayServer.get_name())打印当前显示服务器名称,确认运行环境。ResourceLoader.load("res://scenes/marker.tscn")加载场景资源。scene.instantiate()实例化出节点对象。marker.position = new Vector3(0, 1, 0)设置位置。注意这里显式new Vector3构造了 Godot 类型,这是类型桥接的推荐写法,后续篇章会展开。this.add_child(marker)把实例作为子节点加入场景树。
小结
- 新建脚本语言选 TypeScript,保存为
.ts后像普通脚本一样挂载到节点。 - 两条铁律:必须默认导出继承 Godot 基类的类;Godot 符号不注入全局作用域,必须从
godot模块显式导入。 _ready()、_physics_process(delta: number)等生命周期方法按 Godot 原名书写,命名保持 snake_case。GD.print()与GD.printerr()保证进入 Godot 输出面板;console.log是 Node 终端诊断,不保证镜像。- 公开实例方法自动对 Godot 可见,GDScript 可直接调用;静态方法自 2.4.0 起改用脚本资源 API(
has_static_method、call_static)。 - 本地模块用 ESM 导入且不写后缀;项目脚本只允许 TypeScript,
.cjs仅作互操作 sidecar。 - 加载场景的标准链路是
ResourceLoader.load加instantiate,再add_child。