Why Build Games with Pure JavaScript
Creating games is one of the most engaging ways to learn JavaScript, and building a classic Breakout game provides the perfect foundation for understanding game development fundamentals. In this comprehensive guide, we'll walk through creating a fully functional 2D Breakout game using only pure JavaScript and the HTML5 Canvas API--no external libraries or frameworks required. Master game loops, collision detection, and user input handling to build interactive web experiences that captivate users.
The approach we'll take emphasizes learning the core concepts that power every game, from simple animations to complex collision systems. Starting with pure JavaScript gives you a deep understanding of how game mechanics actually work, making it easier to transition to any game framework later if you choose. These fundamentals also apply when you learn to code a website, as the same event-driven patterns and DOM manipulation skills transfer across all JavaScript projects.
The HTML5 Canvas API provides a powerful, hardware-accelerated surface for rendering 2D graphics directly in the browser. As documented in the MDN 2D Breakout Game tutorial, working with pure JavaScript and Canvas gives you complete control over every aspect of your game's behavior. This direct access means you can optimize exactly where needed and build a mental model of game development that scales to any technology stack.
Modern browsers have optimized Canvas rendering to leverage GPU acceleration, making it surprisingly performant for 2D games. The requestAnimationFrame API synchronizes your game loop with the browser's refresh rate, typically 60 frames per second, ensuring smooth animations without the complexity of managing timing manually. For more advanced animation techniques, explore the Web Animations API which provides complementary tools for declarative animations.
What You'll Learn
- HTML5 Canvas setup and configuration
- Drawing shapes (rectangles, circles) on canvas
- Implementing game loops with requestAnimationFrame
- Ball movement and trajectory physics
- Collision detection with walls, paddle, and bricks
- User input handling (keyboard and mouse)
- Score tracking and game state management
- Best practices for game performance
Table of Contents
- Why Build Games with Pure JavaScript
- Setting Up Your Development Environment
- Drawing on the Canvas
- Creating the Game Loop
- Implementing Ball Movement
- Implementing Collision Detection
- Adding User Controls
- Tracking Game Progress
- Best Practices for JavaScript Game Performance
- Extending Your Game
- Complete Code Overview
- Conclusion
Setting Up Your Development Environment
The game's HTML document structure is minimal because the entire game renders on the canvas element. Your HTML file needs a charset declaration for proper character encoding, a title, basic CSS styling, and a canvas element with an ID for JavaScript access. The canvas element requires width and height attributes to define its pixel dimensions, which become the coordinate system for all drawing operations.
As covered in the MDN Canvas tutorial, understanding these fundamentals is essential before building more complex game mechanics. If you're new to HTML, our guide on HTML websites provides a solid foundation for understanding document structure and semantic markup.
1<!DOCTYPE html>2<html lang="en-US">3 <head>4 <meta charset="utf-8" />5 <title>Gamedev Canvas Workshop</title>6 <style>7 * {8 padding: 0;9 margin: 0;10 }11 canvas {12 background: #eeeeee;13 display: block;14 margin: 0 auto;15 }16 </style>17 </head>18 <body>19 <canvas id="myCanvas" width="480" height="320"></canvas>20 <script>21 // JavaScript code goes here22 </script>23 </body>24</html>Understanding the Canvas Coordinate System
The canvas uses a coordinate system where the origin (0, 0) is at the top-left corner of the canvas. X values increase to the right, and Y values increase downward. This is different from traditional Cartesian coordinates where Y increases upward, but it's the standard for computer graphics because it matches how screens draw pixels from top to bottom.
- Origin (0, 0): Top-left corner
- X-axis: Increases to the right
- Y-axis: Increases downward
When specifying coordinates for drawing operations, all positions are relative to the canvas's coordinate system. A point at (100, 50) would be 100 pixels from the left edge and 50 pixels from the top edge. Understanding this coordinate system is essential because it affects every drawing and collision detection operation in your game.
Drawing on the Canvas
Before you can draw on the canvas, you need to obtain a reference to the canvas element and its 2D rendering context. The context provides all the methods and properties needed for drawing shapes, text, images, and other graphical elements. This two-step process separates canvas creation from drawing operations, allowing for flexible and organized code.
The CanvasRenderingContext2D API provides the complete reference for all 2D drawing operations available in the browser.
1const canvas = document.getElementById("myCanvas");2const ctx = canvas.getContext("2d");Drawing Rectangles
Use rect() to define rectangles, fillRect() to fill, or strokeRect() for outlines.
Drawing Circles
Use arc() method with radius, start angle, and end angle parameters.
Color Specification
Support for named colors, hex, RGB, RGBA, and modern CSS color syntax.
Path Management
Use beginPath() and closePath() to properly manage drawing state.
1ctx.beginPath();2ctx.rect(20, 40, 50, 50); // x, y, width, height3ctx.fillStyle = "red";4ctx.fill();5ctx.closePath();1ctx.beginPath();2ctx.arc(240, 160, 20, 0, Math.PI * 2, false);3ctx.fillStyle = "green";4ctx.fill();5ctx.closePath();6 7// Parameters:8// - x, y: Center coordinates9// - radius: Circle radius10// - startAngle: Starting angle in radians11// - endAngle: Ending angle in radians12// - counterclockwise: true/false (optional)Creating the Game Loop
A game loop is the heartbeat of any game, continuously updating game state and rendering graphics. In modern JavaScript game development, the requestAnimationFrame API is the preferred method for implementing game loops because it synchronizes with the browser's refresh rate (typically 60Hz), pauses when the tab is inactive to save battery, and provides smooth, consistent animations.
As explained in the MDN animation guide, this approach provides significant advantages over older techniques like setInterval.
1function gameLoop() {2 // Update game state3 update();4 5 // Render graphics6 draw();7 8 // Schedule next frame9 requestAnimationFrame(gameLoop);10}11 12// Start the loop13requestAnimationFrame(gameLoop);1function draw() {2 // Clear the entire canvas before each frame3 ctx.clearRect(0, 0, canvas.width, canvas.height);4 5 // Draw game elements6 drawBall();7 drawPaddle();8 drawBricks();9 drawScore();10}Implementing Ball Movement
A ball in a Breakout game requires several properties: position (x, y), velocity (dx, dy), radius, and color. Defining these as a consistent structure helps organize code and makes it easy to modify ball behavior. Starting the ball near the bottom center of the canvas, with a slight upward velocity (negative dy because Y increases downward), creates a natural starting position for gameplay.
1let ball = {2 x: canvas.width / 2,3 y: canvas.height - 30,4 dx: 2,5 dy: -2,6 radius: 10,7 color: "#0095DD"8};1// On each frame, update position by adding velocity2ball.x += ball.dx;3ball.y += ball.dy;4 5// The order matters:6// Update position first, then check for collisions7// This allows accurate boundary detectionImplementing Collision Detection
Collision detection is crucial for any game. The ball needs to bounce off walls, the paddle, and destroy bricks when hit. Each type of collision has its own logic. This collision logic uses the ball's radius to detect when the ball's edge touches a wall, not just its center point, creating more accurate collision detection.
The MDN Breakout game tutorial provides comprehensive coverage of these collision patterns and their implementation.
1function checkWallCollisions() {2 // Right and left walls3 if (ball.x + ball.dx > canvas.width - ball.radius ||4 ball.x + ball.dx < ball.radius) {5 ball.dx = -ball.dx;6 }7 8 // Top wall9 if (ball.y + ball.dy < ball.radius) {10 ball.dy = -ball.dy;11 }12 13 // Bottom wall - game over condition14 else if (ball.y + ball.dy > canvas.height - ball.radius) {15 // Check if paddle hit16 if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) {17 ball.dy = -ball.dy;18 }19 else {20 // Ball hit bottom without paddle - lose life21 lives--;22 if (!lives) {23 gameOver();24 }25 else {26 resetBall();27 }28 }29 }30}1function checkBrickCollisions() {2 for (let c = 0; c < brickColumnCount; c++) {3 for (let r = 0; r < brickRowCount; r++) {4 const brick = bricks[c][r];5 if (brick.status === 1) { // Only check active bricks6 if (ball.x > brick.x &&7 ball.x < brick.x + brickWidth &&8 ball.y > brick.y &&9 ball.y < brick.y + brickHeight) {10 ball.dy = -ball.dy;11 brick.status = 0; // Mark brick as destroyed12 score++;13 14 // Check win condition15 if (score === brickRowCount * brickColumnCount) {16 winGame();17 }18 }19 }20 }21 }22}Adding User Controls
Responding to keyboard input requires listening for keydown and keyup events. Store the state of relevant keys in boolean variables that your game loop can check. Using boolean flags for key states creates smooth, responsive movement. The paddle continues moving as long as the key remains pressed, and stops immediately when released. This approach handles multiple keys being pressed simultaneously and avoids the key-repeat delay.
1let rightPressed = false;2let leftPressed = false;3 4document.addEventListener("keydown", keyDownHandler, false);5document.addEventListener("keyup", keyUpHandler, false);6 7function keyDownHandler(e) {8 if (e.key === "Right" || e.key === "ArrowRight") {9 rightPressed = true;10 }11 else if (e.key === "Left" || e.key === "ArrowLeft") {12 leftPressed = true;13 }14}15 16function keyUpHandler(e) {17 if (e.key === "Right" || e.key === "ArrowRight") {18 rightPressed = false;19 }20 else if (e.key === "Left" || e.key === "ArrowLeft") {21 leftPressed = false;22 }23}1document.addEventListener("mousemove", mouseMoveHandler, false);2 3function mouseMoveHandler(e) {4 const relativeX = e.clientX - canvas.offsetLeft;5 if (relativeX > 0 && relativeX < canvas.width) {6 paddle.x = relativeX - paddle.width / 2;7 }8}Tracking Game Progress
Display and track the player's score and remaining lives. This creates engagement and gives players clear goals to work toward. When a life is lost, reset both the ball and paddle to their starting positions, giving the player a fresh attempt. When lives reach zero, trigger the game-over sequence and offer the option to restart.
1let score = 0;2let lives = 3;3 4function drawScore() {5 ctx.font = "16px Arial";6 ctx.fillStyle = "#0095DD";7 ctx.fillText("Score: " + score, 8, 20);8}9 10function drawLives() {11 ctx.font = "16px Arial";12 ctx.fillStyle = "#0095DD";13 ctx.fillText("Lives: " + lives, canvas.width - 65, 20);14}15 16function resetBall() {17 ball.x = canvas.width / 2;18 ball.y = canvas.height - 30;19 ball.dx = 2;20 ball.dy = -2;21 paddle.x = (canvas.width - paddle.width) / 2;22}Best Practices for JavaScript Game Performance
Building performant games requires attention to several key areas. Here are essential practices for smooth gameplay and optimal resource usage. The game loop is where most of your game's computational work happens--keep it lean by separating update logic from rendering, minimizing object creation within the loop, and using requestAnimationFrame for consistent frame timing.
Optimize Game Loop
Keep the loop lean by separating update logic from rendering.
Efficient Collision
Skip collision checks for destroyed bricks using status flags.
Avoid Garbage
Don't create new objects in the game loop to reduce GC pauses.
Handle Edge Cases
Test on different browsers, handle resize events gracefully.
Extending Your Game
Once the basic Breakout game is working, consider adding features to enhance gameplay and create a more complete experience. These extensions build on the fundamental concepts covered in this guide and demonstrate how to expand a simple game into a polished interactive application. Whether you're building for fun or as a portfolio piece, these additions show advanced understanding of game development principles.
Power-ups
Add special bricks that grant abilities like multi-ball, paddle expansion, or score multipliers.
Levels
Create progressive difficulty with faster ball speed, more brick rows, or moving obstacles.
Sound Effects
Add audio feedback for paddle hits, brick destruction, and game events.
Particle Effects
Create visual flair when bricks are destroyed for a more polished feel.
High Scores
Implement localStorage-based persistent high score tracking.
Animation Effects
Add smooth transitions, screen shake, or slow-motion effects.
Complete Code Overview
The complete Breakout game combines all the elements covered in this guide into a cohesive implementation. This structure--setup, update, draw, repeat--is the foundation of most games and will serve you well as you explore more complex game development projects.
1// Canvas setup2const canvas = document.getElementById("myCanvas");3const ctx = canvas.getContext("2d");4 5// Game variables6let x = canvas.width / 2;7let y = canvas.height - 30;8let dx = 2;9let dy = -2;10const ballRadius = 10;11 12// Game loop13function draw() {14 ctx.clearRect(0, 0, canvas.width, canvas.height);15 drawBall();16 drawPaddle();17 drawBricks();18 drawScore();19 drawLives();20 21 // Collision detection22 checkWallCollisions();23 checkBrickCollisions();24 25 // Update position26 x += dx;27 y += dy;28 29 requestAnimationFrame(draw);30}31 32// Start the game33draw();Conclusion
Building a 2D Breakout game with pure JavaScript teaches fundamental game development concepts that transfer to any technology stack or framework. You've learned how to:
- Set up a rendering canvas and obtain the 2D context
- Draw shapes using the Canvas API
- Implement smooth animations with requestAnimationFrame
- Detect collisions with walls, paddle, and bricks
- Handle user input for keyboard and mouse controls
- Track game progress with score and lives
- Structure code for maintainability and performance
The pure JavaScript approach gives you complete control over every aspect of your game's behavior and a deep understanding of how game mechanics actually work. Whether you continue building games with JavaScript or move to other languages and engines, the concepts covered here will serve as a valuable foundation for your development journey.
Start with the basic implementation and gradually add features as you become more comfortable with the code. Game development is a creative process, and there's no single "right" way to build a game. Experiment, iterate, and most importantly--have fun bringing your ideas to life!
Frequently Asked Questions
Do I need any external libraries to build this game?
No, this entire game can be built using only pure JavaScript and the HTML5 Canvas API. No external libraries or frameworks are required, making it perfect for learning game development fundamentals.
What's the difference between setInterval and requestAnimationFrame?
requestAnimationFrame synchronizes with the browser's refresh rate for smooth animations, pauses when the tab is inactive to save resources, and provides better performance overall. setInterval runs at a fixed interval regardless of display refresh rate.
How do I make the ball bounce at different angles?
You can modify the ball's horizontal velocity (dx) based on where it hits the paddle. Hitting the edge of the paddle can increase horizontal speed, while hitting the center keeps it steady, adding strategic depth to gameplay.
Can I use this code in a production project?
Absolutely! This code demonstrates production-ready patterns for game development. The collision detection, game loop, and input handling patterns are all applicable to real-world projects.
Sources
- MDN Web Docs: 2D Breakout Game Pure JavaScript - Official step-by-step tutorial for building a complete Breakout game
- MDN: Create the Canvas and draw on it - Foundation lesson covering HTML structure and basic drawing operations
- MDN: Move the ball - Animation fundamentals including game loops and ball movement logic
- MDN Canvas API Reference - Complete reference for all 2D drawing operations
- MDN requestAnimationFrame API - API documentation for smooth, performance-optimized animations