mcpField
P
pixijs-ticker

pixijs-ticker

github.com/pixijs開発3585.9k 回インストール4 週間前に更新
リポジトリ

pixijs-ticker について

PixiJS 開発者向けに、Ticker で更新とレンダリングループを動かす方法を解説するスキルです。コールバックの優先順位、ライフサイクル制御、時間値の使い分けを扱います。

主な機能

  1. 01Ticker コールバックと時間値
  2. 02コールバックの優先順位
  3. 03フレームレート制限と速度調整
  4. 04Ticker とアプリのライフサイクル制御
  5. 05表示オブジェクトの onRender 処理

活用シーン

  1. 01フレームレートに依存しないオブジェクトアニメーション
  2. 02フレームレートや大きな時間差分の制限
  3. 03アプリのレンダリングループの一時停止と再開
  4. 04表示オブジェクトへのフレームごとの処理追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-ticker

インストール後、Claude Code で/pixijs-tickerを入力して読み込まれたか確認します。

詳細

app.ticker は登録されたコールバックを毎フレーム実行し、UPDATE_PRIORITY.LOW で app.render() を呼び出します。各コールバックには Ticker インスタンスが渡されます。フレームレートに依存しない乗数(60fps で約 1.0)として deltaTime を読み取るか、実時間の計算には deltaMS を読み取ります。

クイックスタート

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);
};

関連スキル: pixijs-application(Application のセットアップと sharedTicker オプション)、pixijs-performance(フレームレートの最適化)、pixijs-migration-v8(v7 の ticker シグネチャの変更)。

基本パターン

時間の単位

Ticker は用途の異なる 3 つの時間値を公開します。

プロパティ型speed の影響を受ける?minFPS で上限が設定される?用途
deltaTime無次元(60fps で約 1.0)はいはいフレームレートに依存しないアニメーションの乗数
deltaMSミリ秒はいはい時間ベースの計算(ピクセル/秒)
elapsedMSミリ秒いいえいいえ生の計測、プロファイリング
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`);
});

注意点: deltaTime はミリ秒ではありません。targetFPMS が 0.06(つまり 1/16.67)の場合、deltaMS * Ticker.targetFPMS です。ちょうど 60fps のとき、deltaTime は 1.0 です。30fps のときは 2.0 です。これを時間の値として扱うと、間違いが起きやすくなります。

優先度の順序とコンテキストのバインド
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 context
フレームレートの上限設定
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 match

maxFPS は、上限を適用するために更新呼び出しをスキップします。minFPS は、フレーム落ちが大きいときに非常に大きなデルタ値が発生しないよう、deltaTime/deltaMS に上限を設定します(minFPS のデフォルト値は 10 です)。

オブジェクトごとの onRender フック
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;
};

onRender は、GPU による描画の前にシーングラフの走査中に呼び出されます。ロジックが特定の表示オブジェクトに結び付いている場合、グローバルな ticker コールバックの代わりに使用できます。

Ticker.shared、Ticker.system、新しい Ticker
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();

Application はデフォルトで独自の Ticker を作成します。app.init() で sharedTicker: true を設定すると、代わりに Ticker.shared を使用します。Ticker.shared と Ticker.system はどちらも _protected であり、destroy() を呼び出しても実際には破棄されません。計測されたフレームレートは ticker.FPS で、現在のリスナー数は ticker.count で確認できます。

アプリのライフサイクルと手動描画
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() は TickerPlugin によって追加され、ticker.start()/ticker.stop() に対応します。タブがフォーカスを失ったときに一時停止する場合、固定タイムステップのループを実行する場合、またはオフスクリーンに描画する場合は、autoStart: false と独自のフレームドライバーを使用します。

速度のスケーリング
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 elapsedMS

よくある間違い

[CRITICAL] Ticker コールバックの最初の引数はデルタ値ではありません

誤り:

app.ticker.add((dt) => {
  bunny.rotation += dt;
});

正しい例:

app.ticker.add((ticker) => {
  bunny.rotation += ticker.deltaTime;
});

v8 ではコールバックの引数としてデルタ値ではなく Ticker インスタンスが渡されます。v7 のパターン (dt) => ... はコンパイルできますが、dt は Ticker オブジェクト全体です。そのため、これを使った算術演算の結果は NaN になります。

[HIGH] フレームごとのロジックに updateTransform を使用する

誤り:

class MySprite extends Sprite {
  updateTransform() {
    super.updateTransform();
    this.rotation += 0.01;
  }
}

正しい例:

class MySprite extends Sprite {
  constructor() {
    super();
    this.onRender = this._onRender.bind(this);
  }
  private _onRender() {
    this.rotation += 0.01;
  }
}

updateTransform は v8 で削除されました。オブジェクトごとのフレーム処理には onRender コールバックを使用してください。

[MEDIUM] deltaTime をミリ秒として扱う

誤り:

app.ticker.add((ticker) => {
  // Tries to move 100px/sec but deltaTime is ~1.0, not ~16.67
  sprite.x += (100 * ticker.deltaTime) / 1000;
});

正しい例:

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;
});

deltaTime は無次元のスカラー(60fps で約 1.0)であり、ミリ秒ではありません。実時間の計算には deltaMS を使用してください。「60fps での 1 フレームあたり」の動作を実現する単純な乗数として使う場合は、deltaTime を使用します。

API リファレンス

コメント