In this blog post, we will discuss how to implement a simple Pong browser game using ChatGPT. First, we will shortly discuss the advantages and disadvantages of using ChatGPT and then introduce the code generated by ChatGPT in practice.
Vorteile
Time-saving: ChatGPT can save a lot of time as it provides a fast and easy way to generate texts or code blocks without having to write everything by hand. This is particularly useful for simple routine tasks.
Versatility: ChatGPT can be used in many different languages and contexts, making it a versatile tool. It can, for example, help with the implementation of algorithms and code documentation, as well as explain existing code.
Adaptability: ChatGPT can be adapted to specific requirements and needs and generate context-specific code.
Nachteile
Limited control: Since ChatGPT is based on machine learning, users do not have full control over what is generated. The result can sometimes be unpredictable and therefore requires additional checks.
Limited response length: ChatGPT has a maximum response length, which can be a problem when generating longer code sections or complex texts. In this case, you have to ask ChatGPT to continue, which can lead to ChatGPT “forgetting” the context – which brings us to the next disadvantage:
Limited ability to understand context: ChatGPT has difficulty understanding context and can therefore sometimes provide inaccurate or inappropriate results. It is important for users to understand how to best use ChatGPT to achieve the best possible results. Ideally, the “divide-and-conquer” principle should also be used here: the context should be kept as small as possible.
Practical example
Now let’s move on to the practical example: implementing a Pong browser game with ChatGPT.
I asked ChatGPT if it could implement a Pong game for the browser. Unfortunately, the code was longer than the maximum response length, so I had to ask ChatGPT to continue several times. I also instructed it to output only the code without description.
Here’s what the first response looked like:
<!DOCTYPE html> <html> <head> <title>Pong Game</title> <style> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="canvas" width="600" height="400"></canvas> <script src="pong.js"></script> </body> </html>
const canvas = document.getElementById("canvas"); const context = canvas.getContext("2d"); canvas.width = 800; canvas.height = 600; let player1 = { x: 20, y: canvas.height / 2 - 50, width: 10, height: 100, score: 0, }; let player2 = { x: canvas.width - 30, y: canvas.height / 2 - 50, width: 10, height: 100, score: 0, }; let ball = { x: canvas.width / 2, y: canvas.height / 2, radius: 10, speed: 7, dx: 7, dy: -7, }; function drawNet() { context.fillStyle = "#FFF"; for (let i = 0; i <= canvas.height; i += 15) { context.fillRect(canvas.width / 2 - 1, i, 2, 10); } } function drawRect(x, y, w, h, color) { context.fillStyle = color; context.fillRect(x, y, w, h); } function drawCircle(x, y, r, color) { context.fillStyle = color; context.beginPath(); context.arc(x, y, r, 0, Math.PI * 2, false); context.closePath(); context.fill(); } function drawText(text, x, y, color) { context.fillStyle = color; context.font = "45px fantasy"; context.fillText(text, x, y); } function draw() { drawRect(0, 0, canvas.width, canvas.height, "#000"); drawRect(player1.x, player1.y, player1.width, player1.height, "#FFF"); drawRect( player2.x, player2.y, player2.width, player2.height, "#FFF" ); drawCircle(ball.x, ball.y, ball.radius, "#FFF"); drawNet(); } function ballWallCollision() { if (ball.y + ball.radius > canvas.height || ball.y - ball.radius < 0) { ball.dy = -ball.dy; } } function ballPaddleCollision(player) { if ( ball.x + ball.radius > player.x && ball.x - ball.radius < player.x + player.width && ball.y + ball.radius > player.y && ball.y - ball.radius < player.y + player.height ) { let collidePoint = ball.y - (player.y + player.height / 2); collidePoint = collidePoint / (player.height / 2); let angleRad = (Math.PI / 4) * collidePoint; let direction = ball.x + ball.radius < canvas.width / 2 ? 1 : -1; ball.dx = direction * ball.speed * Math.cos(angleRad); ball.dy = ball.speed * Math.sin(angleRad); } } function resetBall() { ball.x = canvas.width / 2; ball.y = canvas.height / 2; ball.speed = 7; ball.dx = ball.speed; ball.dy = -ball.speed; } function drawScore() { context.font = "32px Arial"; context.fillText(player1.score, 100, 50); context.fillText(player2.score, canvas.width - 100, 50); } function checkGameOver() { if (player1.score === maxScore || player2.score === maxScore) { let winner = player1.score === maxScore ? "Player 1" : "Player 2"; alert(`${winner} wins!`); player1.score = 0; player2.score = 0; } } function update() { ball.x += ball.dx; ball.y += ball.dy; ballWallCollision(); ballPaddleCollision(player1); ballPaddleCollision(player2); if (ball.x - ball.radius < 0) { player2.score++; resetBall(); } else if (ball.x + ball.radius > canvas.width) { player1.score++; resetBall(); } checkGameOver(); } function game() { update(); draw(); } let maxScore = 3; canvas.addEventListener("mousemove", (event) => { let rect = canvas.getBoundingClientRect(); player1.y = event.clientY - rect.top - player1.height / 2; }); canvas.addEventListener("mousedown", () => { if (player1.score === maxScore || player2.score === maxScore) { player1.score = 0; player2.score = 0; } }); setInterval(game, 1000 / 60);
The code is basically functional: A game loop has been implemented, objects are being drawn, the ball is moving, and there is collision detection. However, ChatGPT forgot to implement the movement of the paddles. Additionally, a function called drawScore() has been implemented but it is not being called anywhere.
So, it is necessary to make some improvements:
The code is missing the movement of the paddle. The paddles should be able to move using the keyboard. Please show only the places where code needs to be modified.
function movePaddle(evt) { let rect = canvas.getBoundingClientRect(); if (evt.clientY - rect.top - player1.height / 2 > 0 && evt.clientY - rect.top + player1.height / 2 < canvas.height) { player1.y = evt.clientY - rect.top - player1.height / 2; } } function movePaddleUp() { player1.y -= 10; } function movePaddleDown() { player1.y += 10; } document.addEventListener("keydown", function (evt) { switch (evt.key) { case "w": movePaddleUp(); break; case "s": movePaddleDown(); break; } });
Here it seems like I was a bit too vague – while the paddle movement for player 1 was implemented, it is missing for player 2. So, let’s keep improving:
Please implement the same for player 2 as well. The paddle should be moved with the "arrow up" and "arrow down" keys.
function movePaddleUp(player) { player.y -= 10; } function movePaddleDown(player) { player.y += 10; } document.addEventListener("keydown", function (evt) { switch (evt.key) { case "w": movePaddleUp(player1); break; case "s": movePaddleDown(player1); break; case "ArrowUp": movePaddleUp(player2); break; case "ArrowDown": movePaddleDown(player2); break; } });
That looks better now. Now I asked ChatGPT to implement a start button which allows the game to be started and restarted with a button click at the beginning and end of the game. Again, ChatGPT should only output the relevant changes:
<!DOCTYPE html> <html> <head> <title>Pong Game</title> <style> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="canvas" width="600" height="400"></canvas> <button id="startButton">Start</button> <script src="pong.js"></script> </body> </html>
let canvas = document.getElementById("canvas"); let ctx = canvas.getContext("2d"); let startButton = document.getElementById("startButton"); startButton.addEventListener("click", startGame); let gameStarted = false; // Restlicher Code hier function checkGameOver() { if (player1.score === maxScore || player2.score === maxScore) { let winner = player1.score === maxScore ? "Player 1" : "Player 2"; alert(`${winner} wins!`); player1.score = 0; player2.score = 0; startButton.disabled = false; gameStarted = false; } } function startGame() { gameStarted = true; startButton.disabled = true; } function game() { if (!gameStarted) { return; } update(); draw(); }
The game is now basically playable. However, in terms of usability and code itself, we still have some way to go to reach our goal. But let’s ask ChatGPT what he would optimize in the code:
The movement of the paddles is limited to moving up or down by 10 pixels. This can result in relatively slow movement. To improve the responsiveness of the game, one could increase the step by which the paddles move to make them move faster.
The game ends abruptly as soon as a player reaches the maximum score. However, it could be more meaningful to give players a chance to know who won the last game before the game is fully over. One way to do this would be to pause the game for a certain number of seconds and display the name of the winner on the screen.
The code could be better organized by splitting some of the functions into separate files. For example, all functions related to drawing objects on the canvas could be placed in one file and imported from there. This would make the main code more readable and increase maintainability.
Consider using requestAnimationFrame() to update the game loop instead of calling setInterval or setTimeout. requestAnimationFrame() is more efficient and provides better synchronization with the browser's rendering pipeline.
That sounds reasonable. However, the second point is not entirely correct – an alert() is currently called after the end of the game. But that can definitely be implemented in a more user-friendly way.
Of course, the design could also be responsive to be playable on different devices, a consistent use of “let” or “const” would be desirable. Also, there are no comments at all.
Conclusion
In summary, ChatGPT offers both advantages and disadvantages when it comes to generating program code. On the positive side, it can save time, be used in a versatile manner, and enable automated processes. On the other hand, it may have difficulties in understanding context, have limited response lengths, and offer limited control over the generated results.
To achieve the best possible results, it is important for the user to clearly define the context and guide ChatGPT through targeted requests. It is also helpful to fine-tune the output to specific requirements and needs, and carefully review the generated results. With these tips, ChatGPT can be a valuable tool for generating text and code blocks, as well as automating complex tasks.
Furthermore, as mentioned above, ChatGPT can analyze existing code and suggest optimizations.
So ChatGPT and I will continue to work on the code and keep you updated!
Leave a Reply