暂停与时间缩放
tree.paused 暂停游戏;tree.timeScale 让游戏时间变快、变慢或停住,用来做打击停顿和慢动作。两者互相独立。
暂停
ts
import { Node2D, Scene } from 'sapling2d'
class Spinner extends Node2D {
override process(dt: number) {
this.rotation += dt
}
}
export class World extends Scene {
spinner!: Spinner
menuSpinner!: Spinner
override ready() {
this.spinner = this.add(new Spinner()) // 默认 inherit → pausable
this.menuSpinner = this.add(new Spinner({ processMode: 'always' })) // 暂停菜单:暂停时照常运行
}
togglePause() {
this.tree.paused = !this.tree.paused // 暂停 pausable 节点、它们的 Tween / Timer、指针事件和物理
}
}
// 切到后台:tree.focusChanged(false),默认挂起整个主循环- 每个节点有
processMode:inherit(默认,跟随父节点;一路继承到根时就是pausable)、pausable、always。 tree.paused = true时,pausable节点的process/physicsProcess、绑定在它们上的 Tween / Timer、指针事件都停止,物理世界也停止。- 暂停菜单里的节点(包括按钮)设
processMode: 'always',否则暂停时点不到。 createTimer默认在暂停时继续计时;传processAlways: false改成跟着暂停。- 暂停不会停止声音。
- 切到后台时,默认(启动参数
pauseOnBackground: true)挂起整个主循环;tree.focusChanged信号通知前后台切换。
时间缩放
ts
import { Node2D, Scene, v } from 'sapling2d'
class Blade extends Node2D {
override process(dt: number) {
this.rotation += 6 * dt // dt 是乘过 timeScale 的游戏时间:停顿时为 0
}
}
export class Duel extends Scene {
blade!: Blade
override ready() {
this.blade = this.add(new Blade({ position: v(375, 667) }))
}
/** 打击停顿:游戏时间停住一小会儿,再按真实时间恢复(停顿时普通计时器也停了,所以用 ignoreTimeScale)。 */
async hitStop(seconds: number) {
this.tree.timeScale = 0
await this.tree.createTimer(seconds, { ignoreTimeScale: true }).timeout
this.tree.timeScale = 1
}
/** 慢动作:击杀 Boss 时放慢到 0.25 倍,半秒(真实时间)后恢复。 */
async slowMotion() {
this.tree.timeScale = 0.25
await this.tree.createTimer(0.5, { ignoreTimeScale: true }).timeout
this.tree.timeScale = 1
}
}tree.timeScale默认 1,必须 ≥ 0。所有游戏时间都乘上它:process的 dt、物理步数、Tween、Timer、createTimer、帧动画、相机平滑和tree.time。- 为 0 时游戏时间完全停止,输入和渲染照常;停顿中按下的键,在恢复后的第一个物理步里仍然算 just pressed。
- 停顿时普通计时器也停了,所以恢复用
createTimer(秒, { ignoreTimeScale: true }),按真实时间计时。 - 界面(CanvasLayer)也一起变慢;停顿很短时看不出来。
倍速下结果一致
大于 1 时,物理步长仍是 1/60 秒,只是每帧的步数变多:3 倍速时 60Hz 屏幕上每帧 3 步,步序和 1 倍速跑 3 帧完全一样。代价是逻辑耗时也乘上倍速。
按帧的计时和补间一帧只更新一次,倍速下一帧会吞掉几步。所以:
- 要求倍速下结果一致的玩法逻辑放在
physicsProcess里。 - 驱动玩法的计时和动画按物理步推进:
createTimer(秒, { processInPhysics: true })、new Timer({ processInPhysics: true })、createTween({ processInPhysics: true })、new AnimatedSprite2D({ processInPhysics: true })。它们每步推进 1/60 秒游戏时间,在physicsProcess和物理世界之后执行。 - 纯视觉的效果(受击闪白、UI 弹一下)照旧按帧。
ignoreTimeScale不能和processInPhysics同时用。