マガジン

AI生成コードのどこを読めばよい?ゲームの入力・状態・描画を追う

遊びをつくる

執筆にClaudeを使用しています。

三つの透明な箱に並ぶ入力キー、球の動く仕組み、小さなゲームの舞台を赤い糸でつないだ模型。
記事のテーマをもとに制作したAI生成の写真風イメージ。

AIに「ブロックを動かすゲームを書いて」と頼むと、すぐに100行超のコードが返ってきます。動かしてみると確かに動く。でも「なぜ動くのか」「どこを変えれば挙動が変わるのか」がわからないと、次の指示が出せません。このとき、コードを頭から全行読む必要はありません。ゲームのコードには必ず「入力・状態・描画」という三つの責務があり、そこを順に追えば全体像をつかめます。この記事ではその読み方の手順を、短いコード例とあわせて説明します。

この記事の目次
  1. なぜ「三つの責務」で読むのか
  2. まず「入力」を探す:イベントリスナーとキーフラグ
  3. 次に「状態」を探す:どの変数が変化を保持しているか
  4. 最後に「描画」を探す:状態を画面へ写す処理
  5. AIコードを渡されたときの読み手順:5ステップ
  6. AI生成コードでよくある読みにくいパターンと対処
  7. 小さなサンプルで実際に追ってみる

なぜ「三つの責務」で読むのか

どんなゲームも、フレームごとに同じ流れを繰り返しています。まずプレイヤーの操作(キー・タッチ・クリック)を受け取り、それをもとにゲームの内部状態(位置・スコア・生存フラグなど)を更新し、最後に画面へ描き出す。この三段階が「入力 → 状態 → 描画」です。

AIが生成するコードもこの流れから外れません。関数名や書き方がAIごとに違っていても、どこかに入力を受け取る処理、状態を変える処理、キャンバスやDOMへ書き出す処理が必ずあります。三つを見つけられれば、残りの補助的なコードは後回しにできます。

以下のコード例は説明用の簡略サンプルです。実際にAIが生成するコードは構造がより複雑になることがあります。動作を保証するものではなく、読み方の手がかりとして参照してください。

まず「入力」を探す:イベントリスナーとキーフラグ

コードを開いたら最初にaddEventListenerを検索します。キーボード操作なら「keydown」「keyup」、タッチ操作なら「touchstart」「touchend」、マウスなら「mousedown」「click」などのイベント名が引っかかります。ここがゲームへの入口です。

入力を受け取った後、コードがすぐに状態を変える場合と、いったんフラグ(真偽値)へ記録してから後でまとめて処理する場合があります。後者はゲームループと組み合わせて使われることが多く、次の例のような形です。

javascript
// 入力フラグを記録する例(説明用)
const keys = {};
document.addEventListener('keydown', e => { keys[e.key] = true; });
document.addEventListener('keyup',  e => { keys[e.key] = false; });

この場合、`keys` というオブジェクトが入力の窓口です。「ArrowLeft」「ArrowRight」など実際のキー名が使われているか、スペースキーなら「' '」(スペース文字)になっているかを確認します。AIが生成したコードで操作キーを変えたいときは、このオブジェクトを参照している箇所を探せばよいとわかります。

次に「状態」を探す:どの変数が変化を保持しているか

状態とは「ゲームが今どこにあるか」を表す変数群です。位置(x, y)、速度(vx, vy)、スコア、残機、ゲームオーバーフラグなどが典型例です。これらはlet または const でまとめて宣言されていることが多く、ファイルの先頭付近か、ゲームを初期化する関数内に固まっています。

javascript
// 状態変数の例(説明用)
let playerX = 100;
let playerY = 200;
let score   = 0;
let alive   = true;

状態変数を見つけたら、それを書き換えている箇所を検索します。たとえば `playerX =` や `playerX +=` で検索すると、どのタイミング・どんな条件でプレイヤーが動くかが見えます。AIが「壁に当たってもすり抜ける」バグを出した場合、衝突判定の条件式はたいてい状態変数を変更する直前に書かれています。

状態をまとめてオブジェクト化しているコードもあります。その場合は `player.x` のようなドット記法で参照されるので、`player` というオブジェクトを起点に追います。

javascript
// オブジェクトにまとめた状態の例(説明用)
const player = { x: 100, y: 200, speed: 3 };

function update() {
  if (keys['ArrowRight']) player.x += player.speed;
  if (keys['ArrowLeft'])  player.x -= player.speed;
}

この `update` 関数が「入力フラグを読んで状態を更新する」役割を持っています。入力と状態の橋渡し役として、このような関数がゲームの中心になります。

最後に「描画」を探す:状態を画面へ写す処理

描画処理は `canvas` の `getContext('2d')` 経由で行われるか、DOM要素のスタイルや位置を書き換えることで行われます。Canvas を使っている場合は `ctx.fillRect`・`ctx.drawImage`・`ctx.clearRect` などが目印です。DOM操作なら `element.style.left` や `element.textContent =` が状態変数と連動しています。

javascript
// Canvas描画の例(説明用)
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = '#4a90d9';
  ctx.fillRect(player.x, player.y, 32, 32); // 状態変数を使って描く
}

描画関数の中で状態変数がどのように使われているかを見ると、「player.x が増えると四角が右へ動く」という対応関係が一目でわかります。色を変えたければ `fillStyle` の値を、大きさを変えたければ `fillRect` の第3・第4引数を書き換えればよいとわかります。

描画処理はたいてい `requestAnimationFrame` で繰り返し呼ばれます。この呼び出し構造がゲームループです。

javascript
// ゲームループの骨格(説明用)
function loop() {
  update(); // 状態を更新
  draw();   // 状態を描画
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

`requestAnimationFrame` を検索すると、このループの入口が見つかります。ループが見つかれば、そこから `update` と `draw` の両方へたどれます。コード全体を読まなくても、三つの責務がどこにあるかを特定できます。

AIコードを渡されたときの読み手順:5ステップ

以上をまとめると、AIが生成したゲームコードを読むときの手順は次のようになります。

  1. addEventListener を検索する:どのイベント(keydown / touchstart / click)を受け取っているか確認する。入力フラグ変数があればその名前を控える。
  2. 状態変数を探す:ファイル先頭かinitialize関数付近の let / const 宣言をざっと見て、位置・スコア・フラグなど変化しそうな変数をリストアップする。
  3. 状態変数の書き換え箇所を探す:「変数名 =」で検索し、どの関数・どの条件下で値が変わるかを確認する。
  4. requestAnimationFrame を検索する:ゲームループを特定し、ループ内で呼ばれている関数名(update / draw など)を把握する。
  5. 描画関数で状態変数を確認する:drawやrenderと名のつく関数を開き、どの状態変数が座標・色・テキストに使われているかを確認する。

この5ステップを終えると、コードの全行を読んでいなくても「どこを変えれば何が変わるか」の地図ができます。次にAIへ指示を出すときは、この地図をもとに「update関数内の衝突判定を変えてほしい」「player.speed の初期値を上げたい」と具体的に伝えられます。

AI生成コードでよくある読みにくいパターンと対処

AIが生成するコードにはいくつかのパターンがあり、読み慣れていないと三つの責務が見えにくいことがあります。よくあるケースと対処を整理します。

すべてが一つの関数に書かれている

短いサンプルコードでは入力・状態更新・描画が一つの `loop` 関数に混在することがあります。この場合は関数内をスクロールしながら「イベント確認 → 変数書き換え → ctx.fillRect / drawImage」の順番を探します。順番は必ずこの流れになっているはずです。

クラス構文で書かれている

ES6クラスを使ったコードでは `class Game { constructor() {...} update() {...} draw() {...} }` のように責務がメソッドで分かれています。`class` キーワードで検索し、メソッド一覧を確認すると全体像が見えます。状態変数は `this.` で参照されるので、`this.` を手がかりに探します。

変数名が省略されていて意味が読み取りにくい

AIがコードを短くまとめようとした場合、`p` や `s` のような一文字変数が使われることがあります。こうした変数はその初期値や使われ方から意味を推測します。わかりにくければAIに「変数名をわかりやすいものにリネームして」と依頼すると、コードを再生成してもらえます。

また、AIに「このコードの入力・状態・描画の担当箇所をコメントで注記して」と指示するのも有効な方法です。AIが自ら構造を説明するコメントを加えてくれると、次の読み直しが格段に楽になります。

小さなサンプルで実際に追ってみる

読み方の手順を身につける一番の近道は、短いコードで実際に追ってみることです。アソバースのSDKページには小さな連携サンプルが置かれており、コードと画面の動きを同時に確認できます。上記の5ステップを手元のメモに書きながら、サンプルのaddEventListener → 状態変数 → requestAnimationFrame → 描画関数の順に追ってみてください。

一度この流れを自分の手で確認できると、AIが新しいコードを生成するたびに最初から全部読む必要がなくなります。「このコードの状態変数は何か」「update関数はどこか」という問いを持ってコードを開けば、数十行の検索と確認で全体像がつかめるようになります。

AIとの制作では、コードを読む目的が「完全な理解」ではなく「変えたい箇所への道案内」であることが多いです。三つの責務を起点にした読み方は、その目的に合った最小限の地図を与えてくれます。

出典・参考資料