このカジュアルなドライビング ゲームでは、プロシージャル生成の無限の風景で WebGL の可能性を探ることができます。
Slow Roads は、無限に生成されるプロシージャ シーンに重点を置いたカジュアルなドライビング ゲームです。すべて WebGL アプリケーションとしてブラウザでホストされます。多くの人にとって、このような集中的なエクスペリエンスは、ブラウザの制限されたコンテキストでは場違いに思えるかもしれません。実際、このプロジェクトの目標の一つは、そうした考え方を正すことでした。この記事では、ウェブでの 3D の可能性を強調するために、パフォーマンスのハードルを乗り越えるために使用したテクニックをいくつか紹介します。
ブラウザでの 3D 開発
低速道路のリリース後、フィードバックに「ブラウザでできることを知らなかったので」というコメントが繰り返し寄せられました。このような考えをお持ちの方は、決して少数派ではありません。2022 年の JS の状況に関する調査によると、デベロッパーの約 80% がまだ WebGL を試していません。特にブラウザベースのゲームでは、これほど多くの可能性を逃す可能性があるのは残念です。Slow Roads を通じて、WebGL をさらに注目を集め、高パフォーマンスの JavaScript ゲームエンジンというフレーズに躊躇するデベロッパーの数を減らすことができれば幸いです。
WebGL は多くの人にとって神秘的で複雑に見えるかもしれませんが、近年、その開発エコシステムは高度な機能と利便性を備えたツールとライブラリに大きく成熟しています。コンピュータ グラフィックスの経験がなくても、フロントエンド デベロッパーが 3D UX を自分の仕事に組み込むことが、これまで以上に簡単になりました。主要な WebGL ライブラリである Three.js は、3D コンポーネントを React フレームワークに導入する react-three-fiber など、多くの拡張機能の基盤として機能します。また、Babylon.js や PlayCanvas などの包括的なウェブベースのゲーム エディタも登場し、使い慣れたインターフェースと統合されたツールチェーンを提供しています。
これらのライブラリは非常に有用ですが、野心的なプロジェクトは最終的に技術的な制限に直面します。ブラウザベースのゲームのアイデアに懐疑的な人は、JavaScript がシングルスレッドでリソースに制約があることを強調するかもしれません。ただし、これらの制限を回避することで、隠れた価値を引き出すことができます。ブラウザで実現される即時アクセスと幅広い互換性を提供できるプラットフォームは他にありません。ブラウザ対応のシステムであれば、ユーザーはワンクリックで再生を開始できます。アプリをインストールしたり、サービスにログインしたりする必要はありません。言うまでもなく、デベロッパーは、UI の構築やマルチプレーヤー モードのネットワーキングの処理に堅牢なフロントエンド フレームワークを利用できるという、エレガントで便利な機能を利用できます。こうした価値が、ブラウザをプレーヤーとデベロッパーの両方にとって優れたプラットフォームにしていると思います。また、Slow Roads で示されているように、技術的な制限は多くの場合、設計の問題に帰着できます。
低速道路でのスムーズな走行
スローロードのコア要素には高速モーションと高価な風景生成が含まれるため、スムーズなパフォーマンスの必要性がすべての設計上の決定に影響しました。私の主な戦略は、エンジンのアーキテクチャ内でコンテキスト ショートカットを実行できるように、簡素化されたゲームプレイ設計から始めることでした。ただし、ミニマリズムを追い求めるあまり、便利な機能が犠牲になるというデメリットもあります。その結果、さまざまなブラウザやデバイスで適切に動作する、カスタマイズされたハイパー最適化システムが実現します。
以下に、Slow Roads をシンプルに保つための主なコンポーネントを示します。
ゲームプレイを中心に環境エンジンを形作る
ゲームの主要コンポーネントである環境生成エンジンは、必然的に費用が高く、メモリとコンピューティングの予算の大部分を占めています。ここで使用されているトリックは、パフォーマンスの急増でフレームレートが中断されないように、負荷の高い計算をスケジュールし、一定期間に分散することです。
環境はジオメトリのタイルで構成され、カメラからの距離に応じてサイズと解像度(「レベル オブ ディテール」または LoD として分類)が異なります。自由に移動できるカメラを備えた一般的なゲームでは、プレイヤーがどこに移動しても周囲を詳細に描写するために、さまざまな LoD を絶えず読み込み、アンロードする必要があります。これは、特に環境自体が動的に生成される場合、費用とリソースの浪費につながる可能性があります。幸い、この規則は、ユーザーが道路に留まるべきというコンテキスト上の期待のおかげで、低速道路では完全に無視できます。代わりに、ルートの両側にある狭い通路に高精細ジオメトリを予約できます。

道路の中央線自体は、プレイヤーが到着するずっと前に生成されるため、環境の詳細が必要な正確な時刻と場所を正確に予測できます。その結果、費用のかかる作業を事前にスケジュールし、各時点で必要な最小限の作業のみを生成できる、無駄のないシステムが実現します。また、目に見える部分以外の詳細に労力を浪費することもありません。この手法は、道路が分岐のない単一のパスでのみ可能です。これは、アーキテクチャのショートカットに対応するゲームプレイのトレードオフを示す良い例です。

物理法則にこだわる
環境エンジンの計算需要に次ぐのが物理シミュレーションです。低速道路では、利用可能なすべてのショートカットを利用するカスタムの最小限の物理エンジンが使用されます。
ここでの大きな節約は、最初からオブジェクトを過度にシミュレートしないことであり、動的衝突や破壊可能なオブジェクトなどを割り引くことで、最小限の禅的なコンテキストに傾倒します。車両が道路上にあると仮定すると、オフロードの物体との衝突は合理的に無視できます。また、道路をスパースな中央線としてエンコードすることで、道路の中央までの距離チェックに基づいて、道路面やガードレールとの高速な衝突検出を実現できます。オフロードでの走行はコストが高くなりますが、これはゲームプレイのコンテキストに適した公正なトレードオフの例です。
メモリ使用量の管理
ブラウザで制限されているリソースのもう 1 つとして、JavaScript はガベージ コレクションされるにもかかわらず、メモリを慎重に管理することが重要です。見落としがちですが、ゲームループ内で少量の新しいメモリを宣言すると、60 Hz で実行すると大きな問題につながる可能性があります。マルチタスクを実行している可能性が高いコンテキストでユーザーのリソースを消費するだけでなく、大規模なガベージ コレクションが完了するまでに数フレームかかるため、顕著なスタッターが発生する可能性があります。これを回避するには、初期化時にクラス変数にループメモリを事前に割り当て、各フレームでリサイクルします。

また、ジオメトリやそれに関連するデータバッファなどの重いデータ構造を経済的に管理することも非常に重要です。Slow Roads のような無限生成ゲームでは、ほとんどのジオメトリが一種のトレッドミルに存在します。古いピースが後方に消えていくと、そのデータ構造は保存され、ワールドの次のピースのために再利用されます。これはオブジェクト プーリングと呼ばれる設計パターンです。
これらの方法は、コードの簡素さを犠牲にして、リーンな実行を優先するのに役立ちます。パフォーマンス重視のコンテキストでは、デベロッパーの利益のために、便利な機能がクライアントから借用することがある点に注意する必要があります。たとえば、Object.keys()
や Array.map()
などのメソッドは非常に便利ですが、それぞれが戻り値に新しい配列を作成していることは見落としやすいものです。このようなブラックボックスの内部動作を理解することで、コードを強化し、パフォーマンスの低下を回避できます。
プロシージャル生成アセットによる読み込み時間の短縮
ゲーム デベロッパーにとって主な懸念事項はランタイム パフォーマンスですが、ウェブページの最初の読み込み時間に関する一般的な原則は引き続き有効です。ユーザーは、負荷の高いコンテンツに意図的にアクセスする場合は寛容になるかもしれませんが、読み込み時間が長いと、ユーザーの維持につながらないだけでなく、エクスペリエンスにも悪影響を及ぼす可能性があります。ゲームでは、テクスチャ、サウンド、3D モデルなどの大規模なアセットが必要になることが多く、少なくとも、詳細を削減できる部分は慎重に圧縮する必要があります。
また、クライアントでアセットをプロシージャルに生成することで、長時間の転送を回避することもできます。これは、接続速度が遅いユーザーにとって大きなメリットです。また、デベロッパーは、最初の読み込みステップだけでなく、さまざまな品質設定に応じて詳細レベルを調整する際にも、ゲームの構成をより直接的に制御できます。
低速道路のジオメトリのほとんどはプロシージャル生成でシンプルなもので、カスタム シェーダーが複数のテクスチャを組み合わせて詳細を表現しています。欠点は、これらのテクスチャが重いアセットになる可能性があることです。ただし、小さなソース テクスチャからより詳細なディテールを実現できる確率的テクスチャリングなどの方法で、さらに節約できる可能性があります。極端なレベルでは、texgen.js などのツールを使用して、テクスチャを完全にクライアント上で生成することもできます。音声についても同じことが言えます。Web Audio API を使用すると、音声ノードで音声を生成できます。
プロシージャル アセットのメリットにより、初期環境の生成にかかる時間は平均で 3.2 秒です。事前ダウンロードのサイズを小さくすることを最大限に活用するため、シンプルなスプラッシュ画面で新しい訪問者を迎え、高負荷なシーンの初期化は肯定的なボタンが押された後まで延期します。また、バウンスされたセッションの便利なバッファとして機能し、動的に読み込まれるアセットの転送の無駄を最小限に抑えます。
遅い最適化にアジャイル アプローチを適用する
私は、Slow Roads のコードベースを常に試験運用版と見なしており、そのため開発には非常にアジャイルなアプローチを採用しています。複雑で急速に進化するシステム アーキテクチャを扱う場合、重要なボトルネックが発生する場所を予測するのは困難です。重点を置くべきなのは、きれいに実装することではなく、必要な機能を迅速に実装することです。その後、本当に重要な部分でシステムを最適化するようにします。このステップでは、Chrome DevTools のパフォーマンス プロファイラが非常に役立ちます。このプロファイラは、以前のバージョンのゲームに関する重大な問題の診断にも役立ちました。デベロッパーとして貴重な時間を費やさないように、重要でない問題や冗長な問題の検討に時間を費やさないようにしてください。
ユーザー エクスペリエンスのモニタリング
これらのトリックをすべて実装する際は、ゲームが実際の環境で想定どおりに動作することを確認することが重要です。さまざまなハードウェアの機能を考慮することは、どのゲーム開発でも基本的な要素ですが、ウェブゲームでは、ハイエンドのパソコンと 10 年前のモバイル デバイスの両方を同時にターゲットに設定できます。最も簡単な方法は、プロファイラによって検出された、GPU と CPU の両方の負荷の高いタスクについて、コードベースで最も可能性の高いボトルネックを適応させる設定を提供することです。
ただし、自分のマシンでのプロファイリングではカバーできる範囲に限界があるため、なんらかの方法でユーザーとのフィードバック ループを閉じることが重要です。Slow Roads では、パフォーマンスと、画面解像度などのコンテキスト要因をレポートするシンプルな分析を実行しています。これらの分析情報は、socket.io を使用して基本的な Node バックエンドに送信され、ユーザーがゲーム内フォームから送信した書面によるフィードバックも一緒に送信されます。初期の段階では、これらの分析により、UX を簡単に変更することで軽減できる多くの重要な問題が検出されました。たとえば、FPS が常に低いことが検出されたときに設定メニューをハイライト表示したり、パフォーマンスが特に低い場合はハードウェア アクセラレーションを有効にするようユーザーに警告したりしました。
今後の道路の状況
こうした対策をすべて講じても、低い設定でプレイする必要があるプレーヤーの割合は依然として大きく、特に GPU を搭載していない軽量デバイスを使用しているプレーヤーがこれに該当します。利用可能な画質設定の範囲は、パフォーマンスの分布が比較的均等ですが、55 FPS を超えるのはプレーヤーの 52% のみです。

幸い、パフォーマンスを改善して費用を節約できる機会はまだまだあります。GPU の需要を減らすためのレンダリング トリックの追加に加えて、近い将来、環境生成を並列化するウェブワーカーをテストしたいと考えています。最終的には、WASM または WebGPU をコードベースに組み込む必要が生じる可能性があります。空き容量を増やすことで、より豊かで多様な環境を実現できます。これは、残りのプロジェクトの継続的な目標となります。
趣味のプロジェクトとして、Slow Roads は、驚くほど精巧で、パフォーマンスが高く、人気のあるブラウザゲームがどのように作れるかを実証する、非常に充実した方法でした。WebGL に興味を持っていただけたなら、技術的には、Slow Roads は WebGL の全機能のごく一部を示す例に過ぎないことを理解してください。Three.js ショーケースをぜひご覧ください。特にウェブゲーム開発に興味をお持ちの方は、webgamedev.com のコミュニティにぜひご参加ください。