├── README.md ├── index.html └── game.js /README.md: -------------------------------------------------------------------------------- 1 | # Live-coded Space Invaders 2 | 3 | I live-coded a very simple Space Invaders game in front of some Hacker Schoolers from the W2014 batch. It was a lot of fun. 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /game.js: -------------------------------------------------------------------------------- 1 | ;(function (exports) { 2 | var Game = function(canvasId) { 3 | this.WIDTH = 200; 4 | this.HEIGHT = 200; 5 | this.boxX = 10; 6 | 7 | var canvas = getCanvas(canvasId); 8 | sizeCanvas(canvas, this.WIDTH, this.HEIGHT); 9 | var drawingContext = getContext(canvas); 10 | 11 | this.createEntities(); 12 | 13 | var self = this; 14 | this.startTick(function() { 15 | self.update(); 16 | self.draw(drawingContext); 17 | }); 18 | }; 19 | 20 | Game.prototype = { 21 | x: 10, 22 | startTick: function(fn) { 23 | var tick = function() { 24 | fn(); 25 | requestAnimationFrame(tick); 26 | }; 27 | 28 | requestAnimationFrame(tick); 29 | }, 30 | 31 | createEntities: function() { 32 | this.bullets = []; 33 | this.ship = new Ship(this); 34 | 35 | this.invaders = []; 36 | for (var i = 0; i < 24; i++) { 37 | this.invaders.push(new Invader(this, { 38 | x: 20 + 20 * (i % 8), 39 | y: 20 + 20 * (i % 3) 40 | })); 41 | } 42 | }, 43 | 44 | shoot: function(center) { 45 | this.bullets.push(new Bullet(this.game, center)); 46 | }, 47 | 48 | update: function() { 49 | this.ship.update(); 50 | 51 | for (var i = 0; i < this.invaders.length; i++) { 52 | this.invaders[i].update(); 53 | } 54 | 55 | for (var i = 0; i < this.bullets.length; i++) { 56 | this.bullets[i].update(); 57 | } 58 | 59 | for (var i = 0; i < this.bullets.length; i++) { 60 | if (entitiesColliding(this.ship, this.bullets[i])) { 61 | this.ship.color = "#f00"; 62 | } 63 | } 64 | }, 65 | 66 | draw: function(drawingContext) { 67 | drawingContext.clearRect(0, 0, this.WIDTH, this.HEIGHT); 68 | this.ship.draw(drawingContext); 69 | 70 | for (var i = 0; i < this.invaders.length; i++) { 71 | this.invaders[i].draw(drawingContext); 72 | } 73 | 74 | for (var i = 0; i < this.bullets.length; i++) { 75 | this.bullets[i].draw(drawingContext); 76 | } 77 | } 78 | }; 79 | 80 | var sizeCanvas = function(canvas, width, height) { 81 | canvas.width = width; 82 | canvas.height = height; 83 | }; 84 | 85 | var getContext = function(canvas) { 86 | return canvas.getContext('2d'); 87 | }; 88 | 89 | var getCanvas = function(canvasId) { 90 | return document.getElementById(canvasId); 91 | }; 92 | 93 | var Ship = function(game) { 94 | this.game = game; 95 | this.size = { x: 10, y: 10 }; 96 | this.color = "#000"; 97 | this.center = { x: game.WIDTH / 2, y: game.HEIGHT - this.size.y }; 98 | 99 | this.inputter = new Inputter(); 100 | }; 101 | 102 | Ship.prototype = { 103 | update: function() { 104 | if (this.inputter.isDown(37)) { // left 105 | this.center.x--; 106 | } else if (this.inputter.isDown(39)) { 107 | this.center.x++; 108 | } 109 | }, 110 | 111 | draw: function(drawingContext) { 112 | drawRectangleForObject(this, drawingContext); 113 | } 114 | }; 115 | 116 | var drawRectangleForObject = function(obj, drawingContext) { 117 | drawingContext.fillStyle = obj.color; 118 | drawingContext.fillRect(obj.center.x, obj.center.y, obj.size.x, obj.size.y); 119 | }; 120 | 121 | var Invader = function(game, center) { 122 | this.game = game; 123 | this.size = { x: 10, y: 10 }; 124 | this.center = center; 125 | this.color = "#000"; 126 | }; 127 | 128 | Invader.prototype = { 129 | patrolSpeedX: 0, 130 | patrolPositionX: 0, 131 | update: function() { 132 | if (this.patrolPositionX <= 0) { 133 | this.patrolSpeedX = 0.5; 134 | } else if (this.patrolPositionX >= 20) { 135 | this.patrolSpeedX = -0.5; 136 | } 137 | 138 | this.patrolPositionX += this.patrolSpeedX; 139 | this.center.x += this.patrolSpeedX; 140 | 141 | if (Math.random() < 0.005) { 142 | this.game.shoot({ x: this.center.x, y: this.center.y }); 143 | } 144 | }, 145 | 146 | draw: function(drawingContext) { 147 | drawRectangleForObject(this, drawingContext); 148 | } 149 | }; 150 | 151 | var Inputter = function() { 152 | var keyState = {}; 153 | 154 | window.onkeydown = function(e) { 155 | keyState[e.keyCode] = true; 156 | }; 157 | 158 | window.onkeyup = function(e) { 159 | keyState[e.keyCode] = false; 160 | }; 161 | 162 | this.isDown = function(keyCode) { 163 | return keyState[keyCode] === true; 164 | }; 165 | }; 166 | 167 | var Bullet = function(game, center) { 168 | this.game = game; 169 | this.size = { x: 4, y: 4 }; 170 | this.color = "#000"; 171 | this.center = center; 172 | this.vector = { x: Math.random() - 0.5, y: Math.random() }; 173 | }; 174 | 175 | Bullet.prototype = { 176 | update: function() { 177 | this.center.x += this.vector.x; 178 | this.center.y += this.vector.y; 179 | }, 180 | 181 | draw: function(drawingContext) { 182 | drawRectangleForObject(this, drawingContext); 183 | } 184 | }; 185 | 186 | var entitiesColliding = function(e1, e2) { 187 | return !(e1.center.x + e1.size.x / 2 < e2.center.x - e2.size.x / 2 || 188 | e1.center.y + e1.size.y / 2 < e2.center.y - e2.size.y / 2 || 189 | e1.center.x - e1.size.x / 2 > e2.center.x + e2.size.x / 2 || 190 | e1.center.y - e1.size.y / 2 > e2.center.y + e2.size.y / 2); 191 | }; 192 | 193 | window.onload = function () { 194 | new Game("canvas"); 195 | }; 196 | })(this); 197 | --------------------------------------------------------------------------------