
ChatGPT4:ブロック崩しの自動生成(4) 「初の謝罪!カオスの始まり」
リスタートの指示
今まで、
「ボールを落としたら、即ゲームオーバー」という仕様から、
急にライフ制を導入したことで、
「(ライフの残があるならば)ゲームをリスタートする」
必要が出てきました。
下記のプロンプトで、改善を依頼します。
いいですね。次の改善をお願いします。
・ボールを下に落としたらライフを−1したあとは、新たなボールを表示してプレイを再開してください。
・ブロックの色を行ごとに変更する処理が反映されていないので確認し、必要があれば修正してください。
ご指示に従って、ボールが落ちた後に新たなボールを生成し、プレイを再開する処理と、ブロックの色が行ごとに変わるように修正しました。
<!DOCTYPE html>
<html>
<head>
<style>
.block1 { background-color: red; }
.block2 { background-color: green; }
.block3 { background-color: blue; }
.block4 { background-color: yellow; }
.block5 { background-color: orange; }
.block6 { background-color: purple; }
</style>
</head>
<body>
<canvas id="myCanvas" width="1280" height="720"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var score = 0;
var stage = 1;
var life = 3;
var blockRowCount = 6;
var blockColumnCount = 8;
var blockWidth = 75;
var blockHeight = 20;
var blockPadding = 10;
var blockOffsetTop = 30;
var blockOffsetLeft = (canvas.width - (blockColumnCount * (blockWidth + blockPadding))) / 2;
var balls = [{
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
}];
var blocks = [];
function generateBlocks() {
for(var c=0; c<blockColumnCount; c++) {
blocks[c] = [];
for(var r=0; r<blockRowCount; r++) {
blocks[c][r] = { x: 0, y: 0, status: 1, class: `block${r+1}` };
}
}
}
generateBlocks();
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function drawBall(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBlocks() {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
if(blocks[c][r].status == 1) {
var blockX = (c*(blockWidth+blockPadding))+blockOffsetLeft;
var blockY = (r*(blockHeight+blockPadding))+blockOffsetTop;
blocks[c][r].x = blockX;
blocks[c][r].y = blockY;
ctx.beginPath();
ctx.rect(blockX, blockY, blockWidth, blockHeight);
ctx.fillStyle = window.getComputedStyle(document.body).getPropertyValue(blocks[c][r].class);
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLife() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Life: "+life, canvas.width - 100, 20);
}
function drawStage() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Stage: "+stage, canvas.width - 200, 20);
}
function collisionDetection(ball) {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
var b = blocks[c][r];
if(b.status == 1) {
if(ball.x > b.x && ball.x < b.x+blockWidth && ball.y > b.y && ball.y < b.y+blockHeight) {
ball.dy = -ball.dy;
b.status = 0;
score++;
if(score % 50 == 0) {
life++;
}
if(score % 5 == 0) {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
}
if(score == blockRowCount*blockColumnCount*stage) {
if(stage == 10) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
clearInterval(interval);
} else {
stage++;
generateBlocks();
}
}
}
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBlocks();
balls.forEach(ball => drawBall(ball));
drawPaddle();
drawScore();
drawLife();
drawStage();
balls.forEach(ball => collisionDetection(ball));
balls = balls.filter((ball, i) => {
if(ball.x + ball.dx > canvas.width-ballRadius || ball.x + ball.dx < ballRadius) {
ball.dx = -ball.dx;
}
if(ball.y + ball.dy < ballRadius) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.dy > canvas.height-ballRadius) {
if(ball.x > paddleX && ball.x < paddleX + paddleWidth) {
ball.dy = -ball.dy;
return true;
}
else {
life--;
if(life == 0) {
alert("GAME OVER");
document.location.reload();
clearInterval(interval);
} else {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
return false;
}
}
} else {
return true;
}
});
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
}
var interval = setInterval(draw, 10);
</script>
</body>
</html>
動かなくなりましたね
ここへきて、ついに動いていた部分も動かなくなりました。
リスタートどころか、普通にスタートもしません。
相変わらずCSS記述も残っていますが、埋め込みはされていません。
めげずに、褒め続けて修正を依頼してみます。
いいですね。次の改善をお願いします。
・ゲーム開始時にボールが動かない不具合を修正
・ゲーム起動時に、「PUSH SPACE KEY」と表示し、スペースキーが押されたらゲームを起動するように修正
ご指定通りにコードを更新しました。スペースキーが押されたときにゲームが開始され、ゲームが開始されるまではボールが動かないように修正しました。
<!DOCTYPE html>
<html>
<head>
<style>
.block1 { background-color: red; }
.block2 { background-color: green; }
.block3 { background-color: blue; }
.block4 { background-color: yellow; }
.block5 { background-color: orange; }
.block6 { background-color: purple; }
</style>
</head>
<body>
<canvas id="myCanvas" width="1280" height="720"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var score = 0;
var stage = 1;
var life = 3;
var blockRowCount = 6;
var blockColumnCount = 8;
var blockWidth = 75;
var blockHeight = 20;
var blockPadding = 10;
var blockOffsetTop = 30;
var blockOffsetLeft = (canvas.width - (blockColumnCount * (blockWidth + blockPadding))) / 2;
var gameStarted = false;
var balls = [{
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
}];
var blocks = [];
function generateBlocks() {
for(var c=0; c<blockColumnCount; c++) {
blocks[c] = [];
for(var r=0; r<blockRowCount; r++) {
blocks[c][r] = { x: 0, y: 0, status: 1, class: `block${r+1}` };
}
}
}
generateBlocks();
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
else if(e.key == " " || e.key == "Spacebar") {
gameStarted = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function drawBall(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBlocks() {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
if(blocks[c][r].status == 1) {
var blockX = (c*(blockWidth+blockPadding))+blockOffsetLeft;
var blockY = (r*(blockHeight+blockPadding))+blockOffsetTop;
blocks[c][r].x = blockX;
blocks[c][r].y = blockY;
ctx.beginPath();
ctx.rect(blockX, blockY, blockWidth, blockHeight);
ctx.fillStyle = window.getComputedStyle(document.body).getPropertyValue(blocks[c][r].class);
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLife() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Life: "+life, canvas.width - 100, 20);
}
function drawStage() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Stage: "+stage, canvas.width - 200, 20);
}
function drawStartScreen() {
ctx.font = "40px Arial";
ctx.fillStyle = "#0095DD";
ctx.textAlign = "center";
ctx.fillText("PUSH SPACE KEY", canvas.width/2, canvas.height/2);
}
function collisionDetection(ball) {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
var b = blocks[c][r];
if(b.status == 1) {
if(ball.x > b.x && ball.x < b.x+blockWidth && ball.y > b.y && ball.y < b.y+blockHeight) {
ball.dy = -ball.dy;
b.status = 0;
score++;
if(score % 50 == 0) {
life++;
}
if(score % 5 == 0) {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
}
if(score == blockRowCount*blockColumnCount*stage) {
if(stage == 10) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
clearInterval(interval);
} else {
stage++;
generateBlocks();
}
}
}
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBlocks();
balls.forEach(ball => drawBall(ball));
drawPaddle();
drawScore();
drawLife();
drawStage();
if (!gameStarted) {
drawStartScreen();
return;
}
balls.forEach(ball => collisionDetection(ball));
balls = balls.filter((ball, i) => {
if(ball.x + ball.dx > canvas.width-ballRadius || ball.x + ball.dx < ballRadius) {
ball.dx = -ball.dx;
}
if(ball.y + ball.dy < ballRadius) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.dy > canvas.height-ballRadius) {
if(ball.x > paddleX && ball.x < paddleX + paddleWidth) {
ball.dy = -ball.dy;
return true;
}
else {
life--;
if(life == 0) {
alert("GAME OVER");
document.location.reload();
clearInterval(interval);
} else if(i == balls.length - 1) {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
}
return false;
}
}
return true;
});
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
}
var interval = setInterval(draw, 10);
</script>
</body>
</html>
これにより、ゲームが始まるまでボールは動きません。ゲーム開始はスペースキーを押すことで行われます。また、ボールが画面下に行った時には新しいボールが出現し、ゲームが続行されます。

プログラミングでゲーム作ってるな!という感じ。
いい感じなのですが、まだボールが動かないままです。
「ご指定通りにコードを更新しました。」
という言い方あたりが、
指示をしたこちらに責任がある感じがして嫌ですよね。
(責任はこちらにあるのですがw)
ボールが動かないことは大きな問題なので、
繰り返し「2回目です」という念押しと共に、
同様の指示を伝えます。
合わせて、スコア表示も左側が見切れていたので、
画面サイズを調整しています。
今回も、モチベーションを保って欲しいので、
「いいですね。」の褒め言葉は忘れずに!
いいですね。次の改善をお願いします。
・画面幅サイズを960に修正
・ゲーム開始時にボールが動かない不具合を修正してください。2回目です。
初の謝罪コメント!しかし・・・
申し訳ありません、再度ゲーム開始時にボールが動かない不具合を修正し、画面幅を960に修正します。
<!DOCTYPE html>
<html>
<head>
<style>
.block1 { background-color: red; }
.block2 { background-color: green; }
.block3 { background-color: blue; }
.block4 { background-color: yellow; }
.block5 { background-color: orange; }
.block6 { background-color: purple; }
</style>
</head>
<body>
<canvas id="myCanvas" width="960" height="720"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth) / 2;
var rightPressed = false;
var leftPressed = false;
var score = 0;
var stage = 1;
var life = 3;
var blockRowCount = 6;
var blockColumnCount = 8;
var blockWidth = 75;
var blockHeight = 20;
var blockPadding = 10;
var blockOffsetTop = 30;
var blockOffsetLeft = (canvas.width - (blockColumnCount * (blockWidth + blockPadding))) / 2;
var gameStarted = false;
var balls = [{
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
}];
var blocks = [];
function generateBlocks() {
for(var c=0; c<blockColumnCount; c++) {
blocks[c] = [];
for(var r=0; r<blockRowCount; r++) {
blocks[c][r] = { x: 0, y: 0, status: 1, class: `block${r+1}` };
}
}
}
generateBlocks();
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = true;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = true;
}
else if(e.key == " " || e.key == "Spacebar") {
gameStarted = true;
}
}
function keyUpHandler(e) {
if(e.key == "Right" || e.key == "ArrowRight") {
rightPressed = false;
}
else if(e.key == "Left" || e.key == "ArrowLeft") {
leftPressed = false;
}
}
function drawBall(ball) {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawBlocks() {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
if(blocks[c][r].status == 1) {
var blockX = (c*(blockWidth+blockPadding))+blockOffsetLeft;
var blockY = (r*(blockHeight+blockPadding))+blockOffsetTop;
blocks[c][r].x = blockX;
blocks[c][r].y = blockY;
ctx.beginPath();
ctx.rect(blockX, blockY, blockWidth, blockHeight);
ctx.fillStyle = window.getComputedStyle(document.body).getPropertyValue(blocks[c][r].class);
ctx.fill();
ctx.closePath();
}
}
}
}
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: "+score, 8, 20);
}
function drawLife() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Life: "+life, canvas.width - 100, 20);
}
function drawStage() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Stage: "+stage, canvas.width - 200, 20);
}
function drawStartScreen() {
ctx.font = "40px Arial";
ctx.fillStyle = "#0095DD";
ctx.textAlign = "center";
ctx.fillText("PUSH SPACE KEY", canvas.width/2, canvas.height/2);
}
function collisionDetection(ball) {
for(var c=0; c<blockColumnCount; c++) {
for(var r=0; r<blockRowCount; r++) {
var b = blocks[c][r];
if(b.status == 1) {
if(ball.x > b.x && ball.x < b.x+blockWidth && ball.y > b.y && ball.y < b.y+blockHeight) {
ball.dy = -ball.dy;
b.status = 0;
score++;
if(score % 50 == 0) {
life++;
}
if(score % 5 == 0) {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
}
if(score == blockRowCount*blockColumnCount*stage) {
if(stage == 10) {
alert("YOU WIN, CONGRATS!");
document.location.reload();
clearInterval(interval);
} else {
stage++;
generateBlocks();
}
}
}
}
}
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBlocks();
drawScore();
drawLife();
drawStage();
if(gameStarted) {
balls.forEach((ball, i) => {
drawBall(ball);
ball.x += ball.dx;
ball.y += ball.dy;
if(ball.x + ball.dx > canvas.width-ballRadius || ball.x + ball.dx < ballRadius) {
ball.dx = -ball.dx;
}
if(ball.y + ball.dy < ballRadius) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.dy > canvas.height-ballRadius) {
if(ball.x > paddleX && ball.x < paddleX + paddleWidth) {
ball.dy = -ball.dy;
}
else {
balls.splice(i, 1);
if(!balls.length) {
life--;
if(!life) {
alert("GAME OVER");
document.location.reload();
clearInterval(interval);
} else {
balls.push({
x: canvas.width/2,
y: canvas.height-30,
dx: 2,
dy: -2
});
}
}
}
}
if(rightPressed && paddleX < canvas.width-paddleWidth) {
paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
paddleX -= 7;
}
collisionDetection(ball);
});
} else {
drawStartScreen();
}
}
var interval = setInterval(draw, 10);
</script>
</body>
</html>
このコードは、以下の修正を行いました:
・ゲーム開始時にボールが動かない不具合を修正:ゲームが始まるまで(スペースキーが押されるまで)ボールを描画せず、代わりに開始画面を描画するようにしました。
・キャンバスの幅を960pxに修正しました。

今度は「パドル(左右に操作する板のこと)」表示が消えました。
カオスですね。
続きは、また次回!