Metlivi ブログ

バーチャルペットのゲームループでアイドル状態とインタラクティブ状態を分離する方法

バーチャルペットゲームでは、自律的な動作とプレイヤーのアクションを別々の更新パスに保ち、明示的な遷移を通じて両方が1つの共有ペット状態を変更できるようにします。アイドル動作は経過時間によって進行し、インタラクティブ動作は入力イベントまたは現在の入力状態に応答するようにすべきです。これにより、一時停止やテストが容易になり、ペットのアニメーションや欲求タイマーがプレイヤーのコマンドと競合するのを防ぐことができます。

2026年10月15日読了所要時間:6分Metlivi Editorial Team
セクション 1

「アイドル」と「インタラクティブ」の定義を明確にする

これらを必ずしも異なるシーンや個別のループではなく、動作モードとして扱います。**アイドル(idle)**では、ペットは日常のルーチンを実行します。些細な環境アクションの選択、タイマーの進行、必須ではないアニメーションの再生などです。**インタラクティブ(interactive)**では、ゲームはタップ、ドラッグ、選択されたコマンドなどの意図的なアクションを処理します。インタラクション中もペットのアニメーションが再生される場合があります。違いは、どのシステムが意思決定を行い、ゲームプレイの状態を変更できるかという点にあります。

まずは、プレイヤーが実行できるアクションと、ペットが実行できる自律的な動作の短いリストを作成します。それぞれがどの状態変数を変更できるかをマークします。例えば、環境に応じた瞬きは見た目の描画のみに影響するかもしれませんが、選択された「遊ぶ」アクションはペットの現在のアクティビティを変更し、タイマーを開始する可能性があります。このシンプルな所有権マップは、コードが肥大化する前に競合を明らかにするのに役立ちます。

セクション 2

外側のループをペットの動作から独立させる

エンジンのフレームコールバックは、ペットのすべてのルールを内包するのではなく、処理の調整役を担うべきです。有用なシーケンスは、入力の収集、有効なコマンドの適用、シミュレーションの進行、そして最新状態のレンダリングです。タップが誤ってタイマーの刻みとして扱われないよう、入力収集はシミュレーションから分離し、レンダリングにはゲームプレイの変更を含めないようにします。『Game Programming Patterns』では、この分離を入力の処理、ゲームの更新、そしてレンダリングを繰り返すループとして説明しています。固定ステップの更新は、シミュレーションに安定したインターバルが必要な場合に役立ちます。Game Loop, Game Programming Patterns

ウェブゲームの場合、requestAnimationFrame は再描画の前に処理をスケジュールし、経過時間の測定に使用できるタイムスタンプを提供します。ブラウザは一般に非表示のタブでこれらのコールバックを一時停止するため、ゲームがバックグラウンドにある間も信頼できる実時間時計として継続すると想定しないでください。Window.requestAnimationFrame(), MDN

セクション 3

プレイヤー入力をコマンド経由でルーティングする

生の入力を start_play、stop_play、pet_tap などの小さなコマンドに変換します。コマンドハンドラーは、現在のアクションが現在のモードに対して有効かどうかを確認し、共有モデルを1回更新して、結果として生じるプレゼンテーションの合図を発行します。これにより、ボタンのコールバック、アニメーションのコールバック、アイドルのルーチンにアクションのロジックが同時に散らばるのを防ぎます。

例えば、ペットがすでに遊んでいる最中にプレイヤーがタップした場合、タップを無視する、別のアクティビティを選択する、アクティビティを停止するなど、結果を意図的に定義します。アイドルの選択処理とタップハンドラーの両方が同じ更新フレーム内で新しいアクティビティを割り当てるような事態は避けてください。イベント伝播を持つエンジンの場合、適切な段階でゲームプレイの入力を処理し、UIによる消費を尊重します。Godotの Node ドキュメントでは、GUIコントロールの優先度が必要な場合、未処理の入力(unhandled input)の方がゲームプレイに適していることが多いと記されています。Node class, Godot documentation

セクション 4

明確なクロックでアイドル時間を進める

画面に表示されているセッション中に継続して進行すべき動作については、経過シミュレーション時間を累積し、そのインターバルに達したときにアイドルの決定をトリガーします。フレームをカウントしてはいけません。フレームの頻度は変動するためです。Godotでは、_process(delta) が前回のアイドルフロームからの経過時間を受け取るのに対し、_physics_process(delta) は物理演算の刻みに従います。ドキュメントには、特定の条件下では累積されたdeltaが実世界の時間(秒)から乖離する可能性があることも記載されています。Node class, Godot documentation

動作に応じてクロックを選択してください。見た目だけの動きには、通常フレームの経過時間を使用できます。衝突判定が関係する動きは、エンジンの物理演算更新に属します。ペットの「数秒ごとに環境アクションを選択する」タイマーにはシミュレーションタイマーを使用できますが、長いフレームや一時停止の後に何が起こるかを決定しておく必要があります。経過量に上限を設けるか、決定を1回だけ実行するか、制限されたステップ内で追いつくようにするかです。上限のないキャッチアップを行うと、ゲームが再開されたときにペットが多くの状態を一気に飛び越えてしまう可能性があります。

セクション 5

モード遷移を明示的にする

状態を追加する前に、小さな遷移表を書き出しておきましょう。例えば、idle → playing はプレイヤーが選択したアクティビティを開始し、playing → idle はそれが終了するかプレイヤーがキャンセルしたときに発生し、idle → resting は自律ルーチンによって選択される場合があります。タイマーの開始やクリア、関連するアニメーションの選択など、開始時と終了時の処理(entry/exit effects)を一箇所で定義します。ゲームプレイのモードが変化した証拠として、アニメーションの完了だけを使用しないでください。視覚的な再生は中断されたりスキップされたりすることがあるためです。

遷移関数は現在のモードを検証し、モデルを更新して、レンダラーが表示できる結果を返すようにすべきです。これにより、「ペットが何をしているか」と「そのアクションがどのように描画されるか」が分離されます。また、テストの対象も明確になります。コマンドを送信し、結果のモードを検査して、アイドルルーチンがそれを上書きしないことを検証します。

セクション 6

バックグラウンド時間の動作を決定する

一般的なポリシーは2つあり、どちらが適切かはゲームデザインによって異なります。セッション中のみ動作するペットの場合、一時停止中はシミュレーションを停止し、以前の状態から再開できます。ゲームを閉じている間もタイマーを進行させたい場合は、基準となる時間を記録し、復帰時に経過時間を調整(リコンサイル)する必要があります。バックグラウンドでフレームループを実行しようとするのではなく、別個の再開時計算として扱ってください。ブラウザのアニメーションコールバックは非表示のタブでは一時停止される可能性があります。Window.requestAnimationFrame(), MDN

シンプルなペットの場合は、本当に進めるべき数値(例えば1つのアクティビティタイマーなど)のみを調整し、キャッチアップには妥当な上限を設けます。その後、短いインターバルと長いインターバルの両方でアプリを閉じて再度開くテストを行います。クロックの選択、サスペンド時の動作、キャッチアップの上限はデザイン上の決定事項であり、エンジンのフレームコールバックが勝手に決めてくれるものではありません。

セクション 7

競合する更新と入力漏れを確認する

再現可能なシナリオをいくつか用意してループをテストします。ゲームを数インターバルの間アイドル状態のまま放置する、アイドルの決定が行われる直前にコマンドを発行する、入力を長押しまたは連打する、一時停止して再開する、アニメーションの再生中に新しいアクションをトリガーするなどです。各コマンドがモデルを1回だけ変更すること、アイドルロジックがプレイヤーの選択した状態を置き換えないこと、そして経過時間の動作が選択した一時停止ポリシーと一致していることを確認します。

シミュレーションに固定更新を使用している場合は、レンダリングされるフレームの間にそれが0回、1回、または複数回実行される可能性があることを覚えておいてください。Unityは FixedUpdate におけるこの動作をドキュメント化しており、物理計算にそれを使用することを推奨しています。入力と視覚的な更新ではタイミングの考慮事項が異なります。FixedUpdate(), Unity documentation また、UnityのInput Systemはデバイスイベントをキューに入れ、設定された更新モードに従って処理するため、入力処理をそれらのコマンドを消費するループと一致させてください。Input event queue, Unity Input System

セクション 8

維持すべき実践的な分離

アーキテクチャは小さく保ちます。1つの共有ペットモデル、1つの入力からコマンドへのパス、1つのアイドル動作更新、1つの明示的な遷移関数、そしてモデルを読み取るレンダラーです。タイミングに敏感な動作が必要な場合にのみ固定シミュレーションステップを追加し、すべてのアニメーションや環境の選択を物理ティックに依存させないようにします。バグが発生したときは、誰が最後にモードを変更したか、どのクロックがそれを進めたかを調査します。これにより、各更新に明確な役割が与えられ、ペットのアクションが増えてもアイドル動作とインタラクティブ動作の予測可能性が保たれます。

セクション 9

出典

関連記事

このテーマをさらに見る