![見出し画像](https://assets.st-note.com/production/uploads/images/100513079/rectangle_large_type_2_d0bb3d790f7d07fc1edc91a8eb4eb2da.png?width=1200)
ChatGPTに恐竜ゲーム風のゲームを作ってもらった
![](https://assets.st-note.com/production/uploads/images/100513133/picture_pc_d0da52423798bd838a5259797001dd63.gif?width=1200)
ChatGPT(GPT-4)にゲームを作ってもらっているのをよく見かけるので、便乗してやってみました。
ブラウザでサクッと実行したいので、以下のように依頼します。
![](https://assets.st-note.com/img/1679061284312-MzrwzN1Jhf.png?width=1200)
なお、一度に出力できる文字数には制限があるようで、何も指示をしないとJavaScriptファイルを出力している途中でネットワークエラーとなり、チャットが中断されてしまう事象が多々発生しました。
そのため、「1つのファイルを出力したら、そこで発言を止めてください」と指示を出して上記事象を回避するようにしています。
まず、index.htmlが出力されました。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Browser Game</title>
<style>
/* CSSはここに書きます */
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="400"></canvas>
<script>
// JavaScriptはここに書きます
</script>
</body>
</html>
CSS、JavaScriptをhtmlに直接記述する形式ですね。
CSS、JavaScriptは別ファイルとして出力されるケースも多々ありました。
次に、CSS。
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
canvas {
border: 1px solid #000;
}
そしてJavaScript。
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let isJumping = false;
let jumpHeight = 0;
const player = {
x: 100,
y: canvas.height - 50,
size: 40,
draw() {
ctx.fillStyle = 'black';
ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
},
jump() {
if (!isJumping) {
isJumping = true;
jumpHeight = 0;
}
}
};
canvas.addEventListener('click', player.jump);
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (isJumping) {
jumpHeight += 10;
if (jumpHeight > 100) {
isJumping = false;
}
} else {
if (jumpHeight > 0) {
jumpHeight -= 10;
}
}
player.draw();
requestAnimationFrame(gameLoop);
}
gameLoop();
コードの説明も記載してくれます。
このJavaScriptコードは、プレイヤーを表す四角形のオブジェクトを作成し、クリックでジャンプするようにします。また、gameLoop関数でアニメーションを実行し、プレイヤーを描画しています。
これで、Google Chromeの「Dinosaur Game」に似たシンプルなブラウザゲームが完成しました。index.htmlファイルを保存して、ブラウザで開いてゲームを試してみてください。もちろん、ゲームの要素や機能を追加して、さらに発展させることができます。
CSS、JavaScriptをindex.htmlに埋め込み、ブラウザで実行した結果がこちら。
![](https://assets.st-note.com/img/1679062107000-0A5Musrpzm.png?width=1200)
クリックをすると、プレイヤーに見立てた黒い四角がジャンプします。それだけです。
明らかに機能が足りていないので、
・クリックでのジャンプからスペースキーでのジャンプへの変更
・ジャンプによって障害物をよける横スクロールアクションゲームへの修正
を依頼します。
![](https://assets.st-note.com/img/1679062296949-B1qsRueetS.png?width=1200)
JavaScriptが長くなりネットワークエラーが発生してしまうため、40行出力したらそこで止めるような指示を加えています。
プログラムの説明を長々されるとそこでも制限に引っかかるため、不要としています。
出力されたJavaScriptを組み合わせたものが以下です。
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let isJumping = false;
let jumpHeight = 0;
const player = {
x: 100,
y: canvas.height - 50,
size: 40,
draw() {
ctx.fillStyle = 'black';
ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
},
jump() {
if (!isJumping) {
isJumping = true;
jumpHeight = 0;
}
}
};
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
player.jump();
}
});
class Obstacle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
draw() {
ctx.fillStyle = 'red';
ctx.fillRect(this.x, this.y - this.height, this.width, this.height);
}
update() {
this.x -= 5;
if (this.x + this.width < 0) {
this.x = canvas.width;
}
}
}
const obstacle = new Obstacle(canvas.width, canvas.height - 50, 40, 60);
function checkCollision(player, obstacle) {
const playerTop = player.y - player.size - jumpHeight;
const playerBottom = player.y - jumpHeight;
const playerLeft = player.x;
const playerRight = player.x + player.size;
const obstacleTop = obstacle.y - obstacle.height;
const obstacleBottom = obstacle.y;
const obstacleLeft = obstacle.x;
const obstacleRight = obstacle.x + obstacle.width;
return (
playerBottom > obstacleTop &&
playerTop < obstacleBottom &&
playerRight > obstacleLeft &&
playerLeft < obstacleRight
);
}
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (isJumping) {
jumpHeight += 10;
if (jumpHeight > 100) {
isJumping = false;
}
} else {
if (jumpHeight > 0) {
jumpHeight -= 10;
}
}
player.draw();
obstacle.draw();
obstacle.update();
if (checkCollision(player, obstacle)) {
console.log('Game Over');
} else {
requestAnimationFrame(gameLoop);
}
}
gameLoop();
JavaScriptを差し替えると、障害物が右から左へスクロールされるようになりました。
この障害物に衝突すると、そこで動作が停止する仕様になっています。
![](https://assets.st-note.com/img/1679062511365-2Dal2AOVIZ.png?width=1200)
さらに本家の恐竜ゲームへと近づけるため、
・ジャンプの滞空時間を長く
・複数の障害物を生成
・画面上に経過時間を表示
という依頼をしていきます。
![](https://assets.st-note.com/img/1679062680568-xWjHMfWUZU.png?width=1200)
最終的に出力されたJavaScriptは以下。
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let isJumping = false;
let jumpHeight = 0;
let elapsedTime = 0;
const player = {
x: 100,
y: canvas.height - 50,
size: 40,
draw() {
ctx.fillStyle = 'black';
ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
},
jump() {
if (!isJumping) {
isJumping = true;
jumpHeight = 0;
}
}
};
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
player.jump();
}
});
class Obstacle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
draw() {
ctx.fillStyle = 'red';
ctx.fillRect(this.x, this.y - this.height, this.width, this.height);
}
update() {
this.x -= 5;
if (this.x + this.width < 0) {
this.x = canvas.width + Math.random() * 800;
}
}
}
const obstacles = [
new Obstacle(canvas.width, canvas.height - 50, 40, 60),
new Obstacle(canvas.width + 400, canvas.height - 50, 40, 60),
];
function checkCollision(player, obstacle) {
const playerTop = player.y - player.size - jumpHeight;
const playerBottom = player.y - jumpHeight;
const playerLeft = player.x;
const playerRight = player.x + player.size;
const obstacleTop = obstacle.y - obstacle.height;
const obstacleBottom = obstacle.y;
const obstacleLeft = obstacle.x;
const obstacleRight = obstacle.x + obstacle.width;
return (
playerBottom > obstacleTop &&
playerTop < obstacleBottom &&
playerRight > obstacleLeft &&
playerLeft < obstacleRight
);
}
function gameLoop(timestamp) {
elapsedTime = Math.floor(timestamp / 1000);
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (isJumping) {
jumpHeight += 5;
if (jumpHeight > 100) {
isJumping = false;
}
} else {
if (jumpHeight > 0) {
jumpHeight -= 5;
}
}
player.draw();
obstacles.forEach(obstacle => {
obstacle.draw();
obstacle.update();
});
ctx.fillStyle = 'black';
ctx.font = '20px Arial';
ctx.fillText(`Time: ${elapsedTime}s`, 10, 30);
if (obstacles.some(obstacle => checkCollision(player, obstacle))) {
console.log('Game Over');
} else {
requestAnimationFrame(gameLoop);
}
}
requestAnimationFrame(gameLoop);
40行単位で分割して出力しているからか、一部関数が重複したり抜けたりすることはあったものの、そこを切り張りで対応したのみで、プログラム自体の修正は全くしていません。
これで、この記事の冒頭でお見せした恐竜ゲーム風のゲームの完成です。
ネットワークエラー回避のための試行錯誤を含めても、トータル1時間かかっていません。
改めてGPT-4のすごさを実感させられました。
言葉通りの意味での「プログラマ」は、もはや不要なのでは。そう思う、元職業プログラマでした。
この記事が気に入ったらサポートをしてみませんか?