Chapter 6: Level Up: Adding Complexity to Your Games

Using Functions to Organize Code

As your games become more complex, organizing your code becomes essential for maintaining clarity and efficiency. This chapter explores how to use functions in JavaScript to structure and modularize your game code effectively.

Start by setting up your HTML file with a <canvas> element where you’ll continue developing your game. Create a new file named index.html and include the following code:

html

<!DOCTYPE html>
<html>
<head>
<title>Level Up: Adding Complexity to Your Games</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<h1>Using Functions to Organize Code</h1>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script src="script.js"></script>
</body>
</html>

In this code, the <canvas> element is given an ID of gameCanvas and dimensions of 800 pixels width and 600 pixels height. This provides a drawing surface on your web page where you can render graphics and implement game mechanics using JavaScript.

Next, create a CSS file named styles.css to style your page. This file should be in the same directory as your HTML file. Here’s an example of basic styling to center the content and provide a background color:

css

body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f0f0f0;
}

h1 {
color: #333;
}

canvas {
border: 2px solid #333;
margin-top: 20px;
}

This CSS code sets the font for the entire page to Arial, centers the text, and provides a light gray background color. The heading (h1) is colored dark gray, and the <canvas> element has a solid black border to visually distinguish it.

Now, create a JavaScript file named script.js to continue developing your game using functions to organize the code. Begin by getting a reference to the canvas and its drawing context:

javascript

document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Player variables
let playerX = canvas.width / 2;
const playerY = canvas.height - 30;
const playerWidth = 50;
const playerHeight = 10;
const playerSpeed = 5;

// Ball variables
let ballX = canvas.width / 2;
let ballY = canvas.height - 60;
const ballRadius = 10;
let ballDX = 2;
let ballDY = -2;

// Control variables
let rightPressed = false;
let leftPressed = false;

// Event listeners for keyboard controls
document.addEventListener('keydown', keyDownHandler);
document.addEventListener('keyup', keyUpHandler);

function keyDownHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = true;
} else if (event.key === 'ArrowLeft') {
leftPressed = true;
}
}

function keyUpHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = false;
} else if (event.key === 'ArrowLeft') {
leftPressed = false;
}
}

// Function to draw the player paddle
function drawPlayer() {
ctx.beginPath();
ctx.rect(playerX, playerY, playerWidth, playerHeight);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}

// Function to draw the ball
function drawBall() {
ctx.beginPath();
ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}

// Function to update player position
function movePlayer() {
if (rightPressed && playerX < canvas.width - playerWidth) {
playerX += playerSpeed;
} else if (leftPressed && playerX > 0) {
playerX -= playerSpeed;
}
}

// Function to update ball position
function moveBall() {
ballX += ballDX;
ballY += ballDY;

// Ball collision detection with walls
if (ballX + ballDX > canvas.width - ballRadius || ballX + ballDX < ballRadius) {
ballDX = -ballDX;
}
if (ballY + ballDY < ballRadius) {
ballDY = -ballDY;
} else if (ballY + ballDY > canvas.height - ballRadius) {
// Ball collision with player paddle
if (ballX > playerX && ballX < playerX + playerWidth) {
ballDY = -ballDY;
} else {
// Game over condition (ball falls off the bottom)
alert('Game Over');
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}
}

// Function to draw everything on the canvas
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPlayer();
drawBall();
movePlayer();
moveBall();
requestAnimationFrame(draw);
}

draw();
});

In this JavaScript code:

  • Functions such as drawPlayer, drawBall, movePlayer, and moveBall are used to modularize different aspects of the game logic.
  • drawPlayer and drawBall handle drawing the player paddle and ball on the canvas.
  • movePlayer and moveBall update the positions of the player paddle and ball based on user input and game mechanics.
  • By organizing your code into functions, each function focuses on a specific task, improving code readability and maintainability.

Using functions allows you to modularize your game code effectively, making it easier to manage and extend as your game becomes more complex. In the next chapter, you’ll explore advanced techniques such as adding game levels, integrating sound effects, and optimizing performance to further enhance your games.

Working with Arrays and Objects

As you advance in game development, managing game elements and data becomes crucial. This chapter explores how to leverage arrays and objects in JavaScript to organize and manipulate complex game structures efficiently.

Start by setting up your HTML file with a <canvas> element where you’ll continue developing your game. Create a new file named index.html and include the following code:

html

<!DOCTYPE html>
<html>
<head>
<title>Level Up: Adding Complexity to Your Games</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<h1>Working with Arrays and Objects</h1>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script src="script.js"></script>
</body>
</html>

In this code, the <canvas> element is given an ID of gameCanvas and dimensions of 800 pixels width and 600 pixels height. This provides a drawing surface on your web page where you can render graphics and implement game mechanics using JavaScript.

Next, create a CSS file named styles.css to style your page. This file should be in the same directory as your HTML file. Here’s an example of basic styling to center the content and provide a background color:

css

body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f0f0f0;
}

h1 {
color: #333;
}

canvas {
border: 2px solid #333;
margin-top: 20px;
}

This CSS code sets the font for the entire page to Arial, centers the text, and provides a light gray background color. The heading (h1) is colored dark gray, and the <canvas> element has a solid black border to visually distinguish it.

Now, create a JavaScript file named script.js to continue developing your game using arrays and objects to manage game elements. Begin by getting a reference to the canvas and its drawing context:

javascript

document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Player object
const player = {
x: canvas.width / 2,
y: canvas.height - 30,
width: 50,
height: 10,
speed: 5
};

// Ball object
const ball = {
x: canvas.width / 2,
y: canvas.height - 60,
radius: 10,
dx: 2,
dy: -2
};

// Control variables
let rightPressed = false;
let leftPressed = false;

// Event listeners for keyboard controls
document.addEventListener('keydown', keyDownHandler);
document.addEventListener('keyup', keyUpHandler);

function keyDownHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = true;
} else if (event.key === 'ArrowLeft') {
leftPressed = true;
}
}

function keyUpHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = false;
} else if (event.key === 'ArrowLeft') {
leftPressed = false;
}
}

// Function to draw the player paddle
function drawPlayer() {
ctx.beginPath();
ctx.rect(player.x, player.y, player.width, player.height);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}

// Function to draw the ball
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
ctx.fillStyle = '#0095DD';
ctx.fill();
ctx.closePath();
}

// Function to update player position
function movePlayer() {
if (rightPressed && player.x < canvas.width - player.width) {
player.x += player.speed;
} else if (leftPressed && player.x > 0) {
player.x -= player.speed;
}
}

// Function to update ball position
function moveBall() {
ball.x += ball.dx;
ball.y += ball.dy;

// Ball collision detection with walls
if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) {
ball.dx = -ball.dx;
}
if (ball.y + ball.dy < ball.radius) {
ball.dy = -ball.dy;
} else if (ball.y + ball.dy > canvas.height - ball.radius) {
// Ball collision with player paddle
if (ball.x > player.x && ball.x < player.x + player.width) {
ball.dy = -ball.dy;
} else {
// Game over condition (ball falls off the bottom)
alert('Game Over');
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}
}

// Function to draw everything on the canvas
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPlayer();
drawBall();
movePlayer();
moveBall();
requestAnimationFrame(draw);
}

draw();
});

In this JavaScript code:

  • The player object and ball object encapsulate player and ball properties, respectively, using object literals.
  • Functions such as drawPlayer, drawBall, movePlayer, and moveBall interact with these objects to draw and update game elements.
  • Using objects allows you to encapsulate related data and behaviors, improving code organization and readability.

By leveraging arrays and objects, you can efficiently manage and manipulate game elements, making your game code more maintainable and scalable. In the next chapter, you’ll explore advanced game development techniques such as adding game levels, implementing game physics, and optimizing performance to further enhance your games.

Building a More Complex Game

As you progress in game development, you’ll encounter scenarios where complexity increases, requiring structured code and advanced techniques. This chapter delves into creating a more intricate game using JavaScript, focusing on organization and implementation strategies.

To illustrate these concepts, let’s develop a breakout-style game where you control a paddle to bounce a ball and destroy bricks. Here’s how you can structure and build this game:

Start by setting up your HTML file with a <canvas> element where you’ll develop the game. Create a new file named index.html and include the following code:

html

<!DOCTYPE html>
<html>
<head>
<title>Level Up: Adding Complexity to Your Games</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<h1>Building a More Complex Game</h1>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script src="script.js"></script>
</body>
</html>

In this HTML structure:

  • The <canvas> element with an ID of gameCanvas provides a graphical rendering area where you’ll create the game’s visuals and interactions.

Next, create a CSS file named styles.css to style your page. This file should be in the same directory as your HTML file. Here’s an example of basic styling to center the content and provide a background color:

css

body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #f0f0f0;
}

h1 {
color: #333;
}

canvas {
border: 2px solid #333;
margin-top: 20px;
}

This CSS code ensures the page content is centered, uses a readable font (Arial), and provides a light gray background. The heading (h1) is styled with a dark gray color, and the <canvas> element has a solid black border for clarity.

Now, create a JavaScript file named script.js to implement the game’s functionality. Begin by setting up the game environment, including variables for the canvas, context, paddle, ball, and bricks:

javascript

document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Constants for the paddle
const paddleWidth = 100;
const paddleHeight = 10;
const paddleColor = '#0095DD';

// Player paddle object
const playerPaddle = {
x: (canvas.width - paddleWidth) / 2,
y: canvas.height - paddleHeight - 10,
width: paddleWidth,
height: paddleHeight,
color: paddleColor,
speed: 8
};

// Constants for the ball
const ballRadius = 10;
const ballColor = '#0095DD';

// Ball object
const ball = {
x: canvas.width / 2,
y: canvas.height - 30,
radius: ballRadius,
color: ballColor,
dx: 2,
dy: -2
};

// Constants for the bricks
const brickRowCount = 3;
const brickColumnCount = 5;
const brickWidth = 75;
const brickHeight = 20;
const brickPadding = 10;
const brickOffsetTop = 30;
const brickOffsetLeft = 30;
const brickColor = '#0095DD';

// Array to hold brick objects
const bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (let r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}

// Event listeners for keyboard controls
let rightPressed = false;
let leftPressed = false;
document.addEventListener('keydown', keyDownHandler);
document.addEventListener('keyup', keyUpHandler);

function keyDownHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = true;
} else if (event.key === 'ArrowLeft') {
leftPressed = true;
}
}

function keyUpHandler(event) {
if (event.key === 'ArrowRight') {
rightPressed = false;
} else if (event.key === 'ArrowLeft') {
leftPressed = false;
}
}

// Function to draw the player paddle
function drawPlayerPaddle() {
ctx.beginPath();
ctx.rect(playerPaddle.x, playerPaddle.y, playerPaddle.width, playerPaddle.height);
ctx.fillStyle = playerPaddle.color;
ctx.fill();
ctx.closePath();
}

// Function to draw the ball
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
ctx.fillStyle = ball.color;
ctx.fill();
ctx.closePath();
}

// Function to draw bricks
function drawBricks() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status === 1) {
const brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
const brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = brickColor;
ctx.fill();
ctx.closePath();
}
}
}
}

// Function to detect collision between ball and bricks
function collisionDetection() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
const brick = bricks[c][r];
if (brick.status === 1) {
if (ball.x > brick.x && ball.x < brick.x + brickWidth && ball.y > brick.y && ball.y < brick.y + brickHeight) {
ball.dy = -ball.dy;
brick.status = 0; // Brick is destroyed
}
}
}
}
}

// Function to update player paddle position
function movePlayerPaddle() {
if (rightPressed && playerPaddle.x < canvas.width - playerPaddle.width) {
playerPaddle.x += playerPaddle.speed;
} else if (leftPressed && playerPaddle.x > 0) {
playerPaddle.x -= playerPaddle.speed;
}
}

// Function to update ball position
function moveBall() {
ball.x += ball.dx;
ball.y += ball.dy;

// Ball collision detection with walls and paddle
if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) {
ball.dx = -ball.dx;
}
if (ball.y + ball.dy < ball.radius) {
ball.dy = -ball.dy;
} else if (ball.y + ball.dy > canvas.height - ball.radius) {
// Ball collision with player paddle
if (ball.x > playerPaddle.x && ball.x < playerPaddle.x + playerPaddle.width) {
ball.dy = -ball.dy;
} else {
// Game over condition (ball falls off the bottom)
alert('Game Over');
document.location.reload();
clearInterval(interval); // Needed for Chrome to end game
}
}

// Check for collision with bricks
collisionDetection();
}

// Function to draw everything on the canvas
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawPlayerPaddle();
drawBall();
drawBricks();
movePlayerPaddle();
moveBall();
requestAnimationFrame(draw);
}

draw();
});

In this JavaScript code:

  • The playerPaddle object, ball object, and bricks array of objects manage game elements such as the paddle, ball, and bricks respectively.
  • Functions such as drawPlayerPaddle, drawBall, drawBricks, movePlayerPaddle, moveBall, and collisionDetection handle drawing, updating positions, and detecting collisions.
  • Using objects and arrays efficiently organizes and manages game data and behaviors, enhancing code structure and scalability.

This breakout-style game demonstrates how to integrate advanced concepts like collision detection, multiple game elements, and dynamic gameplay mechanics. As you continue to explore game development, consider further enhancements such as adding game levels, implementing game physics, and optimizing performance to create engaging and polished games.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *