mcpField
T
time-and-timers

time-and-timers

github.com/phaserjs開発40.6k810 回インストール10 週間前に更新
リポジトリ

time-and-timers について

ゲーム内の時間管理やイベント予約を行う開発者向けの Phaser 4 ガイドです。シーンのクロック、タイマー、コールバックやトゥイーン、サウンドを組み合わせるタイムラインを解説します。

主な機能

  1. 01遅延・反復タイマーの作成
  2. 02クロックまたは個別タイマーの一時停止
  3. 03クロックとイベントの時間倍率設定
  4. 04絶対・相対時刻でのタイムライン予約
  5. 05タイムラインでのコールバック、トゥイーン、サウンド実行

活用シーン

  1. 01シーン遷移の遅延実行
  2. 02一定間隔での敵の生成や弾の発射
  3. 03トゥイーンとサウンドを含むカットシーンの構成

インストール

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

$npx skills add https://github.com/phaserjs/phaser --skill time-and-timers

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

詳細

時間とタイマー

Phaser 4 における Clock プラグイン、TimerEvent、遅延、ループ、Timeline によるイベントシーケンス、時間の一時停止、タイムスケール、デルタタイムについて。

主要なソースパス: src/time/Clock.js、src/time/TimerEvent.js、src/time/Timeline.js、src/time/typedefs/、src/time/events/ 関連スキル: ../scenes/SKILL.md、../tweens/SKILL.md

クイックスタート

// In a Scene's create() method:

// One-shot delayed call (fires once after 1 second)
this.time.delayedCall(1000, () => {
    console.log('One second later');
});

// Repeating timer (fires 5 times, once every 500ms)
this.time.addEvent({
    delay: 500,
    callback: () => { console.log('tick'); },
    repeat: 4   // 4 repeats = 5 total fires
});

// Infinite loop timer
this.time.addEvent({
    delay: 1000,
    callback: this.spawnEnemy,
    callbackScope: this,
    loop: true
});

this.time はシーンの Clock インスタンスです(キー time で 'Clock' プラグインとして登録されています)。ゲーム時間に基づいてコールバックを発火させる TimerEvent オブジェクトを作成し、管理します。

コアコンセプト

Clock (this.time)

Clock はシーンレベルのプラグインで、ゲーム時間を追跡し、毎フレームすべての TimerEvent を更新します。主なプロパティ:

  • now -- 現在の時間(ミリ秒単位、シーンの update メソッドに渡される time と同等です)。
  • startTime -- シーンが開始されたときのタイムスタンプ。
  • timeScale -- デルタタイムに適用される乗数。デフォルトは 1。1 より大きい値ではすべてのタイマーが速くなり、1 より小さい値では遅くなり、0 では時間が凍結します。
  • paused -- true のとき、TimerEvent は更新されません。

Clock は PRE_UPDATE(保留中の追加/削除を処理するため)と UPDATE(アクティブなイベントを進めるため)をリッスンします。シーンとともに自動的にシャットダウンされ、破棄されます。

TimerEvent

TimerEvent は毎フレーム経過時間を蓄積します: elapsed += delta * clock.timeScale * event.timeScale。elapsed >= delay になると、コールバックが発火します。すべてのリピートが尽きると、イベントは次のフレームで Clock から削除されます。

設定で指定する主なプロパティ: delay、repeat、loop、callback、callbackScope、args、timeScale、startAt、paused。

Timeline (this.add.timeline)

Timeline は、特定の時点でアクションをスケジュールするためのシーケンサーです。独立したタイマーを管理する Clock とは異なり、Timeline は絶対または相対タイムスタンプをキーとするイベントの線形シーケンスを実行します。

const timeline = this.add.timeline([
    { at: 0,    run: () => { /* immediate */ } },
    { at: 1000, run: () => { /* at 1s */ } },
    { at: 2500, tween: { targets: sprite, alpha: 0, duration: 500 } }
]);
timeline.play();

Timeline は常に 一時停止 状態で開始します。開始するには play() を呼び出す必要があります。GameObjectFactory を介して作成され、シーンがシャットダウンすると自動的に破棄されます。

一般的なパターン

遅延呼び出し
// Shorthand -- fires once, no repeat
this.time.delayedCall(2000, () => {
    this.scene.start('GameOver');
});
有限回数のリピートタイマー
// repeat: 9 means 10 total fires (1 initial + 9 repeats)
const timer = this.time.addEvent({
    delay: 200,
    callback: this.fireBullet,
    callbackScope: this,
    repeat: 9
});

// Check progress
timer.getRepeatCount();       // repeats remaining
timer.getOverallProgress();   // 0..1 across all repeats
無限ループ
const spawner = this.time.addEvent({
    delay: 3000,
    callback: this.spawnWave,
    callbackScope: this,
    loop: true
});

// Stop it later
spawner.remove();  // or spawner.paused = true to pause

repeat: -1 を設定することは loop: true と同等です。

startAt による初回発火のショートカット
// First fire happens quickly (after 100ms), then every 2s
this.time.addEvent({
    delay: 2000,
    callback: this.heartbeat,
    callbackScope: this,
    loop: true,
    startAt: 1900  // pre-fill elapsed so first fire is at 100ms
});
タイマーの停止と削除
const timer = this.time.addEvent({ delay: 1000, loop: true, callback: fn });

// Option 1: Remove from clock (schedules removal next frame)
timer.remove();            // silently expires
timer.remove(true);        // fires callback one last time, then expires

// Option 2: Remove via Clock
this.time.removeEvent(timer);

// Option 3: Remove all timers
this.time.removeAllEvents();
一時停止と再開
// Pause the entire Clock (all timers freeze)
this.time.paused = true;
this.time.paused = false;

// Pause a single timer
timer.paused = true;
timer.paused = false;
タイムスケール(スローモーション / 早送り)
// Slow all timers in this scene to half speed
this.time.timeScale = 0.5;

// Speed up a single timer to 2x
timer.timeScale = 2;

// Combined: effective scale = clock.timeScale * event.timeScale
// So 0.5 * 2 = 1x for that specific timer
タイマーの状態を読み取る
timer.getProgress();              // 0..1 for current iteration
timer.getOverallProgress();       // 0..1 across all repeats
timer.getElapsed();               // ms elapsed this iteration
timer.getElapsedSeconds();        // seconds elapsed this iteration
timer.getRemaining();             // ms until next fire
timer.getRemainingSeconds();      // seconds until next fire
timer.getOverallRemaining();      // ms until final fire
timer.getOverallRemainingSeconds(); // seconds until final fire
timer.getRepeatCount();           // repeats left
Timeline: イベントのシーケンス
const timeline = this.add.timeline([
    {
        at: 0,
        run: () => { this.title.setAlpha(1); },
        sound: 'intro'
    },
    {
        at: 2000,
        tween: { targets: this.title, y: 100, duration: 1000 },
        sound: { key: 'whoosh', config: { volume: 0.5 } }
    },
    {
        at: 4000,
        set: { alpha: 0 },
        target: this.title,
        event: 'INTRO_DONE'
    }
]);

timeline.on('INTRO_DONE', (target) => { /* custom event */ });
timeline.on('complete', (tl) => { /* all events ran */ });
timeline.play();
Timeline: from と in による相対タイミング
const timeline = this.add.timeline([
    { at: 1000, run: stepOne },         // absolute: 1s from start
    { from: 500, run: stepTwo },        // relative: 500ms after previous (1.5s)
    { from: 1000, run: stepThree }      // relative: 1000ms after previous (2.5s)
]);
  • at -- Timeline の開始からの絶対ミリ秒(デフォルトは 0)。
  • in -- 現在の elapsed 時間からのオフセット(実行中の Timeline にイベントを追加するときに便利です)。
  • from -- 前のイベントの開始時間からのオフセット。

優先順位: from は in を上書きし、in は at を上書きします。

Timeline: 条件付きイベント
const timeline = this.add.timeline([
    {
        at: 5000,
        if: () => this.player.health > 0,
        run: () => { this.showBonusRound(); }
    }
]);

if コールバックが false を返した場合、イベントはスキップされます(完了としてマークされますが、アクションは実行されません)。

Timeline: ループ
const timeline = this.add.timeline([
    { at: 0, run: () => console.log('start') },
    { at: 1000, run: () => console.log('end') }
]);

timeline.repeat().play();      // infinite loop
timeline.repeat(3).play();     // loop 3 additional times (4 total runs)
timeline.repeat(false).play(); // no looping

TimelineEventConfig の loop コールバックは、リピートの反復時(初回の実行ではない)に発火します。

Timeline: 一時停止、再開、停止、リセット
timeline.pause();      // freezes elapsed counter and pauses spawned tweens
timeline.resume();     // resumes elapsed counter and unpauses spawned tweens
timeline.stop();       // sets paused=true, complete=true
timeline.reset();      // elapsed=0, all events marked incomplete, starts playing
timeline.isPlaying();  // true if not paused and not complete
timeline.getProgress(); // 0..1 based on events completed / total events
Timeline: タイムスケール
timeline.timeScale = 2;   // double speed
timeline.timeScale = 0.5; // half speed

注意: Timeline の timeScale は、Timeline によって作成されたトゥイーンには影響しません。トゥイーンのタイムスケールは別途設定してください。

Timeline: 完全なカットシーンの例

Timeline は、さまざまなアクション(コールバック、トゥイーン、サウンド、プロパティ設定、カスタムイベント)を組み合わせたカットシーンの振り付けに優れています:

class CutsceneScene extends Phaser.Scene {
    create() {
        const timeline = this.add.timeline([
            {
                at: 0,
                run: () => { console.log('Start!'); }
            },
            {
                at: 1000,
                tween: {
                    targets: this.player,
                    x: 400,
                    duration: 500,
                    ease: 'Power2'
                }
            },
            {
                at: 1500,
                sound: 'doorOpen'
            },
            {
                at: 2000,
                set: { visible: true },
                target: this.door
            },
            {
                from: 500,
                run: () => { console.log('Relative timing'); }
            },
            {
                at: 5000,
                event: 'cutsceneDone',
                stop: true
            }
        ]);

        timeline.on('cutsceneDone', () => {
            this.scene.start('GameScene');
        });

        timeline.play();
    }
}
タイマーのリセットと再利用

完了した TimerEvent は、新しい設定でリセットし、Clock に再追加できます:

const timer = this.time.addEvent({
    delay: 1000,
    callback: this.phase1,
    callbackScope: this,
    repeat: 2
});

// Later, after it completes, reconfigure and re-add:
timer.reset({
    delay: 500,
    callback: this.phase2,
    callbackScope: this,
    repeat: 4
});
this.time.addEvent(timer);  // must re-add; reset() alone does not schedule it

設定リファレンス

TimerEventConfig
プロパティ型デフォルト説明
delaynumber0コールバックが発火するまでの遅延時間(ミリ秒)
repeatnumber0初回発火後に繰り返す回数。無限に繰り返すには -1 を使用します
loopbooleanfalsetrue の場合、無期限に繰り返します(repeat: -1 と同じ)
callbackfunction--タイマー発火時に呼び出される関数
callbackScopeanyTimerEventコールバックの this コンテキスト
argsArray[]コールバックに渡される追加引数
timeScalenumber1イベントごとの時間乗数
startAtnumber0経過時間を事前に設定します(ミリ秒)(初回発火が早くなります)
pausedbooleanfalseタイマーを一時停止状態で開始します
TimelineEventConfig
プロパティ型デフォルト説明
atnumber0タイムライン開始からの絶対時間(ミリ秒)
innumber--現在の経過時間からのオフセット(at を上書きします)
fromnumber--前のイベント時刻からのオフセット(at と in を上書きします)
runfunction--イベント発火時に呼び出されるコールバック
loopfunction--繰り返しのイテレーションで呼び出されるコールバック(初回実行時を除く)
iffunction--ガード関数。false を返すとイベントをスキップします
eventstring--Timeline インスタンスで発行されるイベント名
targetany--run/loop/if のスコープ、および set のターゲット
setobject--イベント発火時に target に適用されるキーと値のペア
tweenTweenConfig--イベント発火時に作成されるトゥイーンの設定またはインスタンス
soundstring/object--再生するサウンドキーまたは { key, config }
oncebooleanfalse発火後にこのイベントを削除します
stopbooleanfalseこのイベントの発火時にタイムライン全体を停止します
TimelineEvent(内部)

timeline.events[] に格納される処理済みのイベントオブジェクト。設定に以下を追加したものです。

プロパティ型説明
completebooleanこのイベントが発火したかどうか
timenumber解決された絶対時間(ミリ秒)
repeatnumberこのイベントが繰り返された回数
tweenInstanceTween/TweenChain生成されたトゥイーンへの参照(存在する場合)

イベント

タイムラインイベント
イベント定数リスナーシグネチャ発火タイミング
'complete'Phaser.Time.Events.COMPLETE(timeline)すべてのタイムラインイベントが実行されたとき

TimelineEventConfig の event プロパティによるカスタムイベントも、(target) というシグネチャで Timeline インスタンス上に発行されます。

TimerEvent / Clock

TimerEvent と Clock は EventEmitter イベントを発行しません。タイマーは callback プロパティを直接使用します。Clock はシーンライフサイクルイベント(PRE_UPDATE、UPDATE、SHUTDOWN、DESTROY)によって管理されます。

API クイックリファレンス

Clock(this.time)
メソッドシグネチャ戻り値説明
addEvent(config | TimerEvent)TimerEventタイマーイベントを作成してスケジュールします
delayedCall(delay, callback, args?, scope?)TimerEvent単発の遅延呼び出しの省略記法
removeEvent(event | event[])this特定のタイマーを削除します
removeAllEvents()thisすべてのアクティブなタイマーの削除をスケジュールします
clearPendingEvents()thisまだアクティブリストに追加されていないタイマーをクリアします
プロパティ型説明
nownumber現在のクロック時間(ミリ秒)
startTimenumberシーンが開始された時刻
timeScalenumberすべてのタイマーのデルタ乗数
pausedbooleanすべてのタイマーを凍結します
TimerEvent
メソッド戻り値説明
getProgress()number現在のイテレーションの進捗 (0..1)
getOverallProgress()numberすべての繰り返しを通した進捗 (0..1)
getElapsed()numberこのイテレーションの経過時間 (ミリ秒)
getElapsedSeconds()numberこのイテレーションの経過時間 (秒)
getRemaining()number次に発火するまでのミリ秒
getRemainingSeconds()number次に発火するまでの秒数
getOverallRemaining()number最後の発火までのミリ秒
getOverallRemainingSeconds()number最後の発火までの秒数
getRepeatCount()number残りの繰り返し回数
remove(dispatchCallback?)voidタイマーを終了します (任意でコールバックを発火)
reset(config)TimerEvent新しい設定で再初期化します
destroy()voidコールバック参照を null にします
Timeline (this.add.timeline)
メソッドシグネチャ戻り値説明
add(config | config[])thisタイムラインにイベントを追加します
play(fromStart?)this再生を開始します (デフォルトでは先頭にリセット)
pause()thisタイムラインと生成されたトゥイーンを一時停止します
resume()thisタイムラインと生成されたトゥイーンを再開します
stop()this停止します (一時停止 + 完了に設定)
reset(loop?)this経過時間とすべてのイベントを未完了にリセットします
repeat(amount?)thisループ回数を設定します (-1/true=無限、false=なし)
clear()thisすべてのイベントを削除し、経過時間をリセットして一時停止します
isPlaying()boolean一時停止しておらず完了もしていない場合に true
getProgress()number完了したイベント数に基づく 0..1
プロパティ型説明
elapsednumber現在の経過時間 (ミリ秒)
timeScalenumberデルタの倍率 (生成されたトゥイーンには影響しません)
pausedbooleanタイムラインが一時停止しているかどうか
completebooleanすべてのイベントが実行されたかどうか
loopnumber追加のループ回数 (0=なし、-1=無限)
iterationnumber現在のループイテレーション
totalCompletenumber発火したイベントの数
eventsTimelineEvent[]内部のイベント配列

注意点

  1. repeat と total fires の違い。 repeat: 4 はコールバックが合計 5 回呼び出されることを意味します(初回 1 回 + リピート 4 回)。これはよくある off-by-one の原因です。
  2. repeat を指定したゼロ遅延は例外をスローします。 delay: 0 と任意の repeat/loop を組み合わせた TimerEvent は 'TimerEvent infinite loop created via zero delay' をスローします。
  3. タイムラインは一時停止状態で開始します。 作成後に timeline.play() を呼び出す必要があります。これを忘れるのはよくある間違いです。
  4. タイムラインの timeScale はトゥイーンに影響しません。 timeline.timeScale を設定すると、タイムライン自身の経過カウンターのみがスケールされます。タイムラインによって作成されたトゥイーンは独自の速度で実行されます。トゥイーンの timeScale を個別に設定するか、TweenManager を使用してください。
  5. once イベントは永続的に削除されます。 once: true のタイムラインイベントは発火後に取り除かれ、reset() やループ時に再び現れることはありません。
  6. タイマーの追加は遅延されます。 addEvent() は preUpdate で処理される保留リストにプッシュします。タイマーは次のフレームまでアクティブになりません。
  7. Clock の paused と timeScale 0 の違い。 どちらもタイマーを凍結しますが、paused = true は更新ループを完全にスキップするのに対し、timeScale = 0 はデルタをゼロにしてループを実行し続けます。完全に凍結するには paused を推奨します。
  8. callbackScope のデフォルト。 callbackScope を省略すると、コールバック内の this はシーンではなく TimerEvent 自体になります。アロー関数を使うか、明示的に callbackScope: this を渡してください。
  9. TimerEvent インスタンスの再利用。 TimerEvent オブジェクトを addEvent() に渡すことはできますが、完了状態であってはなりません。Clock はその経過時間とディスパッチ状態をリセットします。
  10. タイムラインの from チェーン。 各 from オフセットは、前の from 値ではなく、前のイベントの解決された時間を基準にしています。イベントは配列の順序で処理されます。
  11. シーンの一時停止はタイムラインも一時停止します。 シーンが一時停止されると(scene.pause())、タイムラインの更新はシーンの更新ステップによって駆動されるため、タイムラインの更新ループも停止します。
  12. timer.reset() は Clock に再追加しません。 timer.reset(config) を呼び出すとタイマーは再初期化されますが、スケジュールはされません。リセット後に再度 this.time.addEvent(timer) を呼び出す必要があります。

ソースファイルマップ

ファイル説明
src/time/Clock.jsシーン Clock プラグイン -- TimerEvent の作成、更新、削除
src/time/TimerEvent.js個別のタイマー -- delay、repeat、loop、進捗トラッキング
src/time/Timeline.jsイベントシーケンサー -- スケジュールされたアクション、トゥイーン、サウンド、ループ
src/time/typedefs/TimerEventConfig.jsaddEvent() の設定 typedef
src/time/typedefs/TimelineEventConfig.jstimeline.add() の設定 typedef
src/time/typedefs/TimelineEvent.js内部イベントオブジェクト typedef
src/time/events/COMPLETE_EVENT.jsタイムライン用の 'complete' イベント定数
src/time/events/index.jsイベント名前空間のバレルファイル

コメント