Path: blob/main/public/games/files/asteroids/game.js
1036 views
// Canvas Asteroids1//2// Copyright (c) 2010 Doug McInnes3//45KEY_CODES = {632: 'space',737: 'left',838: 'up',939: 'right',1040: 'down',1170: 'f',1271: 'g',1372: 'h',1477: 'm',1580: 'p'16}1718KEY_STATUS = { keyDown:false };19for (code in KEY_CODES) {20KEY_STATUS[KEY_CODES[code]] = false;21}2223$(window).keydown(function (e) {24KEY_STATUS.keyDown = true;25if (KEY_CODES[e.keyCode]) {26e.preventDefault();27KEY_STATUS[KEY_CODES[e.keyCode]] = true;28}29}).keyup(function (e) {30KEY_STATUS.keyDown = false;31if (KEY_CODES[e.keyCode]) {32e.preventDefault();33KEY_STATUS[KEY_CODES[e.keyCode]] = false;34}35});3637GRID_SIZE = 60;3839Matrix = function (rows, columns) {40var i, j;41this.data = new Array(rows);42for (i = 0; i < rows; i++) {43this.data[i] = new Array(columns);44}4546this.configure = function (rot, scale, transx, transy) {47var rad = (rot * Math.PI)/180;48var sin = Math.sin(rad) * scale;49var cos = Math.cos(rad) * scale;50this.set(cos, -sin, transx,51sin, cos, transy);52};5354this.set = function () {55var k = 0;56for (i = 0; i < rows; i++) {57for (j = 0; j < columns; j++) {58this.data[i][j] = arguments[k];59k++;60}61}62}6364this.multiply = function () {65var vector = new Array(rows);66for (i = 0; i < rows; i++) {67vector[i] = 0;68for (j = 0; j < columns; j++) {69vector[i] += this.data[i][j] * arguments[j];70}71}72return vector;73};74};7576Sprite = function () {77this.init = function (name, points) {78this.name = name;79this.points = points;8081this.vel = {82x: 0,83y: 0,84rot: 085};8687this.acc = {88x: 0,89y: 0,90rot: 091};92};9394this.children = {};9596this.visible = false;97this.reap = false;98this.bridgesH = true;99this.bridgesV = true;100101this.collidesWith = [];102103this.x = 0;104this.y = 0;105this.rot = 0;106this.scale = 1;107108this.currentNode = null;109this.nextSprite = null;110111this.preMove = null;112this.postMove = null;113114this.run = function(delta) {115116this.move(delta);117this.updateGrid();118119this.context.save();120this.configureTransform();121this.draw();122123var canidates = this.findCollisionCanidates();124125this.matrix.configure(this.rot, this.scale, this.x, this.y);126this.checkCollisionsAgainst(canidates);127128this.context.restore();129130if (this.bridgesH && this.currentNode && this.currentNode.dupe.horizontal) {131this.x += this.currentNode.dupe.horizontal;132this.context.save();133this.configureTransform();134this.draw();135this.checkCollisionsAgainst(canidates);136this.context.restore();137if (this.currentNode) {138this.x -= this.currentNode.dupe.horizontal;139}140}141if (this.bridgesV && this.currentNode && this.currentNode.dupe.vertical) {142this.y += this.currentNode.dupe.vertical;143this.context.save();144this.configureTransform();145this.draw();146this.checkCollisionsAgainst(canidates);147this.context.restore();148if (this.currentNode) {149this.y -= this.currentNode.dupe.vertical;150}151}152if (this.bridgesH && this.bridgesV &&153this.currentNode &&154this.currentNode.dupe.vertical &&155this.currentNode.dupe.horizontal) {156this.x += this.currentNode.dupe.horizontal;157this.y += this.currentNode.dupe.vertical;158this.context.save();159this.configureTransform();160this.draw();161this.checkCollisionsAgainst(canidates);162this.context.restore();163if (this.currentNode) {164this.x -= this.currentNode.dupe.horizontal;165this.y -= this.currentNode.dupe.vertical;166}167}168};169this.move = function (delta) {170if (!this.visible) return;171this.transPoints = null; // clear cached points172173if ($.isFunction(this.preMove)) {174this.preMove(delta);175}176177this.vel.x += this.acc.x * delta;178this.vel.y += this.acc.y * delta;179this.x += this.vel.x * delta;180this.y += this.vel.y * delta;181this.rot += this.vel.rot * delta;182if (this.rot > 360) {183this.rot -= 360;184} else if (this.rot < 0) {185this.rot += 360;186}187188if ($.isFunction(this.postMove)) {189this.postMove(delta);190}191};192this.updateGrid = function () {193if (!this.visible) return;194var gridx = Math.floor(this.x / GRID_SIZE);195var gridy = Math.floor(this.y / GRID_SIZE);196gridx = (gridx >= this.grid.length) ? 0 : gridx;197gridy = (gridy >= this.grid[0].length) ? 0 : gridy;198gridx = (gridx < 0) ? this.grid.length-1 : gridx;199gridy = (gridy < 0) ? this.grid[0].length-1 : gridy;200var newNode = this.grid[gridx][gridy];201if (newNode != this.currentNode) {202if (this.currentNode) {203this.currentNode.leave(this);204}205newNode.enter(this);206this.currentNode = newNode;207}208209if (KEY_STATUS.g && this.currentNode) {210this.context.lineWidth = 3.0;211this.context.strokeStyle = 'green';212this.context.strokeRect(gridx*GRID_SIZE+2, gridy*GRID_SIZE+2, GRID_SIZE-4, GRID_SIZE-4);213this.context.strokeStyle = 'black';214this.context.lineWidth = 1.0;215}216};217this.configureTransform = function () {218if (!this.visible) return;219220var rad = (this.rot * Math.PI)/180;221222this.context.translate(this.x, this.y);223this.context.rotate(rad);224this.context.scale(this.scale, this.scale);225};226this.draw = function () {227if (!this.visible) return;228229this.context.lineWidth = 1.0 / this.scale;230231for (child in this.children) {232this.children[child].draw();233}234235this.context.beginPath();236237this.context.moveTo(this.points[0], this.points[1]);238for (var i = 1; i < this.points.length/2; i++) {239var xi = i*2;240var yi = xi + 1;241this.context.lineTo(this.points[xi], this.points[yi]);242}243244this.context.closePath();245this.context.stroke();246};247this.findCollisionCanidates = function () {248if (!this.visible || !this.currentNode) return [];249var cn = this.currentNode;250var canidates = [];251if (cn.nextSprite) canidates.push(cn.nextSprite);252if (cn.north.nextSprite) canidates.push(cn.north.nextSprite);253if (cn.south.nextSprite) canidates.push(cn.south.nextSprite);254if (cn.east.nextSprite) canidates.push(cn.east.nextSprite);255if (cn.west.nextSprite) canidates.push(cn.west.nextSprite);256if (cn.north.east.nextSprite) canidates.push(cn.north.east.nextSprite);257if (cn.north.west.nextSprite) canidates.push(cn.north.west.nextSprite);258if (cn.south.east.nextSprite) canidates.push(cn.south.east.nextSprite);259if (cn.south.west.nextSprite) canidates.push(cn.south.west.nextSprite);260return canidates261};262this.checkCollisionsAgainst = function (canidates) {263for (var i = 0; i < canidates.length; i++) {264var ref = canidates[i];265do {266this.checkCollision(ref);267ref = ref.nextSprite;268} while (ref)269}270};271this.checkCollision = function (other) {272if (!other.visible ||273this == other ||274this.collidesWith.indexOf(other.name) == -1) return;275var trans = other.transformedPoints();276var px, py;277var count = trans.length/2;278for (var i = 0; i < count; i++) {279px = trans[i*2];280py = trans[i*2 + 1];281// mozilla doesn't take into account transforms with isPointInPath >:-P282if (($.browser.mozilla) ? this.pointInPolygon(px, py) : this.context.isPointInPath(px, py)) {283other.collision(this);284this.collision(other);285return;286}287}288};289this.pointInPolygon = function (x, y) {290var points = this.transformedPoints();291var j = 2;292var y0, y1;293var oddNodes = false;294for (var i = 0; i < points.length; i += 2) {295y0 = points[i + 1];296y1 = points[j + 1];297if ((y0 < y && y1 >= y) ||298(y1 < y && y0 >= y)) {299if (points[i]+(y-y0)/(y1-y0)*(points[j]-points[i]) < x) {300oddNodes = !oddNodes;301}302}303j += 2304if (j == points.length) j = 0;305}306return oddNodes;307};308this.collision = function () {309};310this.die = function () {311this.visible = false;312this.reap = true;313if (this.currentNode) {314this.currentNode.leave(this);315this.currentNode = null;316}317};318this.transformedPoints = function () {319if (this.transPoints) return this.transPoints;320var trans = new Array(this.points.length);321this.matrix.configure(this.rot, this.scale, this.x, this.y);322for (var i = 0; i < this.points.length/2; i++) {323var xi = i*2;324var yi = xi + 1;325var pts = this.matrix.multiply(this.points[xi], this.points[yi], 1);326trans[xi] = pts[0];327trans[yi] = pts[1];328}329this.transPoints = trans; // cache translated points330return trans;331};332this.isClear = function () {333if (this.collidesWith.length == 0) return true;334var cn = this.currentNode;335if (cn == null) {336var gridx = Math.floor(this.x / GRID_SIZE);337var gridy = Math.floor(this.y / GRID_SIZE);338gridx = (gridx >= this.grid.length) ? 0 : gridx;339gridy = (gridy >= this.grid[0].length) ? 0 : gridy;340cn = this.grid[gridx][gridy];341}342return (cn.isEmpty(this.collidesWith) &&343cn.north.isEmpty(this.collidesWith) &&344cn.south.isEmpty(this.collidesWith) &&345cn.east.isEmpty(this.collidesWith) &&346cn.west.isEmpty(this.collidesWith) &&347cn.north.east.isEmpty(this.collidesWith) &&348cn.north.west.isEmpty(this.collidesWith) &&349cn.south.east.isEmpty(this.collidesWith) &&350cn.south.west.isEmpty(this.collidesWith));351};352this.wrapPostMove = function () {353if (this.x > Game.canvasWidth) {354this.x = 0;355} else if (this.x < 0) {356this.x = Game.canvasWidth;357}358if (this.y > Game.canvasHeight) {359this.y = 0;360} else if (this.y < 0) {361this.y = Game.canvasHeight;362}363};364365};366367Ship = function () {368this.init("ship",369[-5, 4,3700, -12,3715, 4]);372373this.children.exhaust = new Sprite();374this.children.exhaust.init("exhaust",375[-3, 6,3760, 11,3773, 6]);378379this.bulletCounter = 0;380381this.postMove = this.wrapPostMove;382383this.collidesWith = ["asteroid", "bigalien", "alienbullet"];384385this.preMove = function (delta) {386if (KEY_STATUS.left) {387this.vel.rot = -6;388} else if (KEY_STATUS.right) {389this.vel.rot = 6;390} else {391this.vel.rot = 0;392}393394if (KEY_STATUS.up) {395var rad = ((this.rot-90) * Math.PI)/180;396this.acc.x = 0.5 * Math.cos(rad);397this.acc.y = 0.5 * Math.sin(rad);398this.children.exhaust.visible = Math.random() > 0.1;399} else {400this.acc.x = 0;401this.acc.y = 0;402this.children.exhaust.visible = false;403}404405if (this.bulletCounter > 0) {406this.bulletCounter -= delta;407}408if (KEY_STATUS.space) {409if (this.bulletCounter <= 0) {410this.bulletCounter = 10;411for (var i = 0; i < this.bullets.length; i++) {412if (!this.bullets[i].visible) {413SFX.laser();414var bullet = this.bullets[i];415var rad = ((this.rot-90) * Math.PI)/180;416var vectorx = Math.cos(rad);417var vectory = Math.sin(rad);418// move to the nose of the ship419bullet.x = this.x + vectorx * 4;420bullet.y = this.y + vectory * 4;421bullet.vel.x = 6 * vectorx + this.vel.x;422bullet.vel.y = 6 * vectory + this.vel.y;423bullet.visible = true;424break;425}426}427}428}429430// limit the ship's speed431if (Math.sqrt(this.vel.x * this.vel.x + this.vel.y * this.vel.y) > 8) {432this.vel.x *= 0.95;433this.vel.y *= 0.95;434}435};436437this.collision = function (other) {438SFX.explosion();439Game.explosionAt(other.x, other.y);440Game.FSM.state = 'player_died';441this.visible = false;442this.currentNode.leave(this);443this.currentNode = null;444Game.lives--;445};446447};448Ship.prototype = new Sprite();449450BigAlien = function () {451this.init("bigalien",452[-20, 0,453-12, -4,45412, -4,45520, 0,45612, 4,457-12, 4,458-20, 0,45920, 0]);460461this.children.top = new Sprite();462this.children.top.init("bigalien_top",463[-8, -4,464-6, -6,4656, -6,4668, -4]);467this.children.top.visible = true;468469this.children.bottom = new Sprite();470this.children.bottom.init("bigalien_top",471[ 8, 4,4726, 6,473-6, 6,474-8, 4]);475this.children.bottom.visible = true;476477this.collidesWith = ["asteroid", "ship", "bullet"];478479this.bridgesH = false;480481this.bullets = [];482this.bulletCounter = 0;483484this.newPosition = function () {485if (Math.random() < 0.5) {486this.x = -20;487this.vel.x = 1.5;488} else {489this.x = Game.canvasWidth + 20;490this.vel.x = -1.5;491}492this.y = Math.random() * Game.canvasHeight;493};494495this.setup = function () {496this.newPosition();497498for (var i = 0; i < 3; i++) {499var bull = new AlienBullet();500this.bullets.push(bull);501Game.sprites.push(bull);502}503};504505this.preMove = function (delta) {506var cn = this.currentNode;507if (cn == null) return;508509var topCount = 0;510if (cn.north.nextSprite) topCount++;511if (cn.north.east.nextSprite) topCount++;512if (cn.north.west.nextSprite) topCount++;513514var bottomCount = 0;515if (cn.south.nextSprite) bottomCount++;516if (cn.south.east.nextSprite) bottomCount++;517if (cn.south.west.nextSprite) bottomCount++;518519if (topCount > bottomCount) {520this.vel.y = 1;521} else if (topCount < bottomCount) {522this.vel.y = -1;523} else if (Math.random() < 0.01) {524this.vel.y = -this.vel.y;525}526527this.bulletCounter -= delta;528if (this.bulletCounter <= 0) {529this.bulletCounter = 22;530for (var i = 0; i < this.bullets.length; i++) {531if (!this.bullets[i].visible) {532bullet = this.bullets[i];533var rad = 2 * Math.PI * Math.random();534var vectorx = Math.cos(rad);535var vectory = Math.sin(rad);536bullet.x = this.x;537bullet.y = this.y;538bullet.vel.x = 6 * vectorx;539bullet.vel.y = 6 * vectory;540bullet.visible = true;541SFX.laser();542break;543}544}545}546547};548549BigAlien.prototype.collision = function (other) {550if (other.name == "bullet") Game.score += 200;551SFX.explosion();552Game.explosionAt(other.x, other.y);553this.visible = false;554this.newPosition();555};556557this.postMove = function () {558if (this.y > Game.canvasHeight) {559this.y = 0;560} else if (this.y < 0) {561this.y = Game.canvasHeight;562}563564if ((this.vel.x > 0 && this.x > Game.canvasWidth + 20) ||565(this.vel.x < 0 && this.x < -20)) {566// why did the alien cross the road?567this.visible = false;568this.newPosition();569}570}571};572BigAlien.prototype = new Sprite();573574Bullet = function () {575this.init("bullet", [0, 0]);576this.time = 0;577this.bridgesH = false;578this.bridgesV = false;579this.postMove = this.wrapPostMove;580// asteroid can look for bullets so doesn't have581// to be other way around582//this.collidesWith = ["asteroid"];583584this.configureTransform = function () {};585this.draw = function () {586if (this.visible) {587this.context.save();588this.context.lineWidth = 2;589this.context.beginPath();590this.context.moveTo(this.x-1, this.y-1);591this.context.lineTo(this.x+1, this.y+1);592this.context.moveTo(this.x+1, this.y-1);593this.context.lineTo(this.x-1, this.y+1);594this.context.stroke();595this.context.restore();596}597};598this.preMove = function (delta) {599if (this.visible) {600this.time += delta;601}602if (this.time > 50) {603this.visible = false;604this.time = 0;605}606};607this.collision = function (other) {608this.time = 0;609this.visible = false;610this.currentNode.leave(this);611this.currentNode = null;612};613this.transformedPoints = function (other) {614return [this.x, this.y];615};616617};618Bullet.prototype = new Sprite();619620AlienBullet = function () {621this.init("alienbullet");622623this.draw = function () {624if (this.visible) {625this.context.save();626this.context.lineWidth = 2;627this.context.beginPath();628this.context.moveTo(this.x, this.y);629this.context.lineTo(this.x-this.vel.x, this.y-this.vel.y);630this.context.stroke();631this.context.restore();632}633};634};635AlienBullet.prototype = new Bullet();636637Asteroid = function () {638this.init("asteroid",639[-10, 0,640-5, 7,641-3, 4,6421, 10,6435, 4,64410, 0,6455, -6,6462, -10,647-4, -10,648-4, -5]);649650this.visible = true;651this.scale = 6;652this.postMove = this.wrapPostMove;653654this.collidesWith = ["ship", "bullet", "bigalien", "alienbullet"];655656this.collision = function (other) {657SFX.explosion();658if (other.name == "bullet") Game.score += 120 / this.scale;659this.scale /= 3;660if (this.scale > 0.5) {661// break into fragments662for (var i = 0; i < 3; i++) {663var roid = $.extend(true, {}, this);664roid.vel.x = Math.random() * 6 - 3;665roid.vel.y = Math.random() * 6 - 3;666if (Math.random() > 0.5) {667roid.points.reverse();668}669roid.vel.rot = Math.random() * 2 - 1;670roid.move(roid.scale * 3); // give them a little push671Game.sprites.push(roid);672}673}674Game.explosionAt(other.x, other.y);675this.die();676};677};678Asteroid.prototype = new Sprite();679680Explosion = function () {681this.init("explosion");682683this.bridgesH = false;684this.bridgesV = false;685686this.lines = [];687for (var i = 0; i < 5; i++) {688var rad = 2 * Math.PI * Math.random();689var x = Math.cos(rad);690var y = Math.sin(rad);691this.lines.push([x, y, x*2, y*2]);692}693694this.draw = function () {695if (this.visible) {696this.context.save();697this.context.lineWidth = 1.0 / this.scale;698this.context.beginPath();699for (var i = 0; i < 5; i++) {700var line = this.lines[i];701this.context.moveTo(line[0], line[1]);702this.context.lineTo(line[2], line[3]);703}704this.context.stroke();705this.context.restore();706}707};708709this.preMove = function (delta) {710if (this.visible) {711this.scale += delta;712}713if (this.scale > 8) {714this.die();715}716};717};718Explosion.prototype = new Sprite();719720GridNode = function () {721this.north = null;722this.south = null;723this.east = null;724this.west = null;725726this.nextSprite = null;727728this.dupe = {729horizontal: null,730vertical: null731};732733this.enter = function (sprite) {734sprite.nextSprite = this.nextSprite;735this.nextSprite = sprite;736};737738this.leave = function (sprite) {739var ref = this;740while (ref && (ref.nextSprite != sprite)) {741ref = ref.nextSprite;742}743if (ref) {744ref.nextSprite = sprite.nextSprite;745sprite.nextSprite = null;746}747};748749this.eachSprite = function(sprite, callback) {750var ref = this;751while (ref.nextSprite) {752ref = ref.nextSprite;753callback.call(sprite, ref);754}755};756757this.isEmpty = function (collidables) {758var empty = true;759var ref = this;760while (ref.nextSprite) {761ref = ref.nextSprite;762empty = !ref.visible || collidables.indexOf(ref.name) == -1763if (!empty) break;764}765return empty;766};767};768769// borrowed from typeface-0.14.js770// http://typeface.neocracy.org771Text = {772renderGlyph: function (ctx, face, char) {773774var glyph = face.glyphs[char];775776if (glyph.o) {777778var outline;779if (glyph.cached_outline) {780outline = glyph.cached_outline;781} else {782outline = glyph.o.split(' ');783glyph.cached_outline = outline;784}785786var outlineLength = outline.length;787for (var i = 0; i < outlineLength; ) {788789var action = outline[i++];790791switch(action) {792case 'm':793ctx.moveTo(outline[i++], outline[i++]);794break;795case 'l':796ctx.lineTo(outline[i++], outline[i++]);797break;798799case 'q':800var cpx = outline[i++];801var cpy = outline[i++];802ctx.quadraticCurveTo(outline[i++], outline[i++], cpx, cpy);803break;804805case 'b':806var x = outline[i++];807var y = outline[i++];808ctx.bezierCurveTo(outline[i++], outline[i++], outline[i++], outline[i++], x, y);809break;810}811}812}813if (glyph.ha) {814ctx.translate(glyph.ha, 0);815}816},817818renderText: function(text, size, x, y) {819this.context.save();820821this.context.translate(x, y);822823var pixels = size * 72 / (this.face.resolution * 100);824this.context.scale(pixels, -1 * pixels);825this.context.beginPath();826var chars = text.split('');827var charsLength = chars.length;828for (var i = 0; i < charsLength; i++) {829this.renderGlyph(this.context, this.face, chars[i]);830}831this.context.fill();832833this.context.restore();834},835836context: null,837face: null838};839840SFX = {841laser: new Audio('39459__THE_bizniss__laser.wav'),842explosion: new Audio('51467__smcameron__missile_explosion.wav')843};844845// preload audio846for (var sfx in SFX) {847(function () {848var audio = SFX[sfx];849audio.muted = true;850audio.play();851852SFX[sfx] = function () {853if (!this.muted) {854if (audio.duration == 0) {855// somehow dropped out856audio.load();857audio.play();858} else {859audio.muted = false;860audio.currentTime = 0;861}862}863return audio;864}865})();866}867// pre-mute audio868SFX.muted = true;869870Game = {871score: 0,872totalAsteroids: 5,873lives: 0,874875canvasWidth: 800,876canvasHeight: 600,877878sprites: [],879ship: null,880bigAlien: null,881882nextBigAlienTime: null,883884885spawnAsteroids: function (count) {886if (!count) count = this.totalAsteroids;887for (var i = 0; i < count; i++) {888var roid = new Asteroid();889roid.x = Math.random() * this.canvasWidth;890roid.y = Math.random() * this.canvasHeight;891while (!roid.isClear()) {892roid.x = Math.random() * this.canvasWidth;893roid.y = Math.random() * this.canvasHeight;894}895roid.vel.x = Math.random() * 4 - 2;896roid.vel.y = Math.random() * 4 - 2;897if (Math.random() > 0.5) {898roid.points.reverse();899}900roid.vel.rot = Math.random() * 2 - 1;901Game.sprites.push(roid);902}903},904905explosionAt: function (x, y) {906var splosion = new Explosion();907splosion.x = x;908splosion.y = y;909splosion.visible = true;910Game.sprites.push(splosion);911},912913FSM: {914boot: function () {915Game.spawnAsteroids(5);916this.state = 'waiting';917},918waiting: function () {919Text.renderText(window.ipad ? 'Touch Screen to Start' : 'Press Space to Start', 36, Game.canvasWidth/2 - 270, Game.canvasHeight/2);920if (KEY_STATUS.space || window.gameStart) {921KEY_STATUS.space = false; // hack so we don't shoot right away922window.gameStart = false;923this.state = 'start';924}925},926start: function () {927for (var i = 0; i < Game.sprites.length; i++) {928if (Game.sprites[i].name == 'asteroid') {929Game.sprites[i].die();930} else if (Game.sprites[i].name == 'bullet' ||931Game.sprites[i].name == 'bigalien') {932Game.sprites[i].visible = false;933}934}935936Game.score = 0;937Game.lives = 2;938Game.totalAsteroids = 2;939Game.spawnAsteroids();940941Game.nextBigAlienTime = Date.now() + 30000 + (30000 * Math.random());942943this.state = 'spawn_ship';944},945spawn_ship: function () {946Game.ship.x = Game.canvasWidth / 2;947Game.ship.y = Game.canvasHeight / 2;948if (Game.ship.isClear()) {949Game.ship.rot = 0;950Game.ship.vel.x = 0;951Game.ship.vel.y = 0;952Game.ship.visible = true;953this.state = 'run';954}955},956run: function () {957for (var i = 0; i < Game.sprites.length; i++) {958if (Game.sprites[i].name == 'asteroid') {959break;960}961}962if (i == Game.sprites.length) {963this.state = 'new_level';964}965if (!Game.bigAlien.visible &&966Date.now() > Game.nextBigAlienTime) {967Game.bigAlien.visible = true;968Game.nextBigAlienTime = Date.now() + (30000 * Math.random());969}970},971new_level: function () {972if (this.timer == null) {973this.timer = Date.now();974}975// wait a second before spawning more asteroids976if (Date.now() - this.timer > 1000) {977this.timer = null;978Game.totalAsteroids++;979if (Game.totalAsteroids > 12) Game.totalAsteroids = 12;980Game.spawnAsteroids();981this.state = 'run';982}983},984player_died: function () {985if (Game.lives < 0) {986this.state = 'end_game';987} else {988if (this.timer == null) {989this.timer = Date.now();990}991// wait a second before spawning992if (Date.now() - this.timer > 1000) {993this.timer = null;994this.state = 'spawn_ship';995}996}997},998end_game: function () {999Text.renderText('GAME OVER', 50, Game.canvasWidth/2 - 160, Game.canvasHeight/2 + 10);1000if (this.timer == null) {1001this.timer = Date.now();1002}1003// wait 5 seconds then go back to waiting state1004if (Date.now() - this.timer > 5000) {1005this.timer = null;1006this.state = 'waiting';1007}10081009window.gameStart = false;1010},10111012execute: function () {1013this[this.state]();1014},1015state: 'boot'1016}10171018};101910201021$(function () {1022var canvas = $("#canvas");1023Game.canvasWidth = canvas.width();1024Game.canvasHeight = canvas.height();10251026var context = canvas[0].getContext("2d");10271028Text.context = context;1029Text.face = vector_battle;10301031var gridWidth = Math.round(Game.canvasWidth / GRID_SIZE);1032var gridHeight = Math.round(Game.canvasHeight / GRID_SIZE);1033var grid = new Array(gridWidth);1034for (var i = 0; i < gridWidth; i++) {1035grid[i] = new Array(gridHeight);1036for (var j = 0; j < gridHeight; j++) {1037grid[i][j] = new GridNode();1038}1039}10401041// set up the positional references1042for (var i = 0; i < gridWidth; i++) {1043for (var j = 0; j < gridHeight; j++) {1044var node = grid[i][j];1045node.north = grid[i][(j == 0) ? gridHeight-1 : j-1];1046node.south = grid[i][(j == gridHeight-1) ? 0 : j+1];1047node.west = grid[(i == 0) ? gridWidth-1 : i-1][j];1048node.east = grid[(i == gridWidth-1) ? 0 : i+1][j];1049}1050}10511052// set up borders1053for (var i = 0; i < gridWidth; i++) {1054grid[i][0].dupe.vertical = Game.canvasHeight;1055grid[i][gridHeight-1].dupe.vertical = -Game.canvasHeight;1056}10571058for (var j = 0; j < gridHeight; j++) {1059grid[0][j].dupe.horizontal = Game.canvasWidth;1060grid[gridWidth-1][j].dupe.horizontal = -Game.canvasWidth;1061}10621063var sprites = [];1064Game.sprites = sprites;10651066// so all the sprites can use it1067Sprite.prototype.context = context;1068Sprite.prototype.grid = grid;1069Sprite.prototype.matrix = new Matrix(2, 3);10701071var ship = new Ship();10721073ship.x = Game.canvasWidth / 2;1074ship.y = Game.canvasHeight / 2;10751076sprites.push(ship);10771078ship.bullets = [];1079for (var i = 0; i < 10; i++) {1080var bull = new Bullet();1081ship.bullets.push(bull);1082sprites.push(bull);1083}1084Game.ship = ship;10851086var bigAlien = new BigAlien();1087bigAlien.setup();1088sprites.push(bigAlien);1089Game.bigAlien = bigAlien;10901091var extraDude = new Ship();1092extraDude.scale = 0.6;1093extraDude.visible = true;1094extraDude.preMove = null;1095extraDude.children = [];10961097var i, j = 0;10981099var paused = false;1100var showFramerate = false;1101var avgFramerate = 0;1102var frameCount = 0;1103var elapsedCounter = 0;11041105var lastFrame = Date.now();1106var thisFrame;1107var elapsed;1108var delta;11091110var canvasNode = canvas[0];11111112// shim layer with setTimeout fallback1113// from here:1114// http://paulirish.com/2011/requestanimationframe-for-smart-animating/1115window.requestAnimFrame = (function () {1116return window.requestAnimationFrame ||1117window.webkitRequestAnimationFrame ||1118window.mozRequestAnimationFrame ||1119window.oRequestAnimationFrame ||1120window.msRequestAnimationFrame ||1121function (/* function */ callback, /* DOMElement */ element) {1122window.setTimeout(callback, 1000 / 60);1123};1124})();11251126var mainLoop = function () {1127context.clearRect(0, 0, Game.canvasWidth, Game.canvasHeight);11281129Game.FSM.execute();11301131if (KEY_STATUS.g) {1132context.beginPath();1133for (var i = 0; i < gridWidth; i++) {1134context.moveTo(i * GRID_SIZE, 0);1135context.lineTo(i * GRID_SIZE, Game.canvasHeight);1136}1137for (var j = 0; j < gridHeight; j++) {1138context.moveTo(0, j * GRID_SIZE);1139context.lineTo(Game.canvasWidth, j * GRID_SIZE);1140}1141context.closePath();1142context.stroke();1143}11441145thisFrame = Date.now();1146elapsed = thisFrame - lastFrame;1147lastFrame = thisFrame;1148delta = elapsed / 30;11491150for (i = 0; i < sprites.length; i++) {11511152sprites[i].run(delta);11531154if (sprites[i].reap) {1155sprites[i].reap = false;1156sprites.splice(i, 1);1157i--;1158}1159}11601161// score1162var score_text = ''+Game.score;1163Text.renderText(score_text, 18, Game.canvasWidth - 14 * score_text.length, 20);11641165// extra dudes1166for (i = 0; i < Game.lives; i++) {1167context.save();1168extraDude.x = Game.canvasWidth - (8 * (i + 1));1169extraDude.y = 32;1170extraDude.configureTransform();1171extraDude.draw();1172context.restore();1173}11741175if (showFramerate) {1176Text.renderText(''+avgFramerate, 24, Game.canvasWidth - 38, Game.canvasHeight - 2);1177}11781179frameCount++;1180elapsedCounter += elapsed;1181if (elapsedCounter > 1000) {1182elapsedCounter -= 1000;1183avgFramerate = frameCount;1184frameCount = 0;1185}11861187if (paused) {1188Text.renderText('PAUSED', 72, Game.canvasWidth/2 - 160, 120);1189} else {1190requestAnimFrame(mainLoop, canvasNode);1191}1192};11931194mainLoop();11951196$(window).keydown(function (e) {1197switch (KEY_CODES[e.keyCode]) {1198case 'f': // show framerate1199showFramerate = !showFramerate;1200break;1201case 'p': // pause1202paused = !paused;1203if (!paused) {1204// start up again1205lastFrame = Date.now();1206mainLoop();1207}1208break;1209case 'm': // mute1210SFX.muted = !SFX.muted;1211break;1212}1213});1214});12151216// vim: fdl=0121712181219