Use the Left and Right Arrows or A and D keys to move, Spacebar to shoot.
Game starts right away, looks best in full mode.
Hope you like it! ;)
A Pen by Nate Wiley on CodePen.
Use the Left and Right Arrows or A and D keys to move, Spacebar to shoot.
Game starts right away, looks best in full mode.
Hope you like it! ;)
A Pen by Nate Wiley on CodePen.
| <div class="container"> | |
| <div class="game-wrap"> | |
| <canvas width="960px" height="540" id="game"></canvas> | |
| <article class="content"> | |
| <h1 class="title"><span>C</span><span>o</span><span>l</span><span>o</span><span>r</span><span> </span><span>B</span><span>l</span><span>a</span><span>s</span><span>t</span></h1> | |
| <p>Use the <code>Left</code> and <code>Right</code> Arrows or <code>A</code> and <code>D</code> keys to move, <code>Spacebar</code> to shoot.</p> | |
| <p><a href="http://codepen.io/natewiley/full/EGyiF" target="_blank">Click here to play in full mode</a>, click the game to pause and take a break. <a href="http://codepen.io/natewiley" target="_blank">Follow me on CodePen</a></p> | |
| </article> | |
| </div> | |
| </div> |
| // Color Blast! | |
| // License MIT | |
| // © 2014 Nate Wiley | |
| (function(window){ | |
| var Game = { | |
| init: function(){ | |
| this.c = document.getElementById("game"); | |
| this.c.width = this.c.width; | |
| this.c.height = this.c.height; | |
| this.ctx = this.c.getContext("2d"); | |
| this.color = "rgba(20,20,20,.7)"; | |
| this.bullets = []; | |
| this.enemyBullets = []; | |
| this.enemies = []; | |
| this.particles = []; | |
| this.bulletIndex = 0; | |
| this.enemyBulletIndex = 0; | |
| this.enemyIndex = 0; | |
| this.particleIndex = 0; | |
| this.maxParticles = 10; | |
| this.maxEnemies = 6; | |
| this.enemiesAlive = 0; | |
| this.currentFrame = 0; | |
| this.maxLives = 3; | |
| this.life = 0; | |
| this.binding(); | |
| this.player = new Player(); | |
| this.score = 0; | |
| this.paused = false; | |
| this.shooting = false; | |
| this.oneShot = false; | |
| this.isGameOver = false; | |
| this.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; | |
| for(var i = 0; i<this.maxEnemies; i++){ | |
| new Enemy(); | |
| this.enemiesAlive++; | |
| } | |
| this.invincibleMode(2000); | |
| this.loop(); | |
| }, | |
| binding: function(){ | |
| window.addEventListener("keydown", this.buttonDown); | |
| window.addEventListener("keyup", this.buttonUp); | |
| window.addEventListener("keypress", this.keyPressed); | |
| this.c.addEventListener("click", this.clicked); | |
| }, | |
| clicked: function(){ | |
| if(!Game.paused) { | |
| Game.pause(); | |
| } else { | |
| if(Game.isGameOver){ | |
| Game.init(); | |
| } else { | |
| Game.unPause(); | |
| Game.loop(); | |
| Game.invincibleMode(1000); | |
| } | |
| } | |
| }, | |
| keyPressed: function(e){ | |
| if(e.keyCode === 32){ | |
| if(!Game.player.invincible && !Game.oneShot){ | |
| Game.player.shoot(); | |
| Game.oneShot = true; | |
| } | |
| if(Game.isGameOver){ | |
| Game.init(); | |
| } | |
| e.preventDefault(); | |
| } | |
| }, | |
| buttonUp: function(e){ | |
| if(e.keyCode === 32){ | |
| Game.shooting = false; | |
| Game.oneShot = false; | |
| e.preventDefault(); | |
| } | |
| if(e.keyCode === 37 || e.keyCode === 65){ | |
| Game.player.movingLeft = false; | |
| } | |
| if(e.keyCode === 39 || e.keyCode === 68){ | |
| Game.player.movingRight = false; | |
| } | |
| }, | |
| buttonDown: function(e){ | |
| if(e.keyCode === 32){ | |
| Game.shooting = true; | |
| } | |
| if(e.keyCode === 37 || e.keyCode === 65){ | |
| Game.player.movingLeft = true; | |
| } | |
| if(e.keyCode === 39 || e.keyCode === 68){ | |
| Game.player.movingRight = true; | |
| } | |
| }, | |
| random: function(min, max){ | |
| return Math.floor(Math.random() * (max - min) + min); | |
| }, | |
| invincibleMode: function(s){ | |
| this.player.invincible = true; | |
| setTimeout(function(){ | |
| Game.player.invincible = false; | |
| }, s); | |
| }, | |
| collision: function(a, b){ | |
| return !( | |
| ((a.y + a.height) < (b.y)) || | |
| (a.y > (b.y + b.height)) || | |
| ((a.x + a.width) < b.x) || | |
| (a.x > (b.x + b.width)) | |
| ) | |
| }, | |
| clear: function(){ | |
| this.ctx.fillStyle = Game.color; | |
| this.ctx.fillRect(0, 0, this.c.width, this.c.height); | |
| }, | |
| pause: function(){ | |
| this.paused = true; | |
| }, | |
| unPause: function(){ | |
| this.paused = false; | |
| }, | |
| gameOver: function(){ | |
| this.isGameOver = true; | |
| this.clear(); | |
| var message = "Game Over"; | |
| var message2 = "Score: " + Game.score; | |
| var message3 = "Click or press Spacebar to Play Again"; | |
| this.pause(); | |
| this.ctx.fillStyle = "white"; | |
| this.ctx.font = "bold 30px Lato, sans-serif"; | |
| this.ctx.fillText(message, this.c.width/2 - this.ctx.measureText(message).width/2, this.c.height/2 - 50); | |
| this.ctx.fillText(message2, this.c.width/2 - this.ctx.measureText(message2).width/2, this.c.height/2 - 5); | |
| this.ctx.font = "bold 16px Lato, sans-serif"; | |
| this.ctx.fillText(message3, this.c.width/2 - this.ctx.measureText(message3).width/2, this.c.height/2 + 30); | |
| }, | |
| updateScore: function(){ | |
| this.ctx.fillStyle = "white"; | |
| this.ctx.font = "16px Lato, sans-serif"; | |
| this.ctx.fillText("Score: " + this.score, 8, 20); | |
| this.ctx.fillText("Lives: " + (this.maxLives - this.life), 8, 40); | |
| }, | |
| loop: function(){ | |
| if(!Game.paused){ | |
| Game.clear(); | |
| for(var i in Game.enemies){ | |
| var currentEnemy = Game.enemies[i]; | |
| currentEnemy.draw(); | |
| currentEnemy.update(); | |
| if(Game.currentFrame % currentEnemy.shootingSpeed === 0){ | |
| currentEnemy.shoot(); | |
| } | |
| } | |
| for(var x in Game.enemyBullets){ | |
| Game.enemyBullets[x].draw(); | |
| Game.enemyBullets[x].update(); | |
| } | |
| for(var z in Game.bullets){ | |
| Game.bullets[z].draw(); | |
| Game.bullets[z].update(); | |
| } | |
| if(Game.player.invincible){ | |
| if(Game.currentFrame % 20 === 0){ | |
| Game.player.draw(); | |
| } | |
| } else { | |
| Game.player.draw(); | |
| } | |
| for(var i in Game.particles){ | |
| Game.particles[i].draw(); | |
| } | |
| Game.player.update(); | |
| Game.updateScore(); | |
| Game.currentFrame = Game.requestAnimationFrame.call(window, Game.loop); | |
| } | |
| } | |
| }; | |
| var Player = function(){ | |
| this.width = 60; | |
| this.height = 20; | |
| this.x = Game.c.width/2 - this.width/2; | |
| this.y = Game.c.height - this.height; | |
| this.movingLeft = false; | |
| this.movingRight = false; | |
| this.speed = 8; | |
| this.invincible = false; | |
| this.color = "white"; | |
| }; | |
| Player.prototype.die = function(){ | |
| if(Game.life < Game.maxLives){ | |
| Game.invincibleMode(2000); | |
| Game.life++; | |
| } else { | |
| Game.pause(); | |
| Game.gameOver(); | |
| } | |
| }; | |
| Player.prototype.draw = function(){ | |
| Game.ctx.fillStyle = this.color; | |
| Game.ctx.fillRect(this.x, this.y, this.width, this.height); | |
| }; | |
| Player.prototype.update = function(){ | |
| if(this.movingLeft && this.x > 0){ | |
| this.x -= this.speed; | |
| } | |
| if(this.movingRight && this.x + this.width < Game.c.width){ | |
| this.x += this.speed; | |
| } | |
| if(Game.shooting && Game.currentFrame % 10 === 0){ | |
| this.shoot(); | |
| } | |
| for(var i in Game.enemyBullets){ | |
| var currentBullet = Game.enemyBullets[i]; | |
| if(Game.collision(currentBullet, this) && !Game.player.invincible){ | |
| this.die(); | |
| delete Game.enemyBullets[i]; | |
| } | |
| } | |
| }; | |
| Player.prototype.shoot = function(){ | |
| Game.bullets[Game.bulletIndex] = new Bullet(this.x + this.width/2); | |
| Game.bulletIndex++; | |
| }; | |
| var Bullet = function(x){ | |
| this.width = 8; | |
| this.height = 20; | |
| this.x = x; | |
| this.y = Game.c.height - 10; | |
| this.vy = 8; | |
| this.index = Game.bulletIndex; | |
| this.active = true; | |
| this.color = "white"; | |
| }; | |
| Bullet.prototype.draw = function(){ | |
| Game.ctx.fillStyle = this.color; | |
| Game.ctx.fillRect(this.x, this.y, this.width, this.height); | |
| }; | |
| Bullet.prototype.update = function(){ | |
| this.y -= this.vy; | |
| if(this.y < 0){ | |
| delete Game.bullets[this.index]; | |
| } | |
| }; | |
| var Enemy = function(){ | |
| this.width = 60; | |
| this.height = 20; | |
| this.x = Game.random(0, (Game.c.width - this.width)); | |
| this.y = Game.random(10, 40); | |
| this.vy = Game.random(1, 3) * .1; | |
| this.index = Game.enemyIndex; | |
| Game.enemies[Game.enemyIndex] = this; | |
| Game.enemyIndex++; | |
| this.speed = Game.random(2, 3); | |
| this.shootingSpeed = Game.random(30, 80); | |
| this.movingLeft = Math.random() < 0.5 ? true : false; | |
| this.color = "hsl("+ Game.random(0, 360) +", 60%, 50%)"; | |
| }; | |
| Enemy.prototype.draw = function(){ | |
| Game.ctx.fillStyle = this.color; | |
| Game.ctx.fillRect(this.x, this.y, this.width, this.height); | |
| }; | |
| Enemy.prototype.update = function(){ | |
| if(this.movingLeft){ | |
| if(this.x > 0){ | |
| this.x -= this.speed; | |
| this.y += this.vy; | |
| } else { | |
| this.movingLeft = false; | |
| } | |
| } else { | |
| if(this.x + this.width < Game.c.width){ | |
| this.x += this.speed; | |
| this.y += this.vy; | |
| } else { | |
| this.movingLeft = true; | |
| } | |
| } | |
| for(var i in Game.bullets){ | |
| var currentBullet = Game.bullets[i]; | |
| if(Game.collision(currentBullet, this)){ | |
| this.die(); | |
| delete Game.bullets[i]; | |
| } | |
| } | |
| }; | |
| Enemy.prototype.die = function(){ | |
| this.explode(); | |
| delete Game.enemies[this.index]; | |
| Game.score += 15; | |
| Game.enemiesAlive = Game.enemiesAlive > 1 ? Game.enemiesAlive - 1 : 0; | |
| if(Game.enemiesAlive < Game.maxEnemies){ | |
| Game.enemiesAlive++; | |
| setTimeout(function(){ | |
| new Enemy(); | |
| }, 2000); | |
| } | |
| }; | |
| Enemy.prototype.explode = function(){ | |
| for(var i=0; i<Game.maxParticles; i++){ | |
| new Particle(this.x + this.width/2, this.y, this.color); | |
| } | |
| }; | |
| Enemy.prototype.shoot = function(){ | |
| new EnemyBullet(this.x + this.width/2, this.y, this.color); | |
| }; | |
| var EnemyBullet = function(x, y, color){ | |
| this.width = 8; | |
| this.height = 20; | |
| this.x = x; | |
| this.y = y; | |
| this.vy = 6; | |
| this.color = color; | |
| this.index = Game.enemyBulletIndex; | |
| Game.enemyBullets[Game.enemyBulletIndex] = this; | |
| Game.enemyBulletIndex++; | |
| }; | |
| EnemyBullet.prototype.draw = function(){ | |
| Game.ctx.fillStyle = this.color; | |
| Game.ctx.fillRect(this.x, this.y, this.width, this.height); | |
| }; | |
| EnemyBullet.prototype.update = function(){ | |
| this.y += this.vy; | |
| if(this.y > Game.c.height){ | |
| delete Game.enemyBullets[this.index]; | |
| } | |
| }; | |
| var Particle = function(x, y, color){ | |
| this.x = x; | |
| this.y = y; | |
| this.vx = Game.random(-5, 5); | |
| this.vy = Game.random(-5, 5); | |
| this.color = color || "orange"; | |
| Game.particles[Game.particleIndex] = this; | |
| this.id = Game.particleIndex; | |
| Game.particleIndex++; | |
| this.life = 0; | |
| this.gravity = .05; | |
| this.size = 40; | |
| this.maxlife = 100; | |
| } | |
| Particle.prototype.draw = function(){ | |
| this.x += this.vx; | |
| this.y += this.vy; | |
| this.vy += this.gravity; | |
| this.size *= .89; | |
| Game.ctx.fillStyle = this.color; | |
| Game.ctx.fillRect(this.x, this.y, this.size, this.size); | |
| this.life++; | |
| if(this.life >= this.maxlife){ | |
| delete Game.particles[this.id]; | |
| } | |
| }; | |
| Game.init(); | |
| }(window)); |
| @import url(http://fonts.googleapis.com/css?family=Lato:100,300,400,700); | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| -webkit-box-sizing: border-box; | |
| box-sizing: border-box; | |
| } | |
| html, body { | |
| height: 100%; | |
| } | |
| body { | |
| min-height: 100%; | |
| max-width: 100%; | |
| background: #111; | |
| font-family: Lato, sans-serif; | |
| } | |
| .container { | |
| min-height: 100%; | |
| max-width: 960px; | |
| margin: 0 auto; | |
| } | |
| .game-wrap { | |
| position: relative; | |
| padding: 20px 0 0; | |
| } | |
| canvas { | |
| position: relative; | |
| max-width: 100%; | |
| border: 2px solid black; | |
| max-height: 100%; | |
| display: block; | |
| margin: 0 auto; | |
| } | |
| .content { | |
| color: #ccc; | |
| text-align: center; | |
| padding: 0 20px; | |
| } | |
| p { | |
| margin: 10px 0; | |
| font-size: 18px; | |
| line-height: 1.5em; | |
| } | |
| code { | |
| background: #222; | |
| background: linear-gradient(#222, #000); | |
| line-height: 1.3em; | |
| display: inline-block; | |
| border-radius: 3px; | |
| font-family: monospace; | |
| padding: 1px 5px; | |
| margin: 0 2px; | |
| } | |
| a { | |
| color: skyblue; | |
| text-decoration: none; | |
| transition: .2s; | |
| &:hover { | |
| color: lighten(skyblue, 10%); | |
| text-decoration: underline; | |
| } | |
| } | |
| .title { | |
| font-size: 40px; | |
| font-weight: 900; | |
| margin: 20px 0; | |
| @for $i from 1 through 11 { | |
| span:nth-child(#{$i}){ | |
| color: hsl($i * 30, 50%, 50%); | |
| } | |
| } | |
| } |