ChatGPT 自動プログラミング実験: 「弾幕? シューティングゲーム」を作らせてみた!
自分が今まで理系の学問系中心に、内容を深く理解するためのシミュレータープログラムを作成してきました。このシミュレーター、簡単なものなら結構短いプログラムで書けてしまうこともあります。
「それなら、ChatGPTに全てプログラムを書かせるのも有り?」とふと思いました。ということで、様々なブラウザで動くようなシミュレーターやゲームをChatGPTに作成させる実験をしていきたいと思っています!
目次
今回のお題: 弾幕シューティングゲーム
今回は弾幕シューティングゲームをChatGPTに作らせてみました。シューティングは昔からある単純なルールに従うようなゲームなので、つくりやすいはず、、、!
失敗例: 初期命令
ChatGPTへの命令
↓のような命令で指示をしたのですが何回か失敗しました。
正直、他のゲームを作ってるときも感じましたが「初期に良いAI/イメージに近い作品を引かないと、その後の修正が大変」です。全く自分と違うイメージのものだと、そこから自分のイメージに寄せるのは至難のわざ。
それゆえに「初回出力を見て、自分のイメージに合ったものが出るまでリセットしてAIガチャを回す」はかなり重要なテクニックだと感じています。
ChatGPT 初回命令
ChatGPTへの命令
それでは改めて。まずは↓の命令で風景を描画させてみました。命令は↑と同じですが、全く違う出力になります。
コード
生成されたプログラムが↓です。
<!DOCTYPE html> <html> <head> <title>弾幕シューティングゲーム</title> </head> <body> <canvas id="gameCanvas" width="640" height="480"></canvas> <script> // ゲームキャンバスの取得 var canvas = document.getElementById("gameCanvas"); var ctx = canvas.getContext("2d"); // ゲームエリアの設定 var gameArea = { x: 0, y: 0, width: canvas.width, height: canvas.height }; // プレイヤーの設定 var player = { x: gameArea.width / 2, y: gameArea.height - 50, speed: 5, color: "#0000ff", radius: 10 }; // 弾の設定 var bullets = []; // 敵の設定 var enemies = []; // キーの設定 var keys = {}; // キーの状態を更新する関数 function updateKeys(event) { keys[event.keyCode] = event.type == "keydown"; } // 弾を発射する関数 function fireBullet() { var bullet = { x: player.x, y: player.y, speed: 10, color: "#ff0000", radius: 5 }; bullets.push(bullet); } // 敵を作成する関数 function createEnemy() { var enemy = { x: Math.random() * gameArea.width, y: -20, speed: Math.random() * 4 + 1, color: "#00ff00", radius: 10 }; enemies.push(enemy); } // ゲームのループ function gameLoop() { // キャンバスをクリア ctx.clearRect(gameArea.x, gameArea.y, gameArea.width, gameArea.height); // プレイヤーの移動 if (keys[37]) { player.x -= player.speed; } if (keys[39]) { player.x += player.speed; } if (keys[32]) { fireBullet(); } // プレイヤーの描画 ctx.fillStyle = player.color; ctx.beginPath(); ctx.arc(player.x, player.y, player.radius, 0, 2 * Math.PI); ctx.fill(); // 弾の移動と描画 for (var i = 0; i < bullets.length; i++) { var bullet = bullets[i]; bullet.y -= bullet.speed; ctx.fillStyle = bullet.color; ctx.beginPath(); ctx.arc(bullet.x, bullet.y, bullet.radius, 0, 2 * Math.PI); ctx.fill(); // 弾が画面外に出たら削除 if (bullet.y < 0) { bullets.splice(i, 1); } } // 敵の移動と描画 for (var i = 0; i < enemies.length; i++) { var enemy = enemies[i]; enemy.y += enemy.speed; ctx.fillStyle = enemy.color; ctx.beginPath(); ctx.arc(enemy.x, enemy.y, enemy.radius, 0, 2 * Math.PI); ctx.fill(); // 敵が画面外に出たら削除 if (enemy.y > gameArea.height) { enemies.splice(i, 1); } // 敵と弾の衝突判定 for (var j = 0; j < bullets.length; j++) { var bullet = bullets[j]; var distance = Math.sqrt(Math.pow(enemy.x - bullet.x, 2) + Math.pow(enemy.y - bullet.y, 2)); if (distance < enemy.radius + bullet.radius) { // 衝突したら敵と弾を削除 enemies.splice(i, 1); bullets.splice(j, 1); } } // 敵とプレイヤーの衝突判定 var distance = Math.sqrt(Math.pow(enemy.x - player.x, 2) + Math.pow(enemy.y - player.y, 2)); if (distance < enemy.radius + player.radius) { // 衝突したらゲームオーバー alert("ゲームオーバー"); location.reload(); } } // 一定時間ごとに敵を作成 if (Math.random() < 0.05) { createEnemy(); } // 次のフレームを描画 requestAnimationFrame(gameLoop); } // ゲームの開始 window.addEventListener("keydown", updateKeys); window.addEventListener("keyup", updateKeys); gameLoop(); </script> </body> </html>
生成されたゲーム
かなりアラート表示がうざったいので、ここに張らずに↓リンクだけ張ることにします。基本的によさげな出力ですが、ゲームオーバー後に1フレームすすむごとに何度も「ゲームオーバー」と表示されます。これは、AI的には正しいのかもですが、人間からしたらバグですね、、
* PCで左右キーで操作可能です。スマホ未対応
https://retu27.com/wp-content/themes/retu27theme/chatgpt/shooting/test1/index.html
改変1: 地面も描画して下さい。人間も描画して下さい。
改変命令
ちょっとさすがに殺風景なので、人や地面も描画させるようにします。
生成コード
↓のような部分が追加され、赤玉がでるようになりました。
// 赤い球の移動と描画 bonus.y += bonus.speed; ctx.fillStyle = bonus.color; ctx.beginPath(); ctx.arc(bonus.x, bonus.y, bonus.radius, 0, 2 * Math.PI); ctx.fill(); // 赤い球とプレイヤーの衝突判定 var distance = Math.sqrt(Math.pow(bonus.x - player.x, 2) + Math.pow(bonus.y - player.y, 2)); if (distance < bonus.radius + player.radius) { // 衝突したらスコアを加算して赤い球を再配置 score += bonus.score; createBonus(); }
生成されたゲーム
これもまだalert表示がうざったいので別リンクにしました。ちゃんと赤玉がでてスコア追加されるようになりました!ただ、スコアが横にはみ出してる、、、
* PCで左右キーで操作可能です。スマホ未対応
https://retu27.com/wp-content/themes/retu27theme/chatgpt/shooting/test2/index.html
改変2: 背景追加、表示修正、自動リスタート
改変命令
背景が何もないと辛いので星空を描画させるようにしました。最初出力したときは星の数がすくなかったので、圧倒的に多く表示追加しました。「星の量がどれぐらいが適切か」というのも、よく星を見てる人間じゃないとわからないところがあるので難しいですよね。
生成コード
↓のような感じになりました。抜粋です
ctx.clearRect(gameArea.x, gameArea.y, gameArea.width, gameArea.height); // 星の描画 ctx.fillStyle = "#ffffff"; for (var i = 0; i < stars.length; i++) { var star = stars[i]; ctx.beginPath(); ctx.arc(star.x, star.y, star.radius, 0, 2 * Math.PI); ctx.fill(); }
生成されたゲーム
なんか背景の星の数が少しずつ多くなるというバグありますが、それでも意外とちゃんとしたシューティングができました!弾幕とまではいかないですが、敵の数も多めになってますね!
ただ、赤玉がなぜかリスタート時にでなくなるバグある、、、
* PCなら、スクリーン一度クリック後に左右キーで操作可能です。スマホ未対応
改変3: バグ修正
改変命令
赤玉がリスタート時にも出るように修正
生成コード
↓のような感じになりました。抜粋です。初期化処理を適切にした様子。
// リスタートのための処理 if (new Date().getTime() - gameOverTime > 3000) { // 変数の初期化 player.x = gameArea.width / 2; player.y = gameArea.height - 50; bullets = []; enemies = []; bonus = { x: Math.random() * gameArea.width, y: -20, speed: 2, color: "#ff0000", radius: 10, score: 10 }; score = 0; gameOver = false; gameOverTime = 0; // ゲームオーバーテキストの非表示 document.getElementById("gameOverText").style.display = "none"; }
生成されたゲーム
赤玉バグはなおったけど、、星が圧倒的に少なくなっている、、、ChatGPTはこのように、片方のバグを直すと、別のバグが再発するようなことが結構ありますね。
こういった意味でも、ある程度まで型ができたら手動で直した方が圧倒的にはやいですね、、
* PCなら、スクリーン一度クリック後に左右キーで操作可能です。スマホ未対応
結論:古典的なゲームは学習済みで作りやすい
今回ChatGPTでのシューティングゲーム作成でうまくいったのは、古典的なゲームでそのプログラミング例がネット上に多く掲載されているからだと思います。だからこそ、少ない文字で適切に意図が伝わったんですね。
逆に独創的なアイデアのゲームだとそれを全部意図伝えるのにはかなり苦労すると思います、、
⇒「ChatGPTプログラム生成実験」カテゴリ記事一覧
その他関連カテゴリ