[Astro #56] データ駆動型シューティングへの進化 〜アイテムシステム・ライフ制・AIがもたらした殺意のステージ〜
はじめに
本日、3Dシューティングゲーム『PROJECT_LAIN / STG_PROTOCOL』に、ゲームとしての骨格と戦略性を全域にわたって組み込む大型アップデートを実装いたしました。
ステージ毎の障害物や敵の配置をすべてJSONで管理できるように修正し、ドロップアイテムの追加や、弾を発射する敵の作成など。
ただ、ステージ構成をAIに任せた所、3面以降鬼のような難易度になり、5面までクリアする事はできなったです。
もしプレイされる場合は、ストレスをためないようご注意ください。
1. 3Dアイテムシステムの実装とデータ駆動化
本作のゲームループに「リソース管理の戦略性」と「自機が成長する快感」を吹き込むため、Three.jsの幾何学メッシュ(Geometry)をフル活用したドロップアイテムシステムを構築しました。
ただパラメータの数値が変動するだけでなく、WebXRならではの空間認識を活かし、幾何学的なオブジェクトが暗闇の電脳空間からプレイヤーの目の前へと迫ってくる立体的な演出にこだわっています。敵撃破時のドロップ率を「10%」というシビアな確率に設定したことで、逃げ場のない弾幕の中でアイテムがドロップした瞬間の脳内麻薬(カタルシス)を極限まで引き上げました。
また、これらのアイテムパラメータはJSON設定ファイルから動的に読み込まれ、枯渇や処理落ちを防ぐオブジェクトプールによって軽量に管理される「データ駆動型」のアーキテクチャを採用しています。
各アイテムの役割と、こだわりのジオメトリ設計は以下の通りです。
🔴 パワーアップ
- メッシュ形状:
TorusGeometry(トーラス / ドーナツ型) - 機能と演出: 自機の主兵装である通常弾を最大3段階まで強化します。取得するごとに単発射撃から広範囲への同時発射(スプレッド)へと火力がインフレし、弾幕で空間を制圧する爽快感を味わえます。さらに、パワーレベルの上昇に伴って弾の光源が鮮やかなネオンカラーへと変容し、火力アップを視覚的に強くフィードバックします。
💖 ライフ回復
- メッシュ形状:
ExtrudeGeometry(押し出し成形による立体ハート型) - 機能と演出: 被弾して削られたダメージを即座に「30%」回復させます。即死制からライフ制へとゲームバランスを移行した本作において、プレイヤーの「精神的支柱」となる最重要アイテムです。単純なプリミティブ形状ではなく、ベジェ曲線で描画したパスに厚みとベベル(角の丸み)を持たせることで、冷徹な幾何学空間の中でひときわ目を引く有機的な立体感を与えています。
⚡ スピードアップ
- メッシュ形状:
OctahedronGeometry(正八面体) - 機能と演出: 自機のXYZ空間における移動速度が段階的に上昇します。鋭角でソリッドな正八面体を採用し、視覚的な「機敏さ」を表現しました。超高密度の敵弾とサイバーピラーが迫り来る後半の鬼畜ステージにおいて、ミリ単位の俊敏な回避(位置取り)を可能にするための重要なタクティカル要素となります。
⭐ スコアアップ
- メッシュ形状: 星型のカスタムジオメトリ
- 機能と演出:
取得した瞬間にボーナススコアが大きく加算されます。古き良きアーケードシューティングへのリスペクトを込めた形状であり、リザルト画面に刻まれる「
RECORDED SCORE」の限界突破を狙うスコアアタッカーにとって、リスクを冒してでも弾幕の隙間に飛び込むインセンティブとして機能します。
2. 敵キャラクターのバリエーション:射撃型(Shooter)の追加
これまでのステージは、迫り来るザコ敵の体当たりや隕石、固定障害物(ピラー/ゲート)といった「自機に向かって直進してくるオブジェクト」を捌くことがメインでした。しかし今回のアップデートで、新たに「プレイヤーに向けてエネルギー弾を発射する敵(Variant: shooter)」を実装しました。
敵のデータ構造(インターフェース)を拡張して variant プロパティを持たせることで、タイムライン(JSON)上で通常の敵と射撃型の敵を自由に混変調してスポーンさせることが可能になりました。
【実装における技術的な工夫】
- プレイヤーを正確に狙う射撃アルゴリズム
射撃型の敵は内部タイマー(
shootTimer)を持ち、2秒間隔で発砲します。その際、単純に弾を前方へ飛ばすのではなく、自機の現在座標(胸の高さ付近:playerPos.y + 1.0)に向けて正確な方向ベクトルを計算し、弾速50(ENEMY_BULLET_SPEED)で真っ直ぐにエネルギー弾を撃ち込んできます。 - 一瞬で脅威を判別させる「視覚的フィードバック」
超高スピードで展開されるVR空間では、敵の種類を瞬時に見分ける必要があります。そのため、通常の敵がマゼンタ(
#ff0055)であるのに対し、射撃型の個体は出現時に子メッシュのマテリアルカラーを動的にネオンパープル(#ff00ff)へと変更し、危険度を視覚的にアピールしています。 - 視認性の高い「赤い八面体」の敵弾
敵が発射する弾のメッシュには、自機の弾や他のオブジェクトと明確に区別がつくよう、警戒色である赤(
#ff0000)の正八面体(OctahedronGeometry)を採用しました。
このシューターの実装により、ただ空間の隙間を避けるだけでなく、「敵の射線(弾道)を予測して動く」「撃たれる前に優先して倒す」という、本格的な弾幕シューティング特有のヒリヒリとした緊張感が電脳空間に生まれました。
3. 即死バグの撲滅と「ライフゲージシステム」の確立
初期のプロトタイプ段階では、敵や弾に一瞬でも掠っただけで画面に SYSTEM_FAILURE の文字が表示され、即座にゲームオーバーとなってしまう非常に尖った仕様でした。この理不尽な衝突処理を根本からリファクタリングし、プレイヤーが戦略的にダメージをコントロールできる「ライフゲージシステム」を完全に確立しました。
これによって、一瞬のミスが即座に破滅に繋がる理不尽さが排除され、ゲームらしい「粘りの立ち回り」と緊張感の共存が可能になっています。
🔴 定数ダメージの導入と「多段ヒットバグ」の防止
従来のシステムでは、衝突判定が重なった数フレームの間にダメージがループ処理され、一瞬にしてライフが溶け去る「多段ヒット」が多発していました。この現象を解決するため、以下の二面からアプローチを行いました。
- オブジェクトごとの被弾ダメージ適正化
プレイヤーの最大HPを
100(PLAYER_MAX_HP)と定義し、衝突対象ごとに明確な定数ダメージを設定しました。ボスの放つ弾は1発につき15(約15%消費)、雑魚シューターの弾は5、隕石は25、固定ピラーは30と細かくマッピングし、耐久値の駆け引きをゲームデザインに組み込んでいます。 - フラグ制御による多重判定の遮断
useFrame内で毎フレーム実行されるエネミーバレットの衝突ループにおいて、自機への接触を検知した直後にeb.active = falseへとフラグを落とすだけでなく、判定の先頭にif (!eb.active) return;というガードクローズを徹底しました。これにより、同一フレーム内で同一のオブジェクトから2重、3重にapplyDamageが呼び出される構造を完全にシャットアウトしています。
🔴 電脳シールド(CYBER_SHIELD)との美しいシナジー
ライフゲージの導入に伴い、SHIFTキー(VRコントローラーではグリップボタン)で展開する「電脳シールド」の価値とリソース管理のジレンマが大幅に向上しました。
シールドを展開している間、シールドゲージは毎秒 20 の割合で激しく消費されていきますが、その代わりにあらゆる敵弾やオブジェクトのダメージを無効化し、無傷で弾き返すことができます。シールドを閉じれば毎秒 10 の速度で滑らかにエネルギーが自動回復していくため、生身で弾幕を避ける時間と、シールドで安全を確保する時間のメリハリが重要になります。
万が一、シールドを展開しすぎてゲージが 0 になると、システムがオーバーヒートを起こしてシールドが完全大破(isShieldBroken)するというペナルティも実装しました。一度大破すると、完全にボタンを離してシステムを冷却するまで再展開が一切不可能になります。
「生身で弾を避けるか」「シールドを張って耐えるか」「オーバーヒートのリスクをどう管理するか」という、アーケードゲームさながらの硬派で熱いゲームバランスが、このライフゲージとシールドの融合によって完成いたしました。
4. 動的ステージ遷移システム(1面〜5面)の構築
本作のゲーム体験を「単発のシューティング」から「完結した物語を体験する体験」へと昇華させるため、ステージ1から5までをシームレスにつなぐ動的なステージ遷移システムを実装しました。
これまでの固定配置型ステージとは異なり、各ステージのタイムラインデータを独立したJSONファイルとして管理し、ボス撃破というトリガーを起点にゲームの進行状況を切り替えるアーキテクチャへと刷新しています。
【実装のポイント:同期と再初期化】 ステージ遷移が発生する際、単にデータを入れ替えるだけではバグの原因となるため、以下の3つのプロセスを同期させることで、プレイヤーの没入感を損なわないスムーズな進行を実現しました。
- JSONファイルの動的インポートとステージ管理
stage1_timeline.jsonからstage5_timeline.jsonまでを個別のモジュールとしてインポートし、現在のステージ状態(currentStage)に基づき読み込むデータを切り替えるロジックを構築しました。これにより、ステージごとの難易度曲線(難易度曲線)を個別に調整・拡張できる柔軟性を確保しています。 - 進行管理タイマー(
elapsedTime.current)の完全な巻き戻し 各ステージはタイムライン上のtimeを基準に進行するため、遷移時には経過時間を保持するelapsedTime.currentを正確に0へとリセットしています。この「巻き戻し」と同時に、画面上に残存するエネミーや弾幕のオブジェクト(enemyBullets.current等)を強制的に消去・非表示化することで、ステージ間の「ゴミ」が次ステージへ持ち越される不具合を排除しました。 - ボス撃破イベントとの連動
UI層およびゲームマネージャー層でボスエネミーのHP監視を行い、
bossHp <= 0となった瞬間にクリア判定イベントを発火させています。このイベントが走ると、BGMのループ切り替え処理が走り、次ステージのタイムラインデータが流し込まれることで、プレイヤーを休む間もなく次の「殺意のレイヤー」へと誘う仕組みです。
この遷移システムの実装により、プレイヤーは1面をクリアした興奮冷めやらぬまま、即座に2面、3面……と、より高密度な電脳空間へと引きずり込まれる、息もつかせぬ連続的なゲーム体験が可能になりました。
5. クロード(AI)による「数学的殺意」のステージデータ作成
タイムライン駆動化のテストベンチとして、AI(Claude)にステージ3〜5の敵配置JSONの作成を依頼しました。その結果、人間の限界に挑むような「鬼畜難易度」のタイムラインが生成されました。
-
高密度オブジェクト迷路
-
開始数秒、あるいは0.3秒刻みでシューター6体と隕石5発が同時に視界を埋め尽くし、サイバーピラーが左右を阻む、手加減を一切知らない超高密度弾幕。
-
この仕様が生んだ「もう一回」の魔力
-
しかし、ランダム生成ではなく「固定タイムライン」だからこそ、プレイヤーは何度も死に物狂いでリトライ(死にゲー化)し、「ここでシールドを展開し、直後にチャージショットで一掃する」という職人技のようなパターン攻略を編み出すカタルシスが誕生しました。
6. ボスエネミーの簡易弾幕アルゴリズム実装
各ステージの最深部で待ち受ける大物の挙動として、簡易的な「ボス射撃ロジック」を実装しました。 時間経過やボスのHP残量(フェーズ)に応じて、手前に向かって弾が高速連射される仕組みです。特に後半ステージでは、ボスの物理的な巨大化(スケールインフレ)と相まって、画面全体をオレンジ色の八面体弾が埋め尽くすド迫力の最終決戦が展開されます。