Seventh JavaScript Project: Creating the Pong Game
Welcome back to our JavaScript project series! Today, we are diving into the creation of a classic arcade game - PONG. Originally developed in 1972, this game is simple yet excellent for testing and refining our skills in HTML, CSS, and, most importantly, JavaScript.
What Will We Learn
Getting Started
Introduction to the Pong Game
Pong is a game where two players control paddles on either side of a rectangular canvas. The ball moves back and forth, and the goal is for players to bounce the ball back towards their opponent. Each player earns points when they overcome their opponent. The objective is to reach a specific score first.
Code in Action
Without further ado, let's dive into the code and start building our version of the Pong game in JavaScript. Below, you'll find the complete code for HTML, CSS, and JavaScript.
HTML (index.html)
First, we will create our classic HTML structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>PONG Game</title>
</head>
<body>
<!-- Game Menu -->
<div id="menu">
<label for="difficulty">Choose difficulty:</label>
<select id="difficulty" name="difficulty">
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
<label for="mode">Choose mode:</label>
<select id="mode" name="mode">
<option value="single">Computer</option>
<option value="multi">Player</option>
</select>
<button onclick="startGame()">Start Game</button>
</div>
<!-- Game Canvas -->
<canvas id="pongCanvas" width="600" height="400" style="display:none;"></canvas>
<!-- JavaScript File -->
<script src="script.js"></script>
</body>
</html>
Description:
CSS (style.css)
We will continue with the styles
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
}
canvas {
border: 2px solid #fff;
}
#menu {
text-align: center;
color: #fff;
margin-bottom: 20px;
}
label, select, button {
margin: 5px;
}
This CSS file defines basic styles for the body, canvas, and game menu elements to ensure a visually appealing and centered layout. If you have any specific styling preferences or additional elements to describe, feel free to let me know!
JavaScript (script.js)
First we write the constants
Constants:
canvas and ctx:
// Get the reference to the game canvas and its 2D context
const canvas = document.getElementById('pongCanvas');
const ctx = canvas.getContext('2d');
The canvas constant represents the HTML canvas element where the game is rendered, and ctx is its 2D rendering context.
paddleSpeed, ballSpeed, and winningScore:
// Set the speed of paddles, ball, and winning score
const paddleSpeed = 5;
const ballSpeed = 3;
const winningScore = 5;
These constants define the speed of the paddles (paddleSpeed), the speed of the ball (ballSpeed), and the score needed to win the game (winningScore).
Variables:
Paddles and Ball:
// Vertical position of the left and right paddles
let leftPaddleY = 160;
let rightPaddleY = 160;
// Speed of movement for the left and right paddles
let leftPaddleVelocity = 0;
let rightPaddleVelocity = 0;
// Position of the ball on the canvas
let ballX = 300;
let ballY = 200;
// Speed of movement for the ball on the x and y axes
let ballXSpeed = ballSpeed;
let ballYSpeed = ballSpeed;
These variables define the position and movement speed of paddles and the ball on the canvas. leftPaddleY and rightPaddleY represent the vertical positions of the left and right paddles. leftPaddleVelocity and rightPaddleVelocity store the movement speed of the paddles. ballX and ballY specify the position of the ball, and ballXSpeed and ballYSpeed represent its movement speed on the x and y axes.
Scores and Difficulty:
// Scores of the left and right players
let leftPlayerScore = 0;
let rightPlayerScore = 0;
// Difficulty of artificial intelligence
let aiDifficulty = 0.1;
// Indicates whether the second player is controlled by the computer
let player2IsComputer = false;
Variables leftPlayerScore and rightPlayerScore store the current scores of the left and right players. aiDifficulty sets the difficulty of artificial intelligence in single-player mode. player2IsComputer indicates whether the second player (right player) is controlled by the computer.
Others:
let gameStarted = false;
The variable gameStarted indicates whether the game is running or in menu mode.
领英推荐
Event Listeners:
// Event listener for keydown events
document.addEventListener('keydown', (event) => {
if (gameStarted) {
if (event.key === 'ArrowUp') {
// Move the right paddle up
rightPaddleVelocity = -paddleSpeed;
} else if (event.key === 'ArrowDown') {
// Move the right paddle down
rightPaddleVelocity = paddleSpeed;
} else if (event.key === 'w') {
// Move the left paddle up
leftPaddleVelocity = -paddleSpeed;
} else if (event.key === 's') {
// Move the left paddle down
leftPaddleVelocity = paddleSpeed;
}
}
});
// Event listener for keyup events
document.addEventListener('keyup', (event) => {
if (gameStarted) {
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
// Stop vertical movement of the right paddle
rightPaddleVelocity = 0;
} else if (event.key === 'w' || event.key === 's') {
// Stop vertical movement of the left paddle
leftPaddleVelocity = 0;
}
}
});
These event listeners are responsible for handling keyboard events. When a key is pressed (keydown), the code checks if the game is started (gameStarted) and then adjusts the velocity of the paddles accordingly. The keys 'ArrowUp' and 'ArrowDown' control the right paddle, while 'w' and 's' control the left paddle.
When a key is released (keyup), the corresponding paddle's velocity is set to 0, stopping its movement.
These event listeners contribute to the interactivity of the game by allowing players to control the paddles using the arrow keys and 'w' and 's' keys.
Function startGame():
function startGame() {
// Get elements for difficulty and game mode
const difficultySelect = document.getElementById('difficulty');
const modeSelect = document.getElementById('mode');
// Set the difficulty based on the selection
switch (difficultySelect.value) {
case 'easy':
aiDifficulty = 0.1;
break;
case 'medium':
aiDifficulty = 0.5;
break;
case 'hard':
aiDifficulty = 0.9;
break;
default:
aiDifficulty = 0.1;
}
// Determine if the second player is controlled by the computer
player2IsComputer = modeSelect.value === 'single';
// Start the game
gameStarted = true;
// Hide the menu and display the canvas
document.getElementById('menu').style.display = 'none';
document.getElementById('pongCanvas').style.display = 'block';
// Start the game loop
gameLoop();
}
The startGame() function performs the following steps:
This function serves as the initialization of the game and transition from the menu to the game canvas.
Function update():
function update() {
// Update paddle positions
leftPaddleY += leftPaddleVelocity;
rightPaddleY += rightPaddleVelocity;
// Update ball position
ballX += ballXSpeed;
ballY += ballYSpeed;
// Reflect the ball if it hits the top or bottom of the canvas
if (ballY < 0 || ballY > canvas.height) {
ballYSpeed = -ballYSpeed;
}
// Check if the ball passed the left paddle
if (ballX < 0) {
if (ballY > leftPaddleY && ballY < leftPaddleY + 80) {
// Reflect the ball if it hits the left paddle
ballXSpeed = -ballXSpeed;
} else {
// Reset the ball position, increase the right player's score, and check for a win
ballX = canvas.width / 2;
ballY = canvas.height / 2;
rightPlayerScore++;
checkWin();
}
}
// Check if the ball passed the right paddle
if (ballX > canvas.width) {
if (ballY > rightPaddleY && ballY < rightPaddleY + 80) {
// Reflect the ball if it hits the right paddle
ballXSpeed = -ballXSpeed;
} else {
// Reset the ball position, increase the left player's score, and check for a win
ballX = canvas.width / 2;
ballY = canvas.height / 2;
leftPlayerScore++;
checkWin();
}
}
// Ensure paddles stay within the canvas boundaries
if (leftPaddleY < 0) {
leftPaddleY = 0;
} else if (leftPaddleY > canvas.height - 80) {
leftPaddleY = canvas.height - 80;
}
if (rightPaddleY < 0) {
rightPaddleY = 0;
} else if (rightPaddleY > canvas.height - 80) {
rightPaddleY = canvas.height - 80;
}
// If playing against the computer, update the AI for the right paddle
if (player2IsComputer) {
// Right paddle AI
if (ballXSpeed > 0 && ballX > canvas.width / 2) {
if (Math.random() < aiDifficulty) {
if (ballY > rightPaddleY + 40) {
rightPaddleVelocity = paddleSpeed;
} else if (ballY < rightPaddleY + 40) {
rightPaddleVelocity = -paddleSpeed;
} else {
rightPaddleVelocity = 0;
}
}
} else {
rightPaddleVelocity = 0;
}
}
// Draw the updated game state
draw();
}
The update() function handles the movement and interaction of paddles and the ball during each frame of the game. It also checks for collisions, updates scores, and ensures that paddles stay within the canvas boundaries. Additionally, if playing against the computer, it updates the AI for the right paddle based on the ball's position.
Function checkWin():
function checkWin() {
// Check if players have reached the winning score
if (leftPlayerScore === winningScore || rightPlayerScore === winningScore) {
// Display the winning player using an alert
alert(leftPlayerScore === winningScore ? "Left player wins!" : "Right player wins!");
// Reset the game to its default state
leftPlayerScore = 0;
rightPlayerScore = 0;
gameStarted = false;
// Display the menu and hide the canvas
document.getElementById('menu').style.display = 'block';
document.getElementById('pongCanvas').style.display = 'none';
}
}
Description of the checkWin() function:
This function ensures that the game is reset upon reaching the winning score, and players are informed about the winner. Its invocation is placed in the update() and startGame() functions at the appropriate locations where win checking is needed.
Function draw():
function draw() {
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw paddles
ctx.fillStyle = '#fff';
ctx.fillRect(0, leftPaddleY, 10, 80); // Left paddle
ctx.fillRect(canvas.width - 10, rightPaddleY, 10, 80); // Right paddle
// Draw ball
ctx.beginPath();
ctx.arc(ballX, ballY, 10, 0, Math.PI * 2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.closePath();
// Draw score
ctx.font = '30px Arial';
ctx.fillText(leftPlayerScore + ' - ' + rightPlayerScore, canvas.width / 2 - 30, 30);
}
Description of the draw() function:
This function is called within the update function to redraw the game elements and scores after each update. It ensures that the visual representation of the game is continuously updated on the canvas.
Function gameLoop():
function gameLoop() {
if (gameStarted) {
// Game update
update();
// Recursive call to gameLoop for the next animation frame
requestAnimationFrame(gameLoop);
}
}
Description of the gameLoop() function:
This function establishes an ongoing cycle for updating and rendering the game. It starts when the game is initiated and continues until the game is ended.
Conclusion:
In this article, we've created a simple yet enjoyable Pong game using HTML, CSS, and JavaScript. Through our code, players can choose the game difficulty, play mode, and initiate an endless cycle of game updates and rendering. Players can either compete against a computer opponent with varying difficulty levels or play against each other on a single device.
We've learned to work with HTML to structure the page, CSS for a basic visual design, and, most importantly, JavaScript for implementing the game logic. Through various functions, event listeners, and the gameLoop cycle, we've ensured smooth gameplay and continuous updating of the game state.
This project not only provides entertainment but also serves as an excellent foundation for further expansion and improvement. You can add more features, enhance the design, or even implement a multiplayer networked game.
We hope you enjoyed the process of creating the Pong game and that this article has provided valuable insights for further exploration into the world of game development using web technologies. Happy coding!
You can find the complete code here GitHub