Brick Breaker 🎮

This was a student project that recreated everyone's favorite game- a game in which you move a paddle around to keep a ball up in the air to ensure it breaks all the bricks on the screen. The game had three rounds with different patterns of bricks to break, and it also kept score.

Built by Krista Handel and Cameron Buscher

Learning Goals

Previously we had built small applications where all of our javascript was housed in a single file. One of the main goals we had for this project was to piece out different bits of functionality and give them their own files. This was easy to do, considering we were also implementing Object Oriented Programming. For each feature of our game we created a class that would take care of the functionality of that specific feature. This was the point where I realized how beautiful programming really was- I had gone from creating a single, ugly javascript file for my projects to separating out functionality based on concerns. This led to more readable code and made the writing process a bit easier because our focus was more clear.

We also focused on writing a test suite for the functionality of our client-side application. Having the separate classes handling the different bits of functionality made the application easier to test.

Initial Setup

  1. Clone down the repository
git clone https://github.com/meloncatty/game-time.git
  1. cd into the repository and install the dependencies:
npm install

Run the Server

To see this code in action, you need to fire up a development server. Use the command:

npm start

Once the server is running, visit in your browser:

  • http://localhost:8080/webpack-dev-server/ to run the application.
  • http://localhost:8080/webpack-dev-server/test.html to run the test suite in the browser.

Run Tests in the Terminal

To run all of the tests:

npm test

File Organization

Webpack is a little opinionated about how files are organized. Here is a brief guide on how to organize development and test files.

Development Files

Node and webpack work together to help us organize our files and keep responsibilities separated.

For example, if we have the lib/index.js file and a lib/Block.js file:

lib/index.js

var Block = require('./Block');

var canvas = document.getElementById('game');
var context = canvas.getContext('2d');

var blocks = [];

blocks.push(new Block(50, 50, 10, 10, context));
blocks.push(new Block(100, 50, 10, 10, context));

requestAnimationFrame(function gameLoop() {
  context.clearRect(0, 0, canvas.width, canvas.height);

  this.blocks.forEach(function(block){
    block.draw()
    block.move()
  })

  requestAnimationFrame(gameLoop);
});

lib/Block.js

function Block(x, y, width, height, context) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.context = context;
}

Block.prototype.draw = function () {
  this.context.fillRect(this.x, this.y, this.width, this.height);
};

Block.prototype.move = function () {
  this.y++;
};

module.exports = Block;

All of the Block.js code could live in the index.js file, but that would go against our philosophy of separating responsibility between files.

There are two main things to pay attention to here:

  1. At the top of the index.js file, we require the Block.js file using the line of code var Block = require('./Block'); (we leave out the .js). This brings in the code from the Block.js file so we can use that file's code in the index.js file.

  2. In the Block.js file, the bottom line says module.exports = Block; which says what we want this file to export when we say require in other files, like in index.js.

So now we have two files that can share code between each other, but we have to pay attention to what we export and what we require. If we didn't do this, then when we try to make a new Block in the index.js file, it won't know what Block we're talking about!

Test Files

Near the end of game time, we had multiple objects for our game that are tested separately with individual test files. The test/index.js file serves as an "entry point" for mocha to load all of the tests we wrote.

Test file organization is a bit different from development files. If we want to test the Block.js file from above, we would need to have a corresponding test file. So in the test directory, we created a new file called test/Block-test.js. Here is what a basic outline of the file looks like:

test/Block-test.js

var chai = require('chai');
var assert = chai.assert;

var Block = require('../lib/Block');

describe('Block', function() {
  context('with default attributes', function() {
    // Your tests here...  
  });  
});

test/index.js

require('./Block-test')

Two main points to pay attention to:

  1. In the Block-test.js file, we require the Block.js file so that we can construct blocks in our tests.

  2. In the test/index.js file, we require the Block-test.js file so that we can view the test results in the browser (at http://localhost:8080/webpack-dev-server/test.html).