SceneTree.create_timer
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — SceneTree.create_timer
SceneTree.create_timer
定义
create_timer 就像厨房里的定时器——你设置一个时间(比如"5 分钟后响"),时间一到它就会"叮"一声提醒你。在 Godot 里,这个"叮"就是一个信号(Timeout 信号),你可以连接这个信号来执行你想要的代码。
打个比方:你在煮面条,设了一个 3 分钟的定时器。这 3 分钟里你可以去做别的事(切菜、摆盘子),不用一直盯着锅看。3 分钟一到,定时器响了,你就知道"该捞面条了"。
在游戏开发中,create_timer 比 Timer 节点更轻量、更灵活。当你只是需要"等几秒后做一件事"时,用它就不需要在场景里额外添加 Timer 节点。
函数签名
C#
public SceneTreeTimer CreateTimer(double timeSec, bool processAlways = true, bool processInPhysics = false, bool ignoreTimeScale = false)GDScript
func create_timer(time_sec: float, process_always: bool = true, process_in_physics: bool = false, ignore_time_scale: bool = false) -> SceneTreeTimer参数说明
| 参数 | 类型 | 必需 | 默认值 | 说明 |
|---|---|---|---|---|
timeSec | double | 是 | — | 定时器时长,单位为秒。例如 2.0 表示 2 秒后触发 |
processAlways | bool | 否 | true | 为 true 时,即使场景树暂停(Paused = true),定时器仍然会继续计时 |
processInPhysics | bool | 否 | false | 为 true 时,使用物理帧(_PhysicsProcess)计时而非渲染帧(_Process) |
ignoreTimeScale | bool | 否 | false | 为 true 时,忽略 Engine.TimeScale 的影响,始终按真实时间计时 |
返回值
SceneTreeTimer——返回一个定时器对象。你可以通过连接它的 Timeout 信号来执行延迟操作。
| 属性/信号 | 说明 |
|---|---|
Timeout 信号 | 计时结束时触发,这是最常用的信号 |
TimeLeft 属性 | 剩余时间(秒),可以随时查看还剩多久 |
代码示例
基础用法:延时执行代码
C#
public override void _Ready()
{
// 创建一个 3 秒的定时器
SceneTreeTimer timer = GetTree().CreateTimer(3.0);
// 3 秒后自动执行这段代码
timer.Timeout += () =>
{
GD.Print("3 秒到了!");
};
// 运行结果(3 秒后): 3 秒到了!
// 再创建一个 1.5 秒的定时器
GetTree().CreateTimer(1.5).Timeout += () =>
{
GD.Print("1.5 秒到了!");
};
// 运行结果(1.5 秒后): 1.5 秒到了!
}GDScript
func _ready():
# 创建一个 3 秒的定时器
var timer = get_tree().create_timer(3.0)
# 3 秒后自动执行这段代码
timer.timeout.connect(func():
print("3 秒到了!")
)
# 运行结果(3 秒后): 3 秒到了!
# 再创建一个 1.5 秒的定时器
get_tree().create_timer(1.5).timeout.connect(func():
print("1.5 秒到了!")
)
# 运行结果(1.5 秒后): 1.5 秒到了!实际场景:敌人生成器(每隔几秒生成一个敌人)
C#
using Godot;
public partial class EnemySpawner : Node2D
{
[Export] public PackedScene ExEnemyScene;
[Export] public float ExSpawnInterval = 2.0f;
[Export] public int ExMaxEnemies = 10;
private int _spawnedCount = 0;
public override void _Ready()
{
SpawnEnemy();
}
private void SpawnEnemy()
{
if (_spawnedCount >= ExMaxEnemies) return;
// 在随机位置生成敌人
var enemy = ExEnemyScene.Instantiate<Node2D>();
enemy.Position = new Vector2(
(float)GD.RandRange(-200, 200),
(float)GD.RandRange(-150, 150)
);
AddChild(enemy);
_spawnedCount++;
GD.Print($"生成了第 {_spawnedCount} 个敌人");
// 运行结果: 生成了第 1 个敌人
// 运行结果(2 秒后): 生成了第 2 个敌人
// 运行结果(4 秒后): 生成了第 3 个敌人
// 间隔一段时间后再生成下一个
GetTree().CreateTimer(ExSpawnInterval).Timeout += SpawnEnemy;
}
}GDScript
extends Node2D
@export var ex_enemy_scene: PackedScene
@export var ex_spawn_interval: float = 2.0
@export var ex_max_enemies: int = 10
var _spawned_count: int = 0
func _ready():
spawn_enemy()
func spawn_enemy():
if _spawned_count >= ex_max_enemies:
return
# 在随机位置生成敌人
var enemy = ex_enemy_scene.instantiate()
enemy.position = Vector2(
randf_range(-200, 200),
randf_range(-150, 150)
)
add_child(enemy)
_spawned_count += 1
print("生成了第 %d 个敌人" % _spawned_count)
# 运行结果: 生成了第 1 个敌人
# 运行结果(2 秒后): 生成了第 2 个敌人
# 运行结果(4 秒后): 生成了第 3 个敌人
# 间隔一段时间后再生成下一个
get_tree().create_timer(ex_spawn_interval).timeout.connect(spawn_enemy)进阶用法:连击判定系统和暂停时仍然计时
C#
using Godot;
public partial class ComboSystem : Node
{
[Export] public float ExComboWindow = 1.5f; // 连击时间窗口
private int _comboCount = 0;
private SceneTreeTimer _comboTimer;
public void OnHit()
{
// 每次命中,连击数 +1
_comboCount++;
GD.Print($"连击 x{_comboCount}!");
// 运行结果(连续命中时): 连击 x1!
// 运行结果: 连击 x2!
// 运行结果: 连击 x3!
// 每次命中都重置计时器
// 如果 1.5 秒内没有再次命中,连击中断
_comboTimer = GetTree().CreateTimer(ExComboWindow);
_comboTimer.Timeout += OnComboExpired;
}
private void OnComboExpired()
{
if (_comboCount > 1)
{
GD.Print($"连击结束!最终连击数: x{_comboCount}");
// 运行结果(1.5 秒无操作后): 连击结束!最终连击数: x3
}
_comboCount = 0;
}
// 在暂停菜单中使用 processAlways 参数
public void ShowPauseHint()
{
// 即使游戏暂停了,3 秒后仍然显示提示
var pauseTimer = GetTree().CreateTimer(3.0, processAlways: true);
pauseTimer.Timeout += () =>
{
GD.Print("暂停提示:按 ESC 继续游戏");
};
// 运行结果(暂停 3 秒后): 暂停提示:按 ESC 继续游戏
}
}GDScript
extends Node
@export var ex_combo_window: float = 1.5 # 连击时间窗口
var _combo_count: int = 0
var _combo_timer: SceneTreeTimer
func on_hit():
# 每次命中,连击数 +1
_combo_count += 1
print("连击 x%d!" % _combo_count)
# 运行结果(连续命中时): 连击 x1!
# 运行结果: 连击 x2!
# 运行结果: 连击 x3!
# 每次命中都重置计时器
# 如果 1.5 秒内没有再次命中,连击中断
_combo_timer = get_tree().create_timer(ex_combo_window)
_combo_timer.timeout.connect(_on_combo_expired)
func _on_combo_expired():
if _combo_count > 1:
print("连击结束!最终连击数: x%d" % _combo_count)
# 运行结果(1.5 秒无操作后): 连击结束!最终连击数: x3
_combo_count = 0
# 在暂停菜单中使用 process_always 参数
func show_pause_hint():
# 即使游戏暂停了,3 秒后仍然显示提示
var pause_timer = get_tree().create_timer(3.0, true)
pause_timer.timeout.connect(func():
print("暂停提示:按 ESC 继续游戏")
)
# 运行结果(暂停 3 秒后): 暂停提示:按 ESC 继续游戏注意事项
- 一次性定时器:
CreateTimer创建的定时器默认只触发一次。如果需要重复触发,需要在Timeout回调中重新创建定时器(参见实际场景示例)。 - 定时器会自动释放:计时结束后,
SceneTreeTimer会自动被引擎回收,你不需要手动释放它。 - 取消定时器:如果你想在定时器触发前取消它,可以调用
timer.Timeout?.Disconnect(...)或者不连接信号(未连接信号的定时器触发后什么都不做)。也可以设置timer.TimeLeft = 0让它立即过期。 - 与
Timer节点的区别:Timer节点适合需要反复触发、需要在编辑器中配置的场景;CreateTimer适合代码中临时创建的一次性延时操作,不需要在场景树中添加额外节点。 processAlways参数的用途:当设为true时,定时器在游戏暂停期间仍然计时。这在暂停菜单的动画、提示信息等场景中非常有用。- C# 差异:C# 中方法名用 PascalCase(
CreateTimer),GDScript 中用 snake_case(create_timer)。
