body {
  margin: 0;
  overflow: hidden;
}
var gamePiece;
var obstacles = [];
var score;

var GameArea = function(width, height, frameRate) {
  this.width = width;
  this.height = height;
  this.frameRate = frameRate;
  this.frame = 0;
  this.currentObstacles = 0;
  
  this.canvas = document.createElement('canvas');
  this.canvas.width = this.width;
  this.canvas.height = this.height;
  this.context = this.canvas.getContext('2d');
  
  this.start = function() {
    document.body.insertBefore(this.canvas, document.body.childNodes[0]);
    
    this.interval = setInterval(this.update, 1000 / this.frameRate);
    
    window.addEventListener('keydown', function(e) {
      gameArea.keys = (gameArea.keys || []);
      gameArea.keys[e.keyCode] = true;
    });
    window.addEventListener('keyup', function(e) {
      gameArea.keys[e.keyCode] = false;
    });
  }
  
  this.update = function() {
    for (var i = 0; i < obstacles.length; i++) {
      if (gamePiece.crashWith(obstacles[i])) {
        gameArea.stop();
      }
    }
    
    gameArea.clear();
    gameArea.frame += 1;
    
    gameArea.addObstacles();
    
    for (var i = 0; i < obstacles.length; i++) {
      obstacles[i].x += -1;
      obstacles[i].update();
    }
    
    gamePiece.stopMove();
    
    gameArea.processInput();
    
    for (var i = 0; i < obstacles.length; i++) {
      if (gameArea.currentObstacles == i &&
          gamePiece.x > obstacles[i].x + obstacles[i].width) {
        gameArea.currentObstacles += 2;
        score.number += 1;
      }
    }
    
    score.text = 'SCORE: ' + score.number;
    score.update();
    
    gamePiece.newPos();
    gamePiece.update();
  }
  
  this.clear = function() {
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }
  
  this.stop = function() {
    clearInterval(this.interval);
  }
  
  this.addObstacles = function() {
    if (gameArea.frame == 1 || gameArea.everyInterval(150)) {
      var x = gameArea.canvas.width;
      var minHeight = 20;
      var maxHeight = 200;
      var height = Math.floor(Math.random() * (maxHeight - minHeight + 1) + minHeight);
      var minGap = 50;
      var maxGap = 200;
      var gap = Math.floor(Math.random() * (maxGap - minGap + 1) + minGap);
      
      obstacles.push(new GamePiece(x, 0, 10, height, 'green'));
      obstacles.push(new GamePiece(x, height + gap, 10, x - height - gap, 'green'));
    }
  }
  
  this.everyInterval = function(n) {
    if ((gameArea.frame / n) % 1 == 0) {
      return true;
    }
    
    return false;
  }
  
  this.processInput = function() {
    if (gameArea.keys && gameArea.keys[37]) {
      gamePiece.speedX = -1;
    }
    if (gameArea.keys && gameArea.keys[39]) {
      gamePiece.speedX = 1;
    }
    if (gameArea.keys && gameArea.keys[38]) {
      gamePiece.speedY = -1;
    }
    if (gameArea.keys && gameArea.keys[40]) {
      gamePiece.speedY = 1;
    }
  }
}

var GamePiece = function(x, y, width, height, color) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.color = color;
  this.speedX = 0;
  this.speedY = 0;
  
  this.update = function() {
    ctx = gameArea.context;
    
    ctx.fillStyle = this.color;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
  
  this.newPos = function() {
    this.x += this.speedX;
    this.y += this.speedY;
  }
  
  this.stopMove = function() {
    this.speedX = 0;
    this.speedY = 0;
  }
  
  this.crashWith = function(object) {
    var left = this.x;
    var right = this.x + (this.width);
    var top = this.y;
    var bottom = this.y + (this.height);
    
    var otherLeft = object.x;
    var otherRight = object.x + (object.width);
    var otherTop = object.y;
    var otherBottom = object.y + (object.height);
    
    var crash = true;
    
    if (left > otherRight ||
        right < otherLeft ||
        top > otherBottom ||
        bottom < otherTop) {
      crash = false;
    }
    
    return crash;
  }
}

var Score = function(text, x, y, color, font) {
  this.text = text;
  this.x = x;
  this.y = y;
  this.color = color;
  this.font = font;
  this.number = 0;
  
  this.update = function() {
    ctx = gameArea.context;
    
    ctx.font = this.font;
    ctx.fillStyle = this.color;
    ctx.fillText(this.text, this.x, this.y);
  }
}

startGame();

function startGame() {
  gameArea = new GameArea(480, 270, 60);
  gamePiece = new GamePiece(10, 120, 30, 30, 'red');
  score = new Score('SCORE: ', 280, 40, 'black', '30px Consolas');
  gameArea.start();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.