CodexでUnityシューティングを改善:仕様・画面・テストの切り分け

AIにゲーム制作を任せたあと、何を確かめて直すか。Unityのシューティングで起きた23.93秒での敗北、HUDに隠れるボス、不要な予告を例に、ルール・自動操作・描画の検査を分けた記録。実行できるC#サンプル付き。

Libra

公開 2026年9月20日 ・ 更新 2026年10月24日

この記事の要点5項目

ルール・自動操作・描画を別々に確かめる。 敵弾を吸収して返すゲームを例に、失敗した層を切り分けた。ルールを動かせるC#サンプルを掲載。

残り4つの要点を読む
  • 自動操縦は最初、標準の敵配置で23.93秒で敗北。 回避の判断を直し、ブラウザでボス撃破まで確かめた。
  • テストが通っても、ボスが表示に隠れる問題や不要な攻撃予告は残っていた。 画面とルールを別々に検査した。
  • ムレウチとは仕様も制作順も違う。 今回の成果物の差だけで、AI全体の優劣は決められない。
  • v1.6では3区間の役割を分離。 編隊から予告狙撃、左右の交差弾道へ進む。

この記事の対象と、書いている範囲

Codex に Unity のゲームを作らせたい人に向けた、制作と検証の記録です。設計の判断・つまずき・確かめ方を残しています。 吸収反撃のルールは、下の「C#サンプルを動かす」で試せます。完成した画面全体の写経教材ではありません。環境づくりから公開までの順番はAIでUnityゲームを作る流れにまとめています。

Claude Codeに4本のゲームを作ってもらったあと、5本目をCodexに頼みました。できたのが、敵弾を吸収して撃ち返す縦シューティング、リフレアです。

依頼どおりに動くこと、画面で状況が分かること、遊びたくなることは、別の確認でした。この記事では、吸収反撃のルール、自動操作の失敗、画面の不具合を分け、どの問題に何を変えたかを残します。題材の公開は終了しましたが、実測・画像・C#サンプルは引き続き参照できます。ここにある検証結果だけで、面白さや完成品の品質を保証するものではありません。

予告線と着弾予定の輪が示された第2区間
v1.6の第2区間。狙撃の予告線が出てから弾が来る。
左右の敵から予告線と弾道が交差する第3区間
v1.6の第3区間。左右の予告を読み、回避か吸収を選ぶ。

最初に渡したのは「同じジャンルで、別ゲームを」という依頼

依頼の中心は、この一文でした。

別ゲームでいいからCodexが考えるシューティングゲームを作って欲しい

参考としてムレウチのページを渡し、成果物を比べたいと伝えました。吸収やボスを作るようには指定していません。そこはCodexが考えています。

一方、開発環境、テストの回し方、公開用スクリプト、制作ログを残す約束は、先にClaude Codeと整えていたものです。「白紙からCodexだけで全部用意した」わけではありません。

引き継いだもの

Unityの環境設定とCLIの使い方
テスト・公開・容量計測の道具
見た目と手応えの合格条件、制作記録の書式

今回Codexが作ったもの

敵弾を吸収して貫通弾で返すルール
90秒の進行と、二段階のボス戦
機体・背景・演出と、自動操縦による通し検証

同じ仕様書で作ったブロック崩しの比較とは条件が違います。今回は、題材を任せたときに何を作るかを見る試みです。後から作る側は、それまでの失敗と道具も利用できます。

シューティングの仕様を、実装とテストへ分ける

依頼文だけでは、いつ完成なのか決まりません。今回は、Codexが仕様書を先に作り、遊びのルールと確認方法を対にして進めました。元の仕様書から、次の制作にも使える部分を抜き出すとこうなります。

作るもの実装する条件確かめ方
操作PCはWASD・矢印で移動、Spaceで吸収。通常射撃は自動開始後に移動・吸収・停止・再開を実際に操作する
吸収反撃0.65秒だけ敵弾を吸収し、発動から4秒は再使用できない吸収成功、空振り、押し続け、敵本体への接触を別々に試す
終了条件60秒でボス、90秒で時間切れ。ライフは3ボス出現・撃破・ライフ切れ・時間切れをそれぞれ検査する
見た目機体の輪郭、雲と施設の速度差、吸収リング、撃破の反応通常戦とボス戦を撮り、HUDで隠れていないか確認する
公開WebGLで開始から再挑戦まで動くテストの件数に加え、公開URLで通しプレイする

ルール本体は Core/Battle.cs、自動操縦は Core/Pilot.cs に分けました。Runtime/Flight.cs が入力とUI、Runtime/FlightArt.cs が絵を担当します。v1.3では、画面の入力を固定ステップへ渡す処理をCore/FlightClock.csへ切り出しました。ルールがUnityの画面に依存しないので、弾を置いて1回進めるだけの検査ができます。

  1. 1

    最小の戦闘を作る

    移動・射撃・被弾・吸収を実装し、ルールのテストで確かめる。
  2. 2

    画面と進行を合わせる

    背景・機体・反応を付け、編隊からボス戦まで進める。
  3. 3

    入力と表示を確かめる

    キーとタッチの入力、HUD、ボスの位置をブラウザで見る。
  4. 4

    ビルドして公開する

    容量と起動時間を記録し、公開URLでも最後まで遊ばせる。

環境をまだ用意していなければCodexからUnityを操作する準備、実行コマンドはUnity CLIのテスト・ビルド手順、配信設定はWebGLゲームの自前公開に分けてあります。

敵弾を「避けるもの」と「取りに行くもの」にした

リフレアの通常射撃は自動です。プレイヤーが考えるのは移動と、吸収を使うタイミング。敵弾が来たら避けるだけでなく、近づいて取り込む選択があります。

  1. 手順 01

    吸収を押す

    スペースキーか画面下の「吸収」

  2. 手順 02

    0.65秒だけ取る

    リングに触れた敵弾を吸収

  3. 手順 03

    貫通弾で返す

    吸収終了時に最大12発

  4. 手順 04

    再使用を待つ

    発動から4秒後に使える

吸収を空振りすると反撃は出ない。敵本体への接触も防げない。

ここには小さな損得があります。早く押すと、弾が届く前に吸収が終わる。待ちすぎると被弾する。使った直後には次の弾を吸収できません。敵本体への接触は防げないので、吸収中ならどこへでも突っ込める、というルールにもしていません。

実装の数値は次のとおりです。記事を読んだ人が、遊びのどの部分を調整したのか追えるように残します。

項目実装した値遊びへの影響
吸収の有効時間0.65秒押すタイミングを選ぶ
再使用発動から4秒連打で守り続けることはできない
反撃吸収数+2発、上限12発多く取ると返す弾が増える
反撃1発のダメージ4(通常弾は1)ボスへの攻撃にも使える
ライフと被弾後の無敵3、1.2秒一度の重なりで全部失わない
ボス60秒に出現、90秒で時間切れ後半は倒し切る必要がある

反撃には、同じ敵へ当たり続けて毎フレーム4ダメージを入れないための管理もあります。貫通弾ごとに「すでに当たった敵の枠」を記録し、次の敵へ進ませる作りです。2体を貫通して倒せることをテストしています。今回は敵の配列が64枠なので、ヒット済みの印は64ビットで持たせています。

20秒ごとに敵を増やすだけだった区間を作り直した

公開後に通常戦の3区間を調べると、v1.5では直進・左右移動・狙撃の3種類が最初から出ていました。20秒と40秒で主に変わるのは敵の出現間隔です。そこでv1.6は、区間ごとに読むものを変えました。

ゲーム内の時間追加した判断画面で伝える方法
0〜20秒編隊を見て射撃位置を取る直進と左右移動の敵だけを出す
20〜40秒狙われた場所から離れるか、吸収して返すか約0.67秒の照準線と着弾予定の輪
40〜60秒左右から交差する弾道をどう抜けるか約0.83秒の予告、二方向の敵と3発の幅ある射撃

最初の案は、予告を付けた代わりに弾が減り、適応する自動操縦の勝利が旧版35/100から98/100へ増えました。区間名を変えただけでは、遊びの作り込みにならないと分かったため、その案は採用していません。予告から着弾までの余裕を残しながら、弾の幅と第3区間の再攻撃を調整しました。

同じゲーム本体のC#を使い、seed1〜100を各方針で再実行した最終候補は、周囲を見て動き吸収時を選ぶ自動操縦が77/100勝、同じ動きで吸収しない場合は10/100勝、使えるたび即吸収する場合は33/100勝でした。中央に留まる・8秒周期で往復する方針は各0/100勝。旧版の対応する3方針は35/100、20/100、21/100です。適応操縦の総勝率は上がったので、全体を単純に「難しくした」とは言えません。予告を読んで動くことと、吸収の時期で結果が変わるかを比較した数字です。人の初見クリア率はまだ測っていません。

C#サンプルを動かす:吸収から反撃まで

説明だけでは挙動を追いにくかったので、v1.6公開版のルール本体と自動操縦を取り出しました。v1.3で追加した入力の固定ステップ処理も同梱しています。Unityの画面を起動せずに、吸収、3区間の攻撃、ボス撃破、入力頻度と移動距離を確かめる小さなコンソール用サンプルです。

リフレアのC#サンプルをダウンロード(ZIP)

必要なのは .NET 10 SDK。今回の実行確認はWindows、SDK 10.0.401です。ZIPを展開し、ReflearSample.csproj があるフォルダで実行します。Unityに付属する環境だけで、このコマンドが使えるとは限りません。

dotnet --list-sdks
dotnet run --project ReflearSample.csproj

dotnet が見つからない場合は.NET SDKの導入が必要です。プロジェクトが見つからない場合は、ZIPを展開したフォルダへ移動できているか確認します。サンプルには追加のNuGetパッケージはありません。

中の Program.cs は、たとえば次の順で吸収を試しています。これは同梱した Battle.cs を使う抜粋で、これだけを空のUnityシーンへ貼るコードではありません。

var game = new Reflear.Core.Battle();
game.Start();

// 自機と同じ場所に、速度0の敵弾を1発置く。
Reflear.Core.Battle.Spawn(game.Bullets, 0, -5, 0, 0, 1, 0);
game.Tick(new Reflear.Core.Command { X = 0, Y = -5, Absorb = true });
// 期待値: Lives=3、Score=25、Stored=1

for (int i = 0; i < 40; i++)
    game.Tick(new Reflear.Core.Command { X = 0, Y = -5 });
// 期待値: Shield=0、Bursts=1、Cooldownはまだ0より大きい

Tick 1回が1/60秒です。Command.X/Y は移動速度ではなく、移動先の座標。サンプルは実時間を待たずにルールを進めます。1秒に何回描画できるかを測るコードではありません。

配布サンプルを実行した結果(末尾)成功
PASS: same seed and inputs produce the same snapshot
PASS: standard mission: won score=19025 lives=2 absorbed=37
14 checks passed. No graphics or browser performance measured.

吸収の得点、反撃、再使用の制限、空振り、接触、3区間の攻撃、入力の再現性、標準配置の通しプレイに加え、30・60・120・144Hzの入力頻度での移動を検査します。計14項目で、失敗したら例外で終了します。数値を変えて失敗した場合は、狙った変更なのか、別のルールまで壊したのかを確認します。

このサンプルに含まれないもの

画面・音・UI・入力デバイスの読取は含めていません。Unityへ持ち込む場合は Battle.cs・Pilot.cs・FlightClock.cs を使い、入力座標の変換と描画をつなぎます。固定ステップはFlightClock.Advanceに任せます。Program.cs はコンソール用です。今回の14項目はサンプルの検査で、v1.6のUnityテスト38件とは別に数えています。

素材を増やす前に、輪郭と奥行きを作った

見た目は、画像素材を集めて組み合わせたものではありません。機体も雲もコードでテクスチャを生成しています。ただし、四角や丸をそのまま並べているわけでもありません。

自機には細い胴体、左右の翼、尾の部分があります。ピクセルを塗る際に上側を明るくし、輪郭にも明るい縁を付けています。その上に白い操縦席と青緑のエンジン光を重ねています。

輪郭

何なのかを伝える

機体の翼・尾・敵の違う形

光

反応を伝える

エンジン・弾・吸収・撃破

速度差

奥行きを伝える

遅い雲と速い施設

背景の雲はゆっくり、施設の影は速く流れます。背景そのものに明るさの差があり、その前を自機が進む。敵を倒したときは破片が広がり、被弾時には自機と画面が反応します。効果音もコードで生成しています。

「素材なし」は見た目を省く条件にはしませんでした。輪郭、陰影、光、背景の速度差を別々に用意したことが、今回の画面の具体的な構成です。どの要素が私の印象に何割効いたかまでは測っていません。

自動で遊ばせたら、最初は24秒で負けた

ゲームのルールはUnityの描画から分離し、1回の更新を1/60秒に固定しています。自動操縦もプレイヤーと同じ移動・吸収の入力を渡します。無敵にしたり、敵を消したりしてボスまで進めているわけではありません。

ところが、最初の自動操縦は途中で負けました。敵配置を決める乱数の種を3種類に変えても、全部ボス登場前に終了しています。

敵配置の種初版の生存時間結果
147.90秒敗北
19(標準)23.93秒敗北
98747.27秒敗北
01

少し先の一点だけ見ても、弾を避け切れなかった

症状
標準配置では23.93秒で敗北。ボスまで検証できない。
原因
初版の自動操縦は、0.25秒先の危険だけを評価し、移動も左右に限っていた。
対処
0.15・0.30・0.45・0.60秒先を評価し、上下移動も候補に追加。複数の時点で危険が少ない方向を選ぶようにした。

この変更後、標準配置では87.23秒でボス撃破まで進みました。ここで直したのは自動操縦の判断です。人が遊ぶゲームの難しさを下げて通した記録ではありません。

ただ、自動操縦は内部の座標を正確に読めます。ボスを倒せたからといって、初めて遊ぶ人が簡単にクリアできるとは言えません。使い道は、毎回同じ条件で最後まで進め、途中の破綻や変更による差を見つけることです。

数字が通っても、ボスが隠れていた

ブラウザの65秒時点の画面を確認すると、ボスが上部の情報表示、HUDに隠れていました。ルールのテストでは勝てる。けれど、肝心の敵が全部見えていない。

02

ボスの位置を下げたら、クリア時間まで変わった

症状
ボス上部がHUDに重なって見えない。
原因
ボスの中心をゲーム内のY座標5に置いていた。描画サイズとHUDの占有範囲を、通し画面で確認できていなかった。
対処
中心をY=3.2へ下げた。自動テストだけで済ませず、PC幅とスマホ幅で最後まで再検証した。
標準配置・同じ自動操縦修正前修正後
ボス撃破まで87.23秒79.73秒
残りライフ12
スコア22,525点23,550点
吸収した敵弾37発38発

位置を下げると、自機の弾も敵の弾も到達するまでの時間が変わります。見た目を直すつもりでも、戦闘の条件が変わっていました。このため、位置変更後にもう一度通しで遊ばせています。画面の修正でも、結果は測り直す必要がありました。

公開後に、予告の嘘と状態の読みにくさを直した

最初の公開ページには遊び方と数字を載せましたが、制作過程の説明が足りませんでした。私は「薄くね? 内容」と伝え、記事を書く前に改善点も見直すよう依頼しました。

この見直しで見つかったのが、ボスの照準線です。狙撃弾は2回に1回なのに、予告は毎回出ていました。実際には来ない攻撃を避けさせる表示です。

修正前:予告を検査するテストの実際の出力エラー
The first volley has only fan bullets
Expected: 0
But was:  0.650000036f

修正は、予告を出す条件に「次の攻撃に狙撃を含む」を足すこと。テストも、最初の扇弾のみの回には予告が出ず、次の狙撃回には予告が出て3本の弾が発射される、というところまで確認します。

v1.1で変えた箇所変更後
照準線狙撃する回だけ予告する
ボス耐久HPの数字に加えてゲージを表示。後半は色も変わる
吸収ボタン吸収中と充電中で色を変え、残り時間をゲージで示す

敵の数や吸収の性能は、この改善では変えていません。必要な情報を信頼できる表示にする修正です。

初版のボス戦。耐久は上部のHPの数字で表示
初版v1。耐久も再使用時間も文字で読む。
改善後のボス戦。HUDの耐久バーと吸収ボタン下のゲージ
v1.1。上部に耐久バー、下部に吸収の時間ゲージ。どちらも同じ自動操縦の65秒付近を撮影。

あわせて、最後の被弾とボスへの攻撃が同じ更新で重なる条件も検査しました。これは修正前から正しく敗北になっていました。「バグを直した件数」に混ぜず、今後その挙動を守るテストとして残しています。

PCで重く感じたので、fpsと操作応答を分けて測った

公開後、私は「PCで少し重い」と伝えました。まずChromeで通しプレイを測りましたが、継続的な処理落ちは再現できませんでした。HUDの更新を減らす試作も、ゲーム全体の高速化を示す結果にはなっていません。

一方、コードでは入力とゲームの更新より先に、機体の描画位置を決めていました。これをLateUpdateへ移し、同じフレームの入力後の座標を描くようにしました。採用前に、キーイベントの受信から、WebGL上の自機の画素が動くまでを比較しています。

入力イベントから描画画素が変わるまで
  • ① v1.133.10ms

    フレーム数の中央値:2

  • ② 改善版16.35ms

    フレーム数の中央値:1

  • ③ 改善版16.60ms

    フレーム数の中央値:1

  • ④ v1.132.25ms

    フレーム数の中央値:2

各16入力の中央値。番号は測定順。短いほど、この測定条件での描画応答が早い。

測定はWindowsのChrome、描画領域506×900、DPR 1。旧版→改善版→改善版→旧版の順で新しいブラウザコンテキストを開き、開始直後に左右の入力を交互に送りました。青緑の自機の画素の重心が、入力した方向に2px以上動いた時点を検出します。旧版の32入力は全て2フレーム、改善版は31入力が1フレーム、1入力が2フレームでした。

何の遅延を測った数字か

ブラウザ内のキーイベント受信から、描画済み画素の読取までです。キーボードの機械的な遅延やモニターへの表示時間は含みません。画素の読取自体にも負荷がかかります。操作に対する描画の遅れが減った根拠として採用し、「ゲーム全体が2倍速い」「重さを完全に解消した」とは扱っていません。

この変更とHUDの不要な文字列更新の削減をv1.2に採用しました。同じコードでEditMode 22件・PlayMode 3件が合格しています。この時点では、私が感じた引っかかりとの対応は未確認。平均fpsだけでは、操作応答の問題を見落とすと分かりました。

120Hzの入力で移動が半分になる不具合も見つかった

追加調査では、キーボード移動にも問題が見つかりました。画面が更新されるたびに移動量を計算し、その後にゲーム内部を1/60秒ずつ進めていました。内部を進めない画面フレームでは、その回の移動量が捨てられていたのです。

旧版の計算を切り出して、0.5秒間ずっと右キーを押す条件を再現しました。入力を120Hzで渡すと、ゲーム内時間は0.5秒進んでいるのに、移動は本来の半分。一定の60Hzだけを確認しても見つからない問題でした。

120Hzで0.5秒分の右入力を渡した結果
  • 旧計算1.75

    ゲーム内の距離。設定速度からの期待値は3.50。

  • 修正後3.50

    各1/60秒の更新で、方向×1/60×速度7を加算。

入力頻度を制御したC#の再現テスト。120Hzの実機モニターでプレイした測定ではありません。

修正では、画面から受け取る情報を「移動方向」と「ポインターの目標座標」に分け、FlightClockがゲーム内部の更新ごとに移動量を加算します。短いフレームで吸収ボタンを押しても次の更新まで保持し、再挑戦ではその保留を消します。

30・60・120・144Hz、不規則な間隔、長いフレームをテストに追加しました。ポインター操作と自動操縦の結果も含め、v1.3はEditMode 31件・PlayMode 3件が合格。実ブラウザでもキー保持を6回測り、移動量は期待値の約98〜103%でした。PC・スマホ幅ともボス撃破と再挑戦、キー・タッチ操作を確認して公開しています。上の配布サンプルにも、4種類の入力頻度を検査するコードを追加しました。

ただし、通常の60HzのChromeでは旧版も期待する移動量の約98〜103%でした。すべてのPCで移動速度が倍になる修正ではありません。負荷調査でも通常条件の引っかかりは実行ごとに変動しており、今回見つけた不具合だけで、私が感じた重さを全部説明できたとは考えていません。

WebGLのボタンは「押せるか」を画面でも伝える

v1.4では出撃・吸収・停止・音のボタンが似た色で、PCのWebGL画面にマウスを重ねても手形になりませんでした。吸収の再充填中もボタンに見えます。内部のルールは押下を無視しますが、プレイヤーにはその状態が伝わりません。

v1.5では、主操作と補助操作の色を分け、ホバー・押下・キーボードの焦点に輪郭を付けました。再充填中や一時停止中は操作を無効表示にします。Unity公式のUSSプロパティの説明では、cursorはランタイムUIで機能しないとされています。そのためUI Toolkitのポインター進入・退出を受け、WebGL側のcanvasのカーソルを切り替えています。

ここでもUnityのテストだけでは足りませんでした。最初のビルドはクリックと手形が動いたものの、押している間の色はホバー時から変わらないことが、ブラウザ画像の同じ画素を比較して分かりました。押下表示はInput Systemのボタン保持状態に合わせて更新し、離す場所によるクリック成立はUI ToolkitのButtonに任せました。PC幅と375px幅で、ボタンの外で離すと出撃しないこと、再充填中は手形にならないこと、一時停止で時間が進まないことを確認しています。幅375pxの検査はChromeのエミュレーションで、スマホ実機の操作感は未評価です。

どこまで確かめたか(確認の手順)と、まだ分からないこと

初版の公開環境では、次の値を記録しました。ロード時間は3回測り、中央値を使っています。ダウンロード完了から起動までの時間と、ページを開いてからの総時間は分けました。

初版v1の実測(2026-09-19)結果
Buildの4ファイル合計6,988,252バイト
WebGLビルド時間163.715秒
受信完了から起動までの中央値439.6ms
ページ遷移から起動までの中央値1,269.8ms
10秒間のfps・3回の中央値60.07

測定環境はWindowsのChrome、画面960×720、描画領域383×682、DPR 1です。約60fpsはこの環境の値で、低性能なスマホでの余裕を示す数字ではありません。最新ビルドの容量と検証記録はゲーム紹介ページにも掲載しています。

v1.1の自動テストはEditMode 22件、PlayMode 2件が合格しました。予告の検査を追加した直後はEditModeが21/22件で、修正して22/22件になった、という順序です。既存のテストが全部通っていたことだけでは、この問題は見つかりませんでした。

スマホ幅の確認はChromeのタッチエミュレーションです。実機での指の隠れ方、発熱、長く遊んだときの疲れは未評価。難易度も、初見の人を複数集めたテストはしていません。自動操縦のクリア記録と、人が感じる遊びやすさは分けて扱います。

私は今回の出来を見て驚きました。でも、次に引き継ぐなら「Codexの方がすごい」という一行より、何を選ばせるゲームにするか、何を画面で伝えるか、最後までどう確かめるかを残したい。リフレアでは、吸収する瞬間、遠景と機体の描き分け、ボス撃破までの通し検証が、その具体例になりました。

よくある質問

よくある質問

Codexには何を指示しましたか?

Claude Code作のムレウチを参考に、Codex自身が考える別のシューティングを作ってほしいと依頼しました。既存の制作手順と合格条件も引き継いでいます。吸収反撃やボスの具体的なルールはCodexが設計しました。

画像や音の素材はどう用意しましたか?

機体や雲のテクスチャをコードで生成し、光・破片・背景の速度差を組み合わせました。効果音も波形を計算して生成しています。外部の画像素材や画像生成APIは使っていません。

自動テストが通ればゲームは完成ですか?

今回の初版はテストが通っても、ブラウザではボスがHUDに隠れていました。さらに公開後の見直しで、狙撃しない回にも予告が出る問題を確認しました。ルールのテストと画面の検査は両方必要でした。

スマホでも確認しましたか?

Chromeのスマホ幅とタッチエミュレーションで、移動・吸収・一時停止・再挑戦を確認しました。スマホ実機での操作感、発熱、性能はまだ評価していません。

この記事は役に立ちましたか?

関連記事