話題のChatGPTを使って、一人用ピンポンゲームを作ったら30分でできた。すごいぞ。ちゃんと遊べる。
ぷよぷよを作ろうとしている人とかいたので、もっと簡単なものを作ってみた。
Q1.Javascriptを使って、一人用のPONGのプログラムを書いて
A. はい、PONGゲームのプログラムをJavaScriptで書いてみましょう!
以下は、一人用のシンプルなPONGゲームのサンプルコードです。このコードは、HTML5のcanvas要素を使用してゲームを描画し、requestAnimationFrame()メソッドを使用してゲームループを制御します。また、簡単な衝突判定を実装しています。
// ゲームの初期化
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var ball = { x: canvas.width/2, y: canvas.height/2, dx: 5, dy: 5, radius: 10 };
var paddle = { x: canvas.width/2, y: canvas.height-20, width: 80, height: 10 };
var leftPressed = false;
var rightPressed = false;
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if(e.keyCode == 37) {
leftPressed = true;
}
else if(e.keyCode == 39) {
rightPressed = true;
}
}
function keyUpHandler(e) {
if(e.keyCode == 37) {
leftPressed = false;
}
else if(e.keyCode == 39) {
rightPressed = false;
}
}
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddle.x - paddle.width/2, paddle.y, paddle.width, paddle.height);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw() {
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁に当たった場合は反射
if(ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
}
if(ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.radius > canvas.height) {
alert("GAME OVER");
document.location.reload();
}
// パドルとの衝突判定
if(ball.y + ball.dy > paddle.y - ball.radius &&
ball.x > paddle.x - paddle.width/2 &&
ball.x < paddle.x + paddle.width/2) {
ball.dy = -ball.dy;
}
// パドルの移動
if(leftPressed && paddle.x - paddle.width/2 > 0) {
paddle.x -= 7;
}
else if(rightPressed && paddle.x + paddle.width/2 < canvas.width) {
paddle.x += 7;
}
// ゲーム画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ボールとパドルの描画
drawBall();
drawPaddle();
// ゲームループの再帰呼び出し
requestAnimationFrame(draw);
}
// ゲームル
おお!すごい。なんかコードが出てきた。途中までしかないけど、いちおう動かしてみたい。
Q2.このコードをpong.jsというファイル名として、pong.jsを読み込むHTMLファイルを作って
A.以下は、先程のJavaScriptコードをpong.jsというファイル名で保存し、それを読み込むHTMLファイルの例です。
このHTMLファイルには<canvas>要素と、<script>要素が含まれています。<script>要素でJavaScriptファイルを読み込み、ゲームの開始を開始するためにdraw()関数を呼び出します。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PONG</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width="480" height="320"></canvas>
<script src="pong.js"></script>
</body>
</html>
上記のHTMLファイルをブラウザで開くと、pong.jsファイルが読み込まれ、PONGゲームが表示されます。ただし、pong.jsファイルとHTMLファイルが同じフォルダにある必要があります。また、要素の幅と高さは、任意の値に設定できます。
HTMLファイルもできた。でも、これだけでは動かないなぁ。どういうコードになっているのかな。
Q3.このpong.jsの動作について、コメントを分かりやすく追加して
A.はい、コメントを追加して、PONGゲームの動作をさらに分かりやすく説明してみましょう。
// ゲームの初期化
var canvas = document.getElementById("canvas"); // canvas要素を取得
var ctx = canvas.getContext("2d"); // canvasの2Dコンテキストを取得
var ball = { x: canvas.width/2, y: canvas.height/2, dx: 5, dy: 5, radius: 10 }; // ボールの初期位置と速度、半径
var paddle = { x: canvas.width/2, y: canvas.height-20, width: 80, height: 10 }; // パドルの初期位置とサイズ
var leftPressed = false; // 左キーが押されているかどうかのフラグ
var rightPressed = false; // 右キーが押されているかどうかのフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーが押された時の処理
function keyDownHandler(e) {
if(e.keyCode == 37) { // 左キー
leftPressed = true;
}
else if(e.keyCode == 39) { // 右キー
rightPressed = true;
}
}
// キーが離された時の処理
function keyUpHandler(e) {
if(e.keyCode == 37) { // 左キー
leftPressed = false;
}
else if(e.keyCode == 39) { // 右キー
rightPressed = false;
}
}
// ボールを描画する関数
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2); // 円を描画
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// パドルを描画する関数
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddle.x - paddle.width/2, paddle.y, paddle.width, paddle.height); // 長方形を描画
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// ゲームループの関数
function draw() {
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁に当たった場合は反射
if(ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
}
if(ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
}
else if(ball.y + ball.radius > canvas.height) { // 下側の壁に当たった場合はゲームオーバー
alert("GAME OVER");
document.location.reload(); // ページをリロードしてリセット
}
// パドルとの衝突判定
if(ball.y + ball.dy >
どうみても、コードが最後までない。
Q4.pong.jsは、draw()が途中になっています。最後まで記述してください
A.すみません、前回の回答の最後の部分が切れていました。以下が、PONGゲームのdraw()関数の最後の部分です。
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
ball.dy = -ball.dy;
}
// パドルの移動
if(leftPressed && paddle.x > paddle.width/2) {
paddle.x -= 7;
}
else if(rightPressed && paddle.x < canvas.width - paddle.width/2) {
paddle.x += 7;
}
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ボールとパドルを描画
drawBall();
drawPaddle();
// 次のフレームを描画
requestAnimationFrame(draw);
}
// ゲームを開始する
draw();
draw()関数の最後に、requestAnimationFrame()を呼び出して、次のフレームを描画するようにしています。これにより、ゲームループが実現されます。また、clearRect()を使用して、前のフレームで描画されたボールとパドルを消去しています。最後に、drawBall()とdrawPaddle()を呼び出して、ボールとパドルを描画しています。
requestAnimationFrame()は、ブラウザが次の再描画をする前に、アニメーションを更新するために使用されるメソッドです。これにより、フレームレートをブラウザに任せることができ、よりスムーズなアニメーションが実現されます。
手動で修正
と、ここまで作ってコードを結合しても、ちゃんと動かない。そこで、コードを手動で修正。
「else if」であるべきところが「if」になってる。インデントもちょっとおかしい。
これでゲームが遊べるようになったけど、すぐにゲームオーバーになるので、ボールの初期値を修正。
だいたい、ここまでで30分くらい。
pong.jsの完全版はこちら。
// JS PONG Game for single player by ChatGPT and Me
// ゲームの初期化
var canvas = document.getElementById("canvas"); // canvas要素を取得
var ctx = canvas.getContext("2d"); // canvasの2Dコンテキストを取得
var ball = { x: canvas.width/2, y: canvas.height/2, dx: 5, dy: -5, radius: 10 }; // ボールの初期位置と速度、半径
var paddle = { x: canvas.width/2, y: canvas.height-20, width: 80, height: 10 }; // パドルの初期位置とサイズ
var leftPressed = false; // 左キーが押されているかどうかのフラグ
var rightPressed = false; // 右キーが押されているかどうかのフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーが押された時の処理
function keyDownHandler(e) {
if(e.keyCode == 37) { // 左キー
leftPressed = true;
}
else if(e.keyCode == 39) { // 右キー
rightPressed = true;
}
}
// キーが離された時の処理
function keyUpHandler(e) {
if(e.keyCode == 37) { // 左キー
leftPressed = false;
}
else if(e.keyCode == 39) { // 右キー
rightPressed = false;
}
}
// ボールを描画する関数
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2); // 円を描画
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// パドルを描画する関数
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddle.x - paddle.width/2, paddle.y, paddle.width, paddle.height); // 長方形を描画
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// ゲームループの関数
function draw() {
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁に当たった場合は反射
if(ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
} else if(ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
} else if(ball.y + ball.radius > canvas.height) {
// 下側の壁に当たった場合はゲームオーバー
alert("GAME OVER");
document.location.reload(); // ページをリロードしてリセット
}
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
ball.dy = -ball.dy;
}
// パドルの移動
if(leftPressed && paddle.x > paddle.width/2) {
paddle.x -= 7;
} else if(rightPressed && paddle.x < canvas.width - paddle.width/2) {
paddle.x += 7;
}
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ボールとパドルを描画
drawBall();
drawPaddle();
// 次のフレームを描画
requestAnimationFrame(draw);
}
// ゲームを開始する
draw();
Q5.このpong.jsとHTMLファイルでは、白い画面しか表示されません。
このpong.jsとHTMLファイルでは、白い画面しか表示されません。ゲームの背景を明るい灰色、ボールを黄色、パドルを白、HTMLファイルの背景を濃い灰色になるよう、pong.jsとHTMLファイルを作成してください。HTMLファイルのファイル名はindex.htmlです。
A. pong.jsファイルに以下のように変更を加え、背景色と描画色を指定するようにします。
// キャンバスの背景色
ctx.fillStyle = '#f2f2f2';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// ボールの描画色
ctx.fillStyle = '#f1c40f';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
// パドルの描画色
ctx.fillStyle = '#fff';
ctx.fillRect(paddle.x - paddle.width/2, canvas.height - paddle.height, paddle.width, paddle.height);
次に、index.htmlファイルに以下のように変更を加え、背景色を指定します。
<!DOCTYPE html>
<html>
<head>
<title>PONG Game</title>
</head>
<body style="background-color: #222;">
<canvas id="myCanvas" width="480" height="320"></canvas>
<script src="pong.js"></script>
</body>
</html>
bodyタグにstyle属性を追加し、背景色を濃い灰色に指定しています。また、キャンバスの背景色はpong.jsファイル内で指定しています。
以上の変更を加えた後、index.htmlファイルをブラウザで開くと、背景色と描画色が変更されたPONGゲームが表示されるはずです。
なんか怪しいような気もするが、色合いを調整して反映。
Q6.JavaScriptでは、keycodeの使用が非奨励となっているため、次のコードを奨励されている形式に書き直して
let leftPressed = false; // 左キーが押されているかどうかのフラグ
let rightPressed = false; // 右キーが押されているかどうかのフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーが押された時の処理
function keyDownHandler(e) {
if(e.keyCode == 37) { // 左キー
leftPressed = true;
}
else if(e.keyCode == 39) { // 右キー
rightPressed = true;
}
}
A.次のように、keycodeの代わりにkeyを使用して書き直すことができます。
let leftPressed = false; // 左キーが押されているかどうかのフラグ
let rightPressed = false; // 右キーが押されているかどうかのフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーが押された時の処理
function keyDownHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = true;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = true;
}
}
// キーが離された時の処理
function keyUpHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = false;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = false;
}
}
これにより、キーコードを使用する代わりに、キーの名前を使用して、キーハンドラー関数を書くことができます。また、キーが離された時の処理を追加することも忘れないでください。
コメント欄で指摘を受けたので修正。へたに調べるより、聞いたほうが早いゾ。キーを離したときに処理まで指摘してされた。
Q7.(さらに改良)次のコードのように一人用PONGゲームがあります。このゲームで、paddleに当たる位置によってballの方向が変わるようにするには、コードのどこを修正すればいいですか。
// JS PONG Game for single player by ChatGPT and Me
// ゲームの初期化
let canvas = document.getElementById("canvas"); // canvas要素を取得
let ctx = canvas.getContext("2d"); // canvasの2Dコンテキストを取得
let ball = { x: canvas.width/2, y: canvas.height/2, dx: 5, dy: -5, radius: 10 }; // ボールの初期位置と速度、半径
let paddle = { x: canvas.width/2, y: canvas.height-20, width: 80, height: 10 }; // パドルの初期位置とサイズ
let leftPressed = false; // 左キーが押されているかどうかのフラグ
let rightPressed = false; // 右キーが押されているかどうかのフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// キーが押された時の処理
function keyDownHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = true;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = true;
}
}
// キーが離された時の処理
function keyUpHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = false;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = false;
}
}
// 背面を描画する関数
function drawBackground() {
ctx.fillStyle = '#f2f2f2';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// ボールを描画する関数
function drawBall() {
ctx.fillStyle = '#f1c40f';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
// パドルを描画する関数
function drawPaddle() {
ctx.beginPath();
ctx.fillStyle = '#ccc';
ctx.fillRect(paddle.x - paddle.width/2, canvas.height - paddle.height, paddle.width, paddle.height);
ctx.closePath();
}
// ゲームループの関数
function draw() {
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁に当たった場合は反射
if(ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
} else if(ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
} else if(ball.y + ball.radius > canvas.height) {
// 下側の壁に当たった場合はゲームオーバー
alert("GAME OVER");
document.location.reload(); // ページをリロードしてリセット
}
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
ball.dy = -ball.dy;
}
// パドルの移動
if(leftPressed && paddle.x > paddle.width/2) {
paddle.x -= 7;
} else if(rightPressed && paddle.x < canvas.width - paddle.width/2) {
paddle.x += 7;
}
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ゲーム要素を描画
drawBackground();
drawBall();
drawPaddle();
// 次のフレームを描画
requestAnimationFrame(draw);
}
// ゲームを開始する
draw();
A. ボールの移動処理の後、次の行にパドルとの衝突判定があります。
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
ball.dy = -ball.dy;
}
この部分で、ボールがパドルに当たったかどうかが判定されています。パドルの位置によってボールの反射方向を変えるには、この部分でball.dxを変更すれば良いです。
たとえば、パドルの左側に当たった場合はball.dxを負の値に、右側に当たった場合は正の値に変更することができます。具体的には、以下のようになります。
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
if (ball.x < paddle.x) { // パドルの左側に当たった場合
ball.dx = -Math.abs(ball.dx);
} else { // パドルの右側に当たった場合
ball.dx = Math.abs(ball.dx);
}
ball.dy = -ball.dy;
}
このようにすると、パドルの左側に当たった場合はボールが左に反射し、右側に当たった場合はボールが右に反射します。
Q.8このプログラムのHTMLファイルは次のようになっています。ゲームの開始・停止・再開ボタンを追加するにはどうすればいいですか。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>gpt-pong</title>
<style>
canvas {
border: 1px solid #505050;
}
</style>
</head>
<body style="background-color: #b8b8b8;">
<h1>gpt-pong</h1>
<canvas id="canvas" width="480" height="320"></canvas>
<script src="pong.js"></script>
<p><a href="https://github.com/ycatch/gpt-pong">Source code</a></p>
</body>
</html>
A. ゲームの開始・停止・再開ボタンを追加するには、以下の手順に従ってください。
HTMLファイルに、ボタンを追加するための要素を作成します。例えば、以下のようにします。
<button id="start-button">Start</button>
<button id="stop-button">Stop</button>
<button id="resume-button">Resume</button>
JavaScriptファイルに、ボタンをクリックしたときに呼び出される関数を追加します。たとえば、以下のようにします。
document.getElementById("start-button").addEventListener("click", function(){
startGame();
});
document.getElementById("stop-button").addEventListener("click", function(){
stopGame();
});
document.getElementById("resume-button").addEventListener("click", function(){
resumeGame();
});
JavaScriptファイルに、ボタンを押したときに呼び出される関数を実装します。以下は、startGame、stopGame、resumeGameの例です。
function startGame() {
// ゲームを開始するための処理を実装します。
}
function stopGame() {
// ゲームを停止するための処理を実装します。
}
function resumeGame() {
// ゲームを再開するための処理を実装します。
}
startGame、stopGame、resumeGame関数に、ゲームの開始・停止・再開に必要な処理を追加します。
以上の手順を実行することで、ゲームの開始・停止・再開ボタンを追加することができます。
Q9.ゲームの開始・停止・再開に必要なstartGame、stopGame、resumeGame関数を書いてください
以下のように、startGame、stopGame、resumeGame関数を追加することができます。
A.ゲームの開始・停止・再開に必要なstartGame、stopGame、resumeGame関数を書いてください
以下のように、startGame、stopGame、resumeGame関数を追加することができます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>gpt-pong</title>
<style>
canvas {
border: 1px solid #505050;
}
</style>
</head>
<body style="background-color: #b8b8b8;">
<h1>gpt-pong</h1>
<canvas id="canvas" width="480" height="320"></canvas>
<script src="pong.js"></script>
<p><a href="https://github.com/ycatch/gpt-pong">Source code</a></p>
<button onclick="startGame()">Start Game</button>
<button onclick="stopGame()">Stop Game</button>
<button onclick="resumeGame()">Resume Game</button>
<script>
var intervalId;
function startGame() {
if (!intervalId) {
intervalId = setInterval(update, 10);
}
}
function stopGame() {
clearInterval(intervalId);
intervalId = null;
}
function resumeGame() {
if (!intervalId) {
intervalId = setInterval(update, 10);
}
}
</script>
</body>
</html>
これにより、画面にStart Game、Stop Game、Resume Gameの3つのボタンが追加され、それぞれがstartGame、stopGame、resumeGame関数を呼び出します。また、intervalIdという変数を使用して、ゲームの更新を停止、再開することができます。
Q10.setInterval(update, 10)の役割を教えて
A.setInterval(update, 10) は、10ミリ秒ごとに update 関数を呼び出すように設定するメソッドです。このメソッドは、ゲームのループを作成するために使用されます。
具体的には、ゲーム内の状態を更新し、描画を更新するために update 関数が呼び出されます。10ミリ秒ごとに update 関数が呼び出されるため、ゲームは60FPSで実行されます(1秒あたり1000ミリ秒 / 10ミリ秒 = 100、1秒あたり100回呼び出されるため、60FPSになります)。
したがって、 setInterval(update, 10) を使用することで、定期的に update 関数を呼び出すことができ、ゲームを実行することができます。
Q11.一人用PONGゲームにはupdate関数はありません。setIntervalでどの関数を呼び出せばいいですか
A.一人用PONGゲームでは、update() 関数の代わりに gameLoop() 関数が用意されています。
setInterval() メソッドで gameLoop() 関数を繰り返し実行することができます。以下のようにコードを書き換えることができます。
// gameLoop() 関数を定義する
function gameLoop() {
movePaddle();
moveBall();
collisionDetection();
draw();
}
// setInterval() メソッドで gameLoop() 関数を繰り返し実行する
setInterval(gameLoop, 10);
これにより、gameLoop() 関数が10ミリ秒ごとに繰り返し実行されるようになります。
手動で修正
setIntervalで呼び出す関数名は、drawなので手動で修正。
また、drawを繰り返し実行する方法も変更。
// JS PONG Game for single player by ChatGPT and Me
// ゲームの初期化
let canvas = document.getElementById("canvas"); // canvas要素を取得
let ctx = canvas.getContext("2d"); // canvasの2Dコンテキストを取得
let ball = { x: canvas.width/2, y: canvas.height/2, dx: 5, dy: -5, radius: 10 }; // ボールの初期位置と速度、半径
let paddle = { x: canvas.width/2, y: canvas.height-20, width: 80, height: 10 }; // パドルの初期位置とサイズ
let leftPressed = false; // 左キーが押されているかどうかのフラグ
let rightPressed = false; // 右キーが押されているかどうかのフラグ
let intervalId; //開始・停止・再開のフラグ
// キーイベントのリスナーを追加
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
// ボタンイベントのリスナーを追加
document.getElementById("start-button").addEventListener("click", function(){
startGame();
});
document.getElementById("stop-button").addEventListener("click", function(){
stopGame();
});
document.getElementById("resume-button").addEventListener("click", function(){
resumeGame();
});
// キーが押された時の処理
function keyDownHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = true;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = true;
}
}
// キーが離された時の処理
function keyUpHandler(e) {
if(e.key === "ArrowLeft") { // 左キー
leftPressed = false;
}
else if(e.key === "ArrowRight") { // 右キー
rightPressed = false;
}
}
// ボタンが押された時の処理
// ゲームを開始
function startGame() {
if (!intervalId) {
intervalId = setInterval(draw, 10);
}
}
// ゲームを停止
function stopGame() {
clearInterval(intervalId);
intervalId = null;
}
// ゲームを再開
function resumeGame() {
if (!intervalId) {
intervalId = setInterval(draw, 10);
}
}
// 背面を描画する関数
function drawBackground() {
ctx.fillStyle = '#f2f2f2';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
// ボールを描画する関数
function drawBall() {
ctx.fillStyle = '#f1c40f';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
}
// パドルを描画する関数
function drawPaddle() {
ctx.beginPath();
ctx.fillStyle = '#ccc';
ctx.fillRect(paddle.x - paddle.width/2, canvas.height - paddle.height, paddle.width, paddle.height);
ctx.closePath();
}
// ゲームループの関数
function draw() {
// ボールの移動
ball.x += ball.dx;
ball.y += ball.dy;
// 壁に当たった場合は反射
if(ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
} else if(ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
} else if(ball.y + ball.radius > canvas.height) {
// 下側の壁に当たった場合はゲームオーバー
alert("GAME OVER");
document.location.reload(); // ページをリロードしてリセット
}
// パドルとの衝突判定
if(ball.y + ball.dy > canvas.height - ball.radius - paddle.height && ball.x > paddle.x - paddle.width/2 && ball.x < paddle.x + paddle.width/2) {
if (ball.x < paddle.x) { // パドルの左側に当たった場合
ball.dx = -Math.abs(ball.dx);
} else { // パドルの右側に当たった場合
ball.dx = Math.abs(ball.dx);
}
ball.dy = -ball.dy;
}
// パドルの移動
if(leftPressed && paddle.x > paddle.width/2) {
paddle.x -= 7;
} else if(rightPressed && paddle.x < canvas.width - paddle.width/2) {
paddle.x += 7;
}
// 画面のクリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ゲーム要素を描画
drawBackground();
drawBall();
drawPaddle();
}
CSSフレームワークを適用
さらに、手動でCSSフレームワークのmilligramを適用。こういうのは自分でやったほうが早いかな。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
<title>gpt-pong</title>
<style>
canvas {
border: 1px solid #505050;
}
</style>
</head>
<body style="background-color:white;">
<div class="container">
<div class="row">
<div class="column column-100">
<h1>gpt-pong</h1>
<canvas id="canvas" width="480" height="320"></canvas>
</div>
</div>
<div class="row">
<div class="column column-100">
<button id="start-button">Start</button>
<button id="stop-button">Stop</button>
<button id="resume-button">Resume</button>
<hr>
<p><a href="https://github.com/ycatch/gpt-pong">Source code</a></p>
<script src="pong.js"></script>
</div>
</div>
</div>
</body>
</html>
感想
-
ここまで出来るのはすごい。
-
コードの出力量に制限があるみたいで、完全版が出力されない場合が多々ある。
-
ある程度コードを把握して自分で組み立てる羽目になった。
-
else ifが漏れるのはなんでやねん。
-
あと、varで宣言されてた。直すのを忘れていた。
-
このあとブロック崩しに進化させようとしたけど、コードの断片しか出力してくれない。
-
アプリ開発ツールの中に組み込んで、コードリポジトリの一部みたいに使うのは有効そう
-
ノーコードというかローコードツールだね
関連ページ
- chatGPTにぷよぷよを作らせてみた。 - Qiita
https://qiita.com/gatuwo_jp/items/a2c63c960c3c9480a91e - GPT-4を使って ぷよぷよ 作ってみたときの感想
https://zenn.dev/corocn/articles/b4c473ed779935