【ChatGPT o1-mini】のプログラミング能力の向上。簡単なプロンプトでアステロイドゲームを作った(遊べます)。
はじめに
13日に発表されたChatGPTの新モデル、大型のo1-previewと小型のo1-mini。
プログラミング能力は、小型のo1-miniの方が高いということで、実際に試してみます。
プロンプト
以下のようなシンプルなプロンプトを入力して、ゲームを作ります。
果たして、動くものはできるでしょうか?
HTMLファイルのシングルページアプリケーションのゲームを作ります。アステロイドゲームを作ってください。
アステロイドゲームをシングルページアプリケーション(HTMLファイル)として作成するためのサンプルコードを以下に提供します。このゲームは、HTML5の`<canvas>`要素とJavaScriptを使用して実装されています。
HTMLファイル
以下のコードをコピーして、例えば`asteroid_game.html`という名前で保存してください。その後、ブラウザで開くことでゲームをプレイできます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>アステロイドゲーム</title>
<style>
body {
margin: 0;
background: #000;
overflow: hidden;
color: #fff;
font-family: Arial, sans-serif;
}
#gameCanvas {
display: block;
margin: 0 auto;
background: #000;
}
#score {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
font-size: 20px;
}
#gameOver {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 40px;
display: none;
}
#restart {
position: absolute;
top: 60%;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
font-size: 20px;
display: none;
cursor: pointer;
}
</style>
</head>
<body>
<div id="score">スコア: 0</div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div id="gameOver">ゲームオーバー</div>
<button id="restart">再スタート</button>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const gameOverElement = document.getElementById('gameOver');
const restartButton = document.getElementById('restart');
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
let score = 0;
let animationId;
let gameOver = false;
// プレイヤーの設定
const player = {
x: WIDTH / 2,
y: HEIGHT / 2,
radius: 20,
angle: 0,
rotation: 0,
speed: 0,
velocity: { x: 0, y: 0 },
thrust: 0.1,
friction: 0.99,
draw: function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.beginPath();
ctx.moveTo(20, 0);
ctx.lineTo(-10, 10);
ctx.lineTo(-10, -10);
ctx.closePath();
ctx.strokeStyle = 'white';
ctx.stroke();
ctx.restore();
},
update: function() {
this.angle += this.rotation;
this.velocity.x *= this.friction;
this.velocity.y *= this.friction;
this.velocity.x += Math.cos(this.angle) * this.speed;
this.velocity.y += Math.sin(this.angle) * this.speed;
this.x += this.velocity.x;
this.y += this.velocity.y;
// 画面端を反対側に移動
if (this.x > WIDTH + this.radius) this.x = -this.radius;
if (this.x < -this.radius) this.x = WIDTH + this.radius;
if (this.y > HEIGHT + this.radius) this.y = -this.radius;
if (this.y < -this.radius) this.y = HEIGHT + this.radius;
}
};
// アステロイドの設定
const asteroids = [];
const asteroidCount = 5;
function createAsteroid(x, y, radius, level) {
const asteroid = {
x: x,
y: y,
radius: radius,
speed: Math.random() * 1.5 + 0.5,
angle: Math.random() * Math.PI * 2,
velocity: {
x: Math.cos(Math.random() * Math.PI * 2) * (Math.random() * 1.5 + 0.5),
y: Math.sin(Math.random() * Math.PI * 2) * (Math.random() * 1.5 + 0.5)
},
level: level || 0,
draw: function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.beginPath();
for (let i = 0; i < 10; i++) {
const angle = (Math.PI * 2 / 10) * i;
const r = this.radius + Math.random() * 10 - 5;
ctx.lineTo(r * Math.cos(angle), r * Math.sin(angle));
}
ctx.closePath();
ctx.strokeStyle = 'white';
ctx.stroke();
ctx.restore();
},
update: function() {
this.x += this.velocity.x;
this.y += this.velocity.y;
// 画面端を反対側に移動
if (this.x > WIDTH + this.radius) this.x = -this.radius;
if (this.x < -this.radius) this.x = WIDTH + this.radius;
if (this.y > HEIGHT + this.radius) this.y = -this.radius;
if (this.y < -this.radius) this.y = HEIGHT + this.radius;
}
};
asteroids.push(asteroid);
}
// 初期アステロイド生成
for (let i = 0; i < asteroidCount; i++) {
let x, y;
do {
x = Math.random() * WIDTH;
y = Math.random() * HEIGHT;
} while (Math.hypot(player.x - x, player.y - y) < 100);
createAsteroid(x, y, 50);
}
// キー入力の処理
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.code] = true;
});
document.addEventListener('keyup', (e) => {
keys[e.code] = false;
});
// 弾丸の設定
const bullets = [];
const bulletSpeed = 5;
const bulletLimit = 10;
function shootBullet() {
if (bullets.length < bulletLimit) {
bullets.push({
x: player.x,
y: player.y,
velocity: {
x: Math.cos(player.angle) * bulletSpeed + player.velocity.x,
y: Math.sin(player.angle) * bulletSpeed + player.velocity.y
},
radius: 2,
lifespan: 60,
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = 'white';
ctx.fill();
},
update: function() {
this.x += this.velocity.x;
this.y += this.velocity.y;
this.lifespan--;
}
});
}
}
// 衝突判定
function checkCollision(obj1, obj2) {
const dist = Math.hypot(obj1.x - obj2.x, obj1.y - obj2.y);
return dist < obj1.radius + obj2.radius;
}
// ゲームループ
function gameLoop() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
// プレイヤーの操作
if (keys['ArrowLeft']) {
player.rotation = -0.05;
} else if (keys['ArrowRight']) {
player.rotation = 0.05;
} else {
player.rotation = 0;
}
if (keys['ArrowUp']) {
player.speed = player.thrust;
} else {
player.speed = 0;
}
if (keys['Space']) {
shootBullet();
keys['Space'] = false; // 連射防止
}
player.update();
player.draw();
// アステロイドの更新と描画
asteroids.forEach((asteroid, index) => {
asteroid.update();
asteroid.draw();
// プレイヤーとの衝突判定
if (checkCollision(player, asteroid)) {
endGame();
}
// 弾丸との衝突判定
bullets.forEach((bullet, bIndex) => {
if (checkCollision(bullet, asteroid)) {
bullets.splice(bIndex, 1);
asteroids.splice(index, 1);
score += 100;
scoreElement.textContent = `スコア: ${score}`;
// 小さいアステロイドを生成
if (asteroid.radius > 20) {
for (let i = 0; i < 2; i++) {
createAsteroid(asteroid.x, asteroid.y, asteroid.radius / 2, asteroid.level + 1);
}
}
}
});
});
// 弾丸の更新と描画
bullets.forEach((bullet, index) => {
bullet.update();
bullet.draw();
if (bullet.lifespan <= 0) {
bullets.splice(index, 1);
}
});
// 次のフレーム
if (!gameOver) {
animationId = requestAnimationFrame(gameLoop);
}
}
// ゲーム終了
function endGame() {
gameOver = true;
cancelAnimationFrame(animationId);
gameOverElement.style.display = 'block';
restartButton.style.display = 'block';
}
// 再スタート
restartButton.addEventListener('click', () => {
// 初期化
asteroids.length = 0;
bullets.length = 0;
score = 0;
scoreElement.textContent = `スコア: ${score}`;
player.x = WIDTH / 2;
player.y = HEIGHT / 2;
player.velocity.x = 0;
player.velocity.y = 0;
gameOver = false;
gameOverElement.style.display = 'none';
restartButton.style.display = 'none';
// アステロイド再生成
for (let i = 0; i < asteroidCount; i++) {
let x, y;
do {
x = Math.random() * WIDTH;
y = Math.random() * HEIGHT;
} while (Math.hypot(player.x - x, player.y - y) < 100);
createAsteroid(x, y, 50);
}
// ゲーム開始
animationId = requestAnimationFrame(gameLoop);
});
// ゲーム開始
animationId = requestAnimationFrame(gameLoop);
</script>
</body>
</html>
ゲーム画面
ゲームの操作方法
回転: 左矢印キー (`ArrowLeft`) と右矢印キー (`ArrowRight`) を使用して宇宙船を回転させます。
推進: 上矢印キー (`ArrowUp`) を押して宇宙船を前進させます。
射撃: スペースキー (`Space`) を押して弾丸を発射します。
コードの説明
HTML構造:
`<canvas>`要素はゲームの描画領域です。
スコア表示やゲームオーバーのメッセージ、再スタートボタンを表示するための要素も含まれています。
スタイル:
ゲームの背景を黒に設定し、キャンバスを中央に配置しています。
スコアやゲームオーバーのメッセージ、再スタートボタンのスタイルも定義しています。
JavaScript:
プレイヤー: 宇宙船の位置、速度、回転などを管理します。`draw`メソッドで宇宙船を描画し、`update`メソッドで位置と速度を更新します。
アステロイド: ランダムな位置と速度でアステロイドを生成し、画面上を移動させます。衝突判定も行います。
弾丸: 宇宙船から発射され、一定の寿命で消滅します。アステロイドと衝突するとアステロイドを分割または破壊します。
ゲームループ: `requestAnimationFrame`を使用して、毎フレームゲームの状態を更新し、描画します。
衝突判定: プレイヤーとアステロイド、弾丸とアステロイドの衝突を検出します。
ゲームオーバー: 宇宙船がアステロイドと衝突した場合にゲームを終了し、再スタートボタンを表示します。
再スタート: ゲームオーバー後に再度ゲームを開始できるように初期化します。
カスタマイズ
この基本的なアステロイドゲームを基に、以下のような機能を追加・カスタマイズすることができます。
音楽と効果音: ゲームに音楽や効果音を追加して、より没入感のある体験に。
スコアボード: 高得点を記録し、表示する機能。
複数のレベル: アステロイドの数や速度をレベルに応じて増加させる。
パワーアップ: シールドや追加弾薬などのパワーアップアイテムを追加。
グラフィックスの向上: より詳細な宇宙船やアステロイドのデザイン。
注意事項
パフォーマンス: 多数のアステロイドや弾丸を同時に処理すると、ブラウザのパフォーマンスに影響を与える可能性があります。適切に最適化してください。
モバイル対応: このコードはデスクトップ向けに設計されています。モバイルデバイスでプレイ可能にするためには、タッチ操作のサポートや画面サイズの調整が必要です。
ぜひ、このコードを基にして、自分だけのアステロイドゲームを作成してみてください!
以下のファイルをダウンロードして、ファイルをクリックすると実際に遊べます!
o1-mini版アステロイドゲームのファイル
弊社サーバにもアップしておきました。こちらをクリックしていただくとブラウザで遊べます。
比較対象
同じプロンプトでGPT-4oで作成したアステロイドゲームのファイル
GPT-4oで作ったこのゲームは、機体も動きませんので、不合格です。
同じく、Webアプリケーション制作に特化したGPTsが出力したアステロイドゲーム
このGPTsで作ったゲームは、ちゃんと遊べますが、o1-miniで作ったゲームの方が面白いし、オープニングやエンディングもできていて、ゲームとしての完成度は高いです。
まとめ
以上、o1-miniのプログラミング能力を試す実験としてのゲーム制作でした。
結論としては、少なくとも今回試したゲーム制作においては、o1-miniは、GPT-4oよりプログラミング能力が上がっています。
【重版決定】AIアプリをプログラミング不要で開発する書籍
GPTsを自分で作って世界に公開したい方はこちら!
この記事が気に入ったらサポートをしてみませんか?