📝
Claude 3.5でインベーダーゲームを作った
生成AI(Claude 3.5)を使ってインベーダーゲームのプログラムを作ってもらいました。
追加の指示は2回だけである程度動くものができました。
完成したゲームのリンクは以下です。
完成したゲームのリンク
指示したプロンプト
指示したプロンプトを順に並べます。
htmlのcanvasでスペースインベーダーを作って
ゲームオーバーしたらエンターキーでリスタートできるようにして
すべての敵を倒したらクリアにして
完成したプログラム
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>スペースインベーダー</title>
<style>
canvas {
border: 2px solid black;
display: block;
margin: 0 auto;
background-color: black;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// ゲーム状態を初期化する関数
function resetGame() {
// プレイヤーの設定
player.x = canvas.width / 2 - 25;
player.y = canvas.height - 50;
// 敵の再初期化
enemies.length = 0;
initEnemies();
// 弾のクリア
bullets.length = 0;
enemyBullets.length = 0;
// ゲーム状態のリセット
gameOver = false;
gameClear = false;
score = 0;
// ゲームループの再開
gameLoop();
}
// プレイヤーの設定
const player = {
x: canvas.width / 2 - 25,
y: canvas.height - 50,
width: 50,
height: 20,
speed: 5,
color: 'green'
};
// 敵の設定
const enemies = [];
const enemyWidth = 40;
const enemyHeight = 20;
const enemyRows = 5;
const enemyCols = 10;
const enemyColor = 'red';
// 弾の設定
const bullets = [];
const enemyBullets = [];
// ゲーム状態
let gameOver = false;
let gameClear = false;
let score = 0;
// 敵の初期化
function initEnemies() {
for (let row = 0; row < enemyRows; row++) {
for (let col = 0; col < enemyCols; col++) {
enemies.push({
x: col * (enemyWidth + 10) + 50,
y: row * (enemyHeight + 10) + 50,
width: enemyWidth,
height: enemyHeight,
speed: 1
});
}
}
}
// プレイヤーの描画
function drawPlayer() {
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
}
// 敵の描画
function drawEnemies() {
ctx.fillStyle = enemyColor;
enemies.forEach(enemy => {
ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
});
}
// 弾の描画
function drawBullets() {
ctx.fillStyle = 'white';
bullets.forEach(bullet => {
ctx.fillRect(bullet.x, bullet.y, 5, 10);
});
enemyBullets.forEach(bullet => {
ctx.fillRect(bullet.x, bullet.y, 5, 10);
});
}
// 敵の移動
function moveEnemies() {
let hitEdge = false;
enemies.forEach(enemy => {
enemy.x += enemy.speed;
if (enemy.x + enemy.width > canvas.width || enemy.x < 0) {
hitEdge = true;
}
});
if (hitEdge) {
enemies.forEach(enemy => {
enemy.speed *= -1;
enemy.y += 20;
});
}
}
// 衝突判定
function checkCollisions() {
// プレイヤーの弾と敵の衝突
bullets.forEach((bullet, bulletIndex) => {
enemies.forEach((enemy, enemyIndex) => {
if (
bullet.x < enemy.x + enemy.width &&
bullet.x + 5 > enemy.x &&
bullet.y < enemy.y + enemy.height &&
bullet.y + 10 > enemy.y
) {
bullets.splice(bulletIndex, 1);
enemies.splice(enemyIndex, 1);
score += 10;
}
});
});
// すべての敵を倒したかチェック
if (enemies.length === 0) {
gameClear = true;
}
// 敵の弾とプレイヤーの衝突
enemyBullets.forEach((bullet, bulletIndex) => {
if (
bullet.x < player.x + player.width &&
bullet.x + 5 > player.x &&
bullet.y < player.y + player.height &&
bullet.y + 10 > player.y
) {
gameOver = true;
}
});
// 敵がプレイヤーに到達
enemies.forEach(enemy => {
if (enemy.y + enemy.height > player.y) {
gameOver = true;
}
});
}
// 敵の弾発射
function enemyShoot() {
if (Math.random() < 0.02 && enemies.length > 0) {
const randomEnemy = enemies[Math.floor(Math.random() * enemies.length)];
enemyBullets.push({
x: randomEnemy.x + randomEnemy.width / 2,
y: randomEnemy.y + randomEnemy.height,
speed: 3
});
}
}
// ゲームループ
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (!gameOver && !gameClear) {
drawPlayer();
drawEnemies();
drawBullets();
moveEnemies();
checkCollisions();
enemyShoot();
// 弾の移動
bullets.forEach((bullet, index) => {
bullet.y -= 7;
if (bullet.y < 0) {
bullets.splice(index, 1);
}
});
enemyBullets.forEach((bullet, index) => {
bullet.y += bullet.speed;
if (bullet.y > canvas.height) {
enemyBullets.splice(index, 1);
}
});
// スコア表示
ctx.fillStyle = 'white';
ctx.font = '20px Arial';
ctx.fillText(`スコア: ${score}`, 10, 30);
requestAnimationFrame(gameLoop);
} else if (gameOver) {
// ゲームオーバー画面
ctx.fillStyle = 'white';
ctx.font = '40px Arial';
ctx.fillText('ゲームオーバー', canvas.width / 2 - 120, canvas.height / 2);
ctx.font = '20px Arial';
ctx.fillText(`スコア: ${score}`, canvas.width / 2 - 50, canvas.height / 2 + 50);
ctx.font = '15px Arial';
ctx.fillText('Enterキーを押してリスタート', canvas.width / 2 - 100, canvas.height / 2 + 100);
} else if (gameClear) {
// ゲームクリア画面
ctx.fillStyle = 'white';
ctx.font = '40px Arial';
ctx.fillText('ゲームクリア!', canvas.width / 2 - 120, canvas.height / 2);
ctx.font = '20px Arial';
ctx.fillText(`スコア: ${score}`, canvas.width / 2 - 50, canvas.height / 2 + 50);
ctx.font = '15px Arial';
ctx.fillText('Enterキーを押してリスタート', canvas.width / 2 - 100, canvas.height / 2 + 100);
}
}
// キーボード入力
document.addEventListener('keydown', (e) => {
if (!gameOver && !gameClear) {
if (e.key === 'ArrowLeft' && player.x > 0) {
player.x -= player.speed;
}
if (e.key === 'ArrowRight' && player.x < canvas.width - player.width) {
player.x += player.speed;
}
if (e.key === ' ') {
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
speed: 7
});
}
} else {
// ゲームオーバーまたはゲームクリア時にEnterキーでリスタート
if (e.key === 'Enter') {
resetGame();
}
}
});
// ゲームの初期化
initEnemies();
gameLoop();
</script>
</body>
</html>
CodePenでも公開しています。
以下のリンクからどうぞ。
Discussion