pixijs-ticker
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseapp.tickerapp.render()UPDATE_PRIORITY.LOWdeltaTimedeltaMSapp.tickerUPDATE_PRIORITY.LOWapp.render()deltaTimedeltaMSQuick Start
快速开始
ts
app.ticker.add((ticker) => {
sprite.rotation += 0.01 * ticker.deltaTime;
sprite.x += (200 / 1000) * ticker.deltaMS;
});
app.ticker.add(
(ticker) => {
updatePhysics(ticker.deltaMS);
},
undefined,
UPDATE_PRIORITY.HIGH,
);
app.ticker.maxFPS = 30;
app.ticker.speed = 0.5;
sprite.onRender = () => {
sprite.scale.x = Math.sin(performance.now() / 500);
};Related skills: (Application setup and sharedTicker option), (frame rate optimization), (v7 ticker signature changes).
pixijs-applicationpixijs-performancepixijs-migration-v8ts
app.ticker.add((ticker) => {
sprite.rotation += 0.01 * ticker.deltaTime;
sprite.x += (200 / 1000) * ticker.deltaMS;
});
app.ticker.add(
(ticker) => {
updatePhysics(ticker.deltaMS);
},
undefined,
UPDATE_PRIORITY.HIGH,
);
app.ticker.maxFPS = 30;
app.ticker.speed = 0.5;
sprite.onRender = () => {
sprite.scale.x = Math.sin(performance.now() / 500);
};相关技能: (应用程序设置与sharedTicker选项)、(帧率优化)、(v7版本Ticker签名变更)。
pixijs-applicationpixijs-performancepixijs-migration-v8Core Patterns
核心模式
Time units
时间单位
The Ticker exposes three timing values, each for different use cases:
| Property | Type | Scaled by speed? | Capped by minFPS? | Use case |
|---|---|---|---|---|
| dimensionless (~1.0 at 60fps) | yes | yes | Frame-rate-independent animation multipliers |
| milliseconds | yes | yes | Time-based calculations (pixels/sec) |
| milliseconds | no | no | Raw measurement, profiling |
ts
import { Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
app.ticker.add((ticker) => {
// deltaTime: dimensionless scalar, ~1.0 at 60fps
sprite.rotation += 0.1 * ticker.deltaTime;
// deltaMS: real milliseconds (speed-scaled, capped)
sprite.x += (200 / 1000) * ticker.deltaMS; // 200 pixels per second
// elapsedMS: raw milliseconds (no scaling, no cap)
console.log(`Raw frame time: ${ticker.elapsedMS}ms`);
});Tension note: is not milliseconds. It is where targetFPMS is 0.06 (i.e. 1/16.67). At exactly 60fps, deltaTime is 1.0. At 30fps, deltaTime is 2.0. This catches people who treat it as a time value.
deltaTimedeltaMS * Ticker.targetFPMSTicker提供三种时间值,分别适用于不同场景:
| 属性名 | 类型 | 是否受speed缩放? | 是否受minFPS限制? | 使用场景 |
|---|---|---|---|---|
| 无量纲值(60fps下约为1.0) | 是 | 是 | 与帧率无关的动画乘数计算 |
| 毫秒数 | 是 | 是 | 基于时间的计算(如像素/秒) |
| 毫秒数 | 否 | 否 | 原始时间测量、性能分析 |
ts
import { Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
app.ticker.add((ticker) => {
// deltaTime:无量纲标量,60fps下约为1.0
sprite.rotation += 0.1 * ticker.deltaTime;
// deltaMS:实际毫秒数(受speed缩放、帧率限制影响)
sprite.x += (200 / 1000) * ticker.deltaMS; // 每秒移动200像素
// elapsedMS:原始毫秒数(不受缩放、限制影响)
console.log(`原始帧时间:${ticker.elapsedMS}ms`);
});注意事项: 不是毫秒数,它等于 ,其中targetFPMS为0.06(即1/16.67)。在恰好60fps时,deltaTime为1.0;在30fps时,deltaTime为2.0。很多人会误将其当作时间值使用,这点需要注意。
deltaTimedeltaMS * Ticker.targetFPMSPriority ordering and context binding
优先级排序与上下文绑定
ts
import { Application, UPDATE_PRIORITY } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
// INTERACTION (50) > HIGH (25) > NORMAL (0) > LOW (-25) > UTILITY (-50)
// app.render() is registered at LOW by the TickerPlugin
app.ticker.add(
(ticker) => {
// Physics runs before normal-priority callbacks
updatePhysics(ticker.deltaMS);
},
undefined,
UPDATE_PRIORITY.HIGH,
);
app.ticker.add((ticker) => {
// Default priority (NORMAL = 0), runs after HIGH but before render
updateAnimations(ticker.deltaTime);
});
// Pass `this` as the second argument to preserve context on class methods
class GameSystem {
public speed = 5;
public position = 0;
public update(ticker: Ticker): void {
this.position += this.speed * ticker.deltaTime;
}
}
const system = new GameSystem();
app.ticker.add(system.update, system);
app.ticker.remove(system.update, system); // must match both fn and contextts
import { Application, UPDATE_PRIORITY } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
// 优先级顺序:INTERACTION (50) > HIGH (25) > NORMAL (0) > LOW (-25) > UTILITY (-50)
// app.render() 由TickerPlugin注册为LOW优先级
app.ticker.add(
(ticker) => {
// 物理更新在普通优先级回调之前执行
updatePhysics(ticker.deltaMS);
},
undefined,
UPDATE_PRIORITY.HIGH,
);
app.ticker.add((ticker) => {
// 默认优先级(NORMAL = 0),在HIGH之后、渲染之前执行
updateAnimations(ticker.deltaTime);
});
// 将`this`作为第二个参数传入,以保留类方法的上下文
class GameSystem {
public speed = 5;
public position = 0;
public update(ticker: Ticker): void {
this.position += this.speed * ticker.deltaTime;
}
}
const system = new GameSystem();
app.ticker.add(system.update, system);
app.ticker.remove(system.update, system); // 必须同时匹配函数和上下文Frame rate capping
帧率限制
ts
import { Ticker } from "pixi.js";
const ticker = new Ticker();
ticker.maxFPS = 30; // Cap at 30fps (skips frames to maintain interval)
ticker.minFPS = 10; // Cap deltaTime so it never exceeds 10fps worth
// If maxFPS < minFPS, minFPS is lowered to match
// If minFPS > maxFPS, maxFPS is raised to matchmaxFPSminFPSts
import { Ticker } from "pixi.js";
const ticker = new Ticker();
ticker.maxFPS = 30; // 限制帧率为30fps(通过跳帧维持间隔)
ticker.minFPS = 10; // 限制deltaTime的最大值,使其不会超过10fps对应的数值
// 如果maxFPS < minFPS,minFPS会被降低至与maxFPS一致
// 如果minFPS > maxFPS,maxFPS会被提高至与minFPS一致maxFPSminFPSPer-object onRender hook
逐对象onRender钩子函数
ts
import { Sprite, Assets, Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
const texture = await Assets.load("bunny.png");
const sprite = new Sprite(texture);
app.stage.addChild(sprite);
sprite.onRender = (renderer) => {
sprite.rotation += 0.01;
};onRenderts
import { Sprite, Assets, Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
const texture = await Assets.load("bunny.png");
const sprite = new Sprite(texture);
app.stage.addChild(sprite);
sprite.onRender = (renderer) => {
sprite.rotation += 0.01;
};onRenderTicker.shared, Ticker.system, and new Ticker
Ticker.shared、Ticker.system与自定义Ticker实例
ts
import { Ticker, UPDATE_PRIORITY } from "pixi.js";
// Ticker.shared: singleton, autoStart=true, protected from destroy()
const shared = Ticker.shared;
// Ticker.system: separate instance used by engine background tasks,
// independent of the main scene ticker. It's a plain Ticker instance
// (autoStart=true, _protected=true) with no intrinsic priority; listeners
// are typically added at UTILITY priority by convention.
const system = Ticker.system;
// new Ticker(): custom instance, autoStart=false, you manage the lifecycle
const custom = new Ticker();
custom.autoStart = true; // start when first listener is added
custom.add((ticker) => {
console.log(ticker.deltaMS);
});
// One-shot callback that auto-removes after firing
custom.addOnce(() => console.log("fires once"), null, UPDATE_PRIORITY.NORMAL);
// When done:
custom.stop();
custom.destroy();ApplicationsharedTicker: trueapp.init()Ticker.sharedTicker.sharedTicker.system_protecteddestroy()ticker.FPSticker.countts
import { Ticker, UPDATE_PRIORITY } from "pixi.js";
// Ticker.shared:单例实例,autoStart=true,调用destroy()不会被销毁
const shared = Ticker.shared;
// Ticker.system:独立实例,用于引擎后台任务,
// 与主场景Ticker无关。它是一个普通的Ticker实例
// (autoStart=true,_protected=true),本身无固有优先级;按照惯例,监听器通常以UTILITY优先级添加。
const system = Ticker.system;
// new Ticker():自定义实例,autoStart=false,由你管理生命周期
const custom = new Ticker();
custom.autoStart = true; // 当添加第一个监听器时自动启动
custom.add((ticker) => {
console.log(ticker.deltaMS);
});
// 一次性回调,触发后自动移除
custom.addOnce(() => console.log("仅触发一次"), null, UPDATE_PRIORITY.NORMAL);
// 使用完毕后:
custom.stop();
custom.destroy();Applicationapp.init()sharedTicker: trueTicker.sharedTicker.sharedTicker.system_protecteddestroy()ticker.FPSticker.countApp lifecycle and manual rendering
应用生命周期与手动渲染
ts
import { Application } from "pixi.js";
const app = new Application();
await app.init({ autoStart: false });
// Pause and resume the built-in render loop at any time.
app.start();
app.stop();
// Or drive the loop yourself (headless, visibility-gated, fixed timestep, etc.)
function animate() {
app.ticker.update(); // fires registered callbacks
app.render(); // renders the stage
requestAnimationFrame(animate);
}
animate();app.start()app.stop()TickerPluginticker.start()ticker.stop()autoStart: falsets
import { Application } from "pixi.js";
const app = new Application();
await app.init({ autoStart: false });
// 随时暂停和恢复内置渲染循环
app.start();
app.stop();
// 或者自行驱动循环(适用于无头模式、可见性控制、固定时间步长等场景)
function animate() {
app.ticker.update(); // 触发已注册的回调函数
app.render(); // 渲染舞台
requestAnimationFrame(animate);
}
animate();app.start()app.stop()TickerPluginticker.start()ticker.stop()autoStart: falseSpeed scaling
速度缩放
ts
import { Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
app.ticker.speed = 0.5; // Half speed (slow motion)
app.ticker.speed = 2.0; // Double speed
// speed affects deltaTime and deltaMS, but NOT elapsedMSts
import { Application } from "pixi.js";
const app = new Application();
await app.init({ width: 800, height: 600 });
app.ticker.speed = 0.5; // 半速(慢动作)
app.ticker.speed = 2.0; // 双倍速
// speed会影响deltaTime和deltaMS,但不会影响elapsedMSCommon Mistakes
常见错误
[CRITICAL] Ticker callback expects delta as first argument
[严重] Ticker回调函数错误地期望delta作为第一个参数
Wrong:
ts
app.ticker.add((dt) => {
bunny.rotation += dt;
});Correct:
ts
app.ticker.add((ticker) => {
bunny.rotation += ticker.deltaTime;
});v8 passes the Ticker instance as the callback argument, not a delta number. The v7 pattern compiles but is the entire Ticker object, so arithmetic on it produces .
(dt) => ...dtNaN错误写法:
ts
app.ticker.add((dt) => {
bunny.rotation += dt;
});正确写法:
ts
app.ticker.add((ticker) => {
bunny.rotation += ticker.deltaTime;
});v8版本中,回调函数的参数是Ticker实例,而非单个delta数值。v7版本中使用的写法虽然能编译通过,但实际是整个Ticker对象,对其进行算术运算会得到。
(dt) => ...dtNaN[HIGH] Using updateTransform for per-frame logic
[高风险] 使用updateTransform处理逐帧逻辑
Wrong:
ts
class MySprite extends Sprite {
updateTransform() {
super.updateTransform();
this.rotation += 0.01;
}
}Correct:
ts
class MySprite extends Sprite {
constructor() {
super();
this.onRender = this._onRender.bind(this);
}
private _onRender() {
this.rotation += 0.01;
}
}updateTransformonRender错误写法:
ts
class MySprite extends Sprite {
updateTransform() {
super.updateTransform();
this.rotation += 0.01;
}
}正确写法:
ts
class MySprite extends Sprite {
constructor() {
super();
this.onRender = this._onRender.bind(this);
}
private _onRender() {
this.rotation += 0.01;
}
}v8版本中已移除方法。对于逐对象的逐帧逻辑,请使用回调函数。
updateTransformonRender[MEDIUM] Treating deltaTime as milliseconds
[中风险] 将deltaTime当作毫秒数使用
Wrong:
ts
app.ticker.add((ticker) => {
// Tries to move 100px/sec but deltaTime is ~1.0, not ~16.67
sprite.x += (100 * ticker.deltaTime) / 1000;
});Correct:
ts
app.ticker.add((ticker) => {
// Using deltaMS for time-based movement
sprite.x += (100 / 1000) * ticker.deltaMS;
// Or using deltaTime as a frame-rate multiplier
sprite.x += 1.5 * ticker.deltaTime;
});deltaTimedeltaMSdeltaTime错误写法:
ts
app.ticker.add((ticker) => {
// 试图以100px/sec的速度移动,但deltaTime约为1.0,而非16.67
sprite.x += (100 * ticker.deltaTime) / 1000;
});正确写法:
ts
app.ticker.add((ticker) => {
// 使用deltaMS进行基于时间的移动计算
sprite.x += (100 / 1000) * ticker.deltaMS;
// 或者将deltaTime作为帧率乘数使用
sprite.x += 1.5 * ticker.deltaTime;
});deltaTimedeltaMSdeltaTime