NarraLeaf

プリロード

プレイヤーがシーンの資産をクリティカル層と先読み層の2段階でプリロードする方法、および待つべきライフサイクル信号

このページで説明する挙動は 0.17.0 以降で利用可能です。

プレイヤーは、シーンが描画される前にその資産をフェッチしてデコードします。0.17.0 以降、この処理は ゲームに入ったときではなく、ストーリーが読み込まれた時点で始まるようになり、2 段階で実行されるため、 最初のフレームはそれが必要とする資産だけを待ちます。

onPreloadComplete の発火位置が変わりました。 現在はゲームに入るに発火し、その時点では メニューがまだ画面に表示されている可能性があります。「ゲームの内容が画面上にある」という信号には onFirstSceneReady を使ってください。参照: どの信号を待つべきか

プリロードが始まるタイミング

Player は、ストーリーが読み込まれた時点ですぐに story.entryScene をプリロード対象のシーンとして 登録するため、フェッチはすでに画面にある何かの裏側で行われます。何もマウントされず、アクションも 実行されません。

自動登録が適用されるのは、プリロード中のシーンも、マウント済みのシーンも存在しない場合のみです。 そのため、自ら preloadScene を呼び出す ホストは、自分の選択を保持できます。

クリティカル層と先読み層

シーンの資産リストは推移的です。つまり、そのシーンから到達可能なすべてのシーンの資産セットを含みます。 このパスは 2 段階で実行されるため、最初のフレームがそのすべてを待つ必要はありません。

保持する内容実行方法
クリティカル層(critical)これから描画されるシーンが直接登録するもの。自身の背景と画像、それに
自身が遷移する先のシーンの直接の背景ペーシングなしで実行され、event:preloaded.complete
つまり最初の描画フレームを制御する唯一の層
先読み層(look-ahead)ここから到達可能なすべてのシーンの完全な資産セットから、すでにクリティカル
層に含まれるものを除いたものクリティカル層の後に実行され、preloadDelay によってペーシングされる。
何もこれを待たない

preloadDelay は最初のフレームのコストには計上されません。投機的な作業だけをペーシングします。 キャッシュ退避パスは両方の層の和集合に対して 1 回だけ実行され、置き換えられたパスに対してはスキップ されるため、プリロードの途中でシーンを切り替えても、現在のシーンがちょうどキャッシュした画像は 失われません。

preloadAllImages: false で動作するゲームは、アクションによる予測方式の挙動を維持しており、 このページの内容はそれらには当てはまりません。

デコード済みビットマップ

クリティカル層は、ソースがキャッシュから外れるまでデコード済みの要素を保持するため、最初に表示される フレームは再度デコードされることがありません。

先読み層はそれらを保持しません。フル解像度のビットマップは 幅 × 高さ × 4 バイトのコストがかかります。

サウンドのプリロード

クリティカル層は、オーディオマネージャーの preload を通じて、現在のシーンのサウンドも温めます。

<Player
    story={story}
    onReady={({ gameState }) => {
        // 音源を再生せずに、フェッチしてデコードし、オーディオキャッシュへ入れる
        void gameState.audioManager.preload(bgm);
    }}
/>
  • preload(sound: Sound): Promise<void> - 音源がオーディオキャッシュに入ったときに resolve します。 読み込みに失敗した音源は警告としてログに記録されるだけで、代わりに初回再生時に読み込まれるため、 この Promise は決して reject しません。

この Promise で何かをゲートしないでください。 ブラウザの自動再生ポリシーがユーザー操作によって 満たされるまでオーディオコンテキストはロックされたままなので、誰もまだ触れていないページでは オーディオのウォームアップが保留のまま留まることがあります。エンジン自身の呼び出しは、発行した ら結果を気にしない方式です。

自動的に温められるのは現在のシーンのサウンドだけです。先読み対象のシーンの音声は、そのシーン自身の パスに委ねられます。

どの信号を待つべきか

信号発火するタイミング
onReadyPlayer インスタンスが初期化された
とき。newGame() はここに置くべきです。これはプリロードや初回レンダリングの保証ではありません。
onPreloadComplete初回のプリロードパス(クリティカル層)が終わったとき。0.17.0 以降、これは
ゲームに入る前です。メニューがまだ画面にあり、どのシーンもマウントされていない可能性があります。
onFirstSceneReadyプリロードパスが終わり、最初のシーンコンポーネントがマウントされ、さらに
ブラウザがそれを描画するフレームを 1 回消化した状態。これが「内容が画面上にある」という信号です。

後者の 2 つは Player の prop としても Game のメソッドとしても存在し、それぞれゲームのライフサイクル 内で最大 1 回だけ発火します。

<Player
    story={story}
    onReady={({ liveGame }) => liveGame.newGame()}
    onPreloadComplete={() => setLoadingBarDone(true)}   // メニューがまだ表示されている場合がある
    onFirstSceneReady={() => setLoadingOverlay(false)}  // シーンが描画された
/>
// Player 要素以外のコードのための、同じ時点。
await game.whenPreloadComplete();
await game.whenFirstSceneReady();

game.isPreloadComplete();
game.isFirstSceneReady();

両方の時点それぞれの on*once*when*is* を含む完全なリスナー一覧は Game を参照してください。

0.16 以前からのアップグレード

これは挙動の破壊的変更であり、新しい API ではありません。 onPreloadCompleteoncePreloadCompletewhenPreloadComplete()event:preloaded.complete はいずれも、 newGame() がシーンをマウントした後ではなく、ゲームに入る前に発火するようになりました。 名前とシグネチャは変わっていないため、コンパイルが失敗することはありません。そして、そこで ローディング画面を隠していたホストは、今やマウントされていないステージを露出させることに なります。

  • 読み込みステップの制御(プログレスバーや、資産がまだダウンロード中は押せないようにする 「開始」ボタンなど)に使っていた場合: 変更は不要です。
  • **「ゲームの内容が画面上にある」**ことを意味させていた場合: onFirstSceneReady / whenFirstSceneReady() に切り替えてください。これらは変更されておらず、依然としてマウント 済みのシーンを必要とします。

preloadComplete リスナーが受け取る ctx.scene は、現在ではマウント済みのシーンではなく プリロード中のシーンである場合があります。

onPreloadedReady は非推奨であり、onPreloadComplete の使用が推奨されます。

シーンを自分でプリロードする

入口シーン以外のシーンを温めるには、それを指定します。プレイヤーがどのシーンへ再開しようとしているかを 知っているセーブスロット画面は、次のように呼び出せます。

gameState.preloadScene(scene);   // または Story を渡すと、その入口シーンが使われる

Player が入口シーンを登録する前にこれを呼び出すと、自動登録は行われません。

設定

以下は GameConfig 上にあります。

  • preloadAllImages(デフォルト true)- 2 段階のシーンパスを実行するかどうか。false の場合、 プレイヤーは次の maxPreloadActions 個のアクションを予測し、代わりにそのソースをプリロードします。
  • preloadConcurrency(デフォルト 5)- 両方の層で同時にフェッチする画像の数。
  • preloadDelay(デフォルト 100)- 先読みバッチ間のペーシング。クリティカル層はペーシングされません。
  • waitForPreload(デフォルト true)- クリティカル層が終わるまでプレイヤーの表示を保留する。
  • forceClearCache(デフォルト false)- シーンが変わったときに画像キャッシュをクリアする。
  • maxPreloadActions(デフォルト 10)- preloadAllImages: false の経路が何アクション先まで 予測するか。

このページの目次