Path: blob/main/static/src/gs/public/radius-raid/js/game.js
1325 views
/*==============================================================================1Init2==============================================================================*/3$.init = function() {4$.setupStorage();5$.wrap = document.getElementById( 'wrap' );6$.wrapInner = document.getElementById( 'wrap-inner' );7$.cbg1 = document.getElementById( 'cbg1' );8$.cbg2 = document.getElementById( 'cbg2' );9$.cbg3 = document.getElementById( 'cbg3' );10$.cbg4 = document.getElementById( 'cbg4' );11$.cmg = document.getElementById( 'cmg' );12$.cfg = document.getElementById( 'cfg' );13$.ctxbg1 = $.cbg1.getContext( '2d' );14$.ctxbg2 = $.cbg2.getContext( '2d' );15$.ctxbg3 = $.cbg3.getContext( '2d' );16$.ctxbg4 = $.cbg4.getContext( '2d' );17$.ctxmg = $.cmg.getContext( '2d' );18$.ctxfg = $.cfg.getContext( '2d' );19$.cw = $.cmg.width = $.cfg.width = 800;20$.ch = $.cmg.height = $.cfg.height = 600;21$.wrap.style.width = $.wrapInner.style.width = $.cw + 'px';22$.wrap.style.height = $.wrapInner.style.height = $.ch + 'px';23$.wrap.style.marginLeft = ( -$.cw / 2 ) - 10 + 'px';24$.wrap.style.marginTop = ( -$.ch / 2 ) - 10 + 'px';25$.ww = Math.floor( $.cw * 2 );26$.wh = Math.floor( $.ch * 2 );27$.cbg1.width = Math.floor( $.cw * 1.1 );28$.cbg1.height = Math.floor( $.ch * 1.1 );29$.cbg2.width = Math.floor( $.cw * 1.15 );30$.cbg2.height = Math.floor( $.ch * 1.15 );31$.cbg3.width = Math.floor( $.cw * 1.2 );32$.cbg3.height = Math.floor( $.ch * 1.2 );33$.cbg4.width = Math.floor( $.cw * 1.25 );34$.cbg4.height = Math.floor( $.ch * 1.25 );3536$.screen = {37x: ( $.ww - $.cw ) / -2,38y: ( $.wh - $.ch ) / -239};4041$.mute = $.storage['mute'];42$.autofire = $.storage['autofire'];43$.slowEnemyDivider = 3;4445$.keys = {46state: {47up: 0,48down: 0,49left: 0,50right: 0,51f: 0,52m: 0,53p: 054},55pressed: {56up: 0,57down: 0,58left: 0,59right: 0,60f: 0,61m: 0,62p: 063}64};65$.okeys = {};66$.mouse = {67x: $.ww / 2,68y: $.wh / 2,69sx: 0,70sy: 0,71ax: window.innerWidth / 2,72ay: 0,73down: 074};75$.buttons = [];7677$.minimap = {78x: 20,79y: $.ch - Math.floor( $.ch * 0.1 ) - 20,80width: Math.floor( $.cw * 0.1 ),81height: Math.floor( $.ch * 0.1 ),82scale: Math.floor( $.cw * 0.1 ) / $.ww,83color: 'hsla(0, 0%, 0%, 0.85)',84strokeColor: '#3a3a3a'85},86$.cOffset = {87left: 0,88top: 089};9091$.levelCount = $.definitions.levels.length;92$.states = {};93$.state = '';94$.enemies = [];95$.bullets = [];96$.explosions = [];97$.powerups = [];98$.particleEmitters = [];99$.textPops = [];100$.levelPops = [];101$.powerupTimers = [];102103$.resizecb();104$.bindEvents();105$.setupStates();106$.renderBackground1();107$.renderBackground2();108$.renderBackground3();109$.renderBackground4();110$.renderForeground();111$.renderFavicon();112$.setState( 'menu' );113$.loop();114};115116/*==============================================================================117Reset118==============================================================================*/119$.reset = function() {120$.indexGlobal = 0;121$.dt = 1;122$.lt = 0;123$.elapsed = 0;124$.tick = 0;125126$.gameoverTick = 0;127$.gameoverTickMax = 200;128$.gameoverExplosion = 0;129130$.instructionTick = 0;131$.instructionTickMax = 400;132133$.levelDiffOffset = 0;134$.enemyOffsetMod = 0;135$.slow = 0;136137$.screen = {138x: ( $.ww - $.cw ) / -2,139y: ( $.wh - $.ch ) / -2140};141$.rumble = {142x: 0,143y: 0,144level: 0,145decay: 0.4146};147148$.mouse.down = 0;149150$.level = {151current: 0,152kills: 0,153killsToLevel: $.definitions.levels[ 0 ].killsToLevel,154distribution: $.definitions.levels[ 0 ].distribution,155distributionCount: $.definitions.levels[ 0 ].distribution.length156};157158$.enemies.length = 0;159$.bullets.length = 0;160$.explosions.length = 0;161$.powerups.length = 0;162$.particleEmitters.length = 0;163$.textPops.length = 0;164$.levelPops.length = 0;165$.powerupTimers.length = 0;166167for( var i = 0; i < $.definitions.powerups.length; i++ ) {168$.powerupTimers.push( 0 );169}170171$.kills = 0;172$.bulletsFired = 0;173$.powerupsCollected = 0;174$.score = 0;175176$.hero = new $.Hero();177178$.levelPops.push( new $.LevelPop( {179level: 1180} ) );181};182183/*==============================================================================184Create Favicon185==============================================================================*/186$.renderFavicon = function() {187var favicon = document.getElementById( 'favicon' ),188favc = document.createElement( 'canvas' ),189favctx = favc.getContext( '2d' ),190faviconGrid = [191[ 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1 ],192[ 1, , , , , , , , , , , , , , , 1 ],193[ 1, , , , , , , , , , , , , , , 1 ],194[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],195[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],196[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],197[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],198[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],199[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],200[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],201[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],202[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],203[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],204[ 1, , , , , , , , , , , , , , , 1 ],205[ 1, , , , , , , , , , , , , , , 1 ],206[ 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1 ]207];208favc.width = favc.height = 16;209favctx.beginPath();210for( var y = 0; y < 16; y++ ) {211for( var x = 0; x < 16; x++ ) {212if( faviconGrid[ y ][ x ] === 1 ) {213favctx.rect( x, y, 1, 1 );214}215}216}217favctx.fill();218favicon.href = favc.toDataURL();219};220221/*==============================================================================222Render Backgrounds223==============================================================================*/224$.renderBackground1 = function() {225var gradient = $.ctxbg1.createRadialGradient( $.cbg1.width / 2, $.cbg1.height / 2, 0, $.cbg1.width / 2, $.cbg1.height / 2, $.cbg1.height );226gradient.addColorStop( 0, 'hsla(0, 0%, 100%, 0.1)' );227gradient.addColorStop( 0.65, 'hsla(0, 0%, 100%, 0)' );228$.ctxbg1.fillStyle = gradient;229$.ctxbg1.fillRect( 0, 0, $.cbg1.width, $.cbg1.height );230231var i = 2000;232while( i-- ) {233$.util.fillCircle( $.ctxbg1, $.util.rand( 0, $.cbg1.width ), $.util.rand( 0, $.cbg1.height ), $.util.rand( 0.2, 0.5 ), 'hsla(0, 0%, 100%, ' + $.util.rand( 0.05, 0.2 ) + ')' );234}235236var i = 800;237while( i-- ) {238$.util.fillCircle( $.ctxbg1, $.util.rand( 0, $.cbg1.width ), $.util.rand( 0, $.cbg1.height ), $.util.rand( 0.1, 0.8 ), 'hsla(0, 0%, 100%, ' + $.util.rand( 0.05, 0.5 ) + ')' );239}240}241242$.renderBackground2 = function() {243var i = 80;244while( i-- ) {245$.util.fillCircle( $.ctxbg2, $.util.rand( 0, $.cbg2.width ), $.util.rand( 0, $.cbg2.height ), $.util.rand( 1, 2 ), 'hsla(0, 0%, 100%, ' + $.util.rand( 0.05, 0.15 ) + ')' );246}247}248249$.renderBackground3 = function() {250var i = 40;251while( i-- ) {252$.util.fillCircle( $.ctxbg3, $.util.rand( 0, $.cbg3.width ), $.util.rand( 0, $.cbg3.height ), $.util.rand( 1, 2.5 ), 'hsla(0, 0%, 100%, ' + $.util.rand( 0.05, 0.1 ) + ')' );253}254}255256$.renderBackground4 = function() {257var size = 50;258$.ctxbg4.fillStyle = 'hsla(0, 0%, 50%, 0.05)';259var i = Math.round( $.cbg4.height / size );260while( i-- ) {261$.ctxbg4.fillRect( 0, i * size + 25, $.cbg4.width, 1 );262}263i = Math.round( $.cbg4.width / size );264while( i-- ) {265$.ctxbg4.fillRect( i * size, 0, 1, $.cbg4.height );266}267}268269/*==============================================================================270Render Foreground271==============================================================================*/272$.renderForeground = function() {273var gradient = $.ctxfg.createRadialGradient( $.cw / 2, $.ch / 2, $.ch / 3, $.cw / 2, $.ch / 2, $.ch );274gradient.addColorStop( 0, 'hsla(0, 0%, 0%, 0)' );275gradient.addColorStop( 1, 'hsla(0, 0%, 0%, 0.5)' );276$.ctxfg.fillStyle = gradient;277$.ctxfg.fillRect( 0, 0, $.cw, $.ch );278279$.ctxfg.fillStyle = 'hsla(0, 0%, 50%, 0.1)';280var i = Math.round( $.ch / 2 );281while( i-- ) {282$.ctxfg.fillRect( 0, i * 2, $.cw, 1 );283}284285var gradient2 = $.ctxfg.createLinearGradient( $.cw, 0, 0, $.ch );286gradient2.addColorStop( 0, 'hsla(0, 0%, 100%, 0.04)' );287gradient2.addColorStop( 0.75, 'hsla(0, 0%, 100%, 0)' );288$.ctxfg.beginPath();289$.ctxfg.moveTo( 0, 0 );290$.ctxfg.lineTo( $.cw, 0 );291$.ctxfg.lineTo( 0, $.ch );292$.ctxfg.closePath();293$.ctxfg.fillStyle = gradient2;294$.ctxfg.fill();295}296297/*==============================================================================298User Interface / UI / GUI / Minimap299==============================================================================*/300301$.renderInterface = function() {302/*==============================================================================303Powerup Timers304==============================================================================*/305for( var i = 0; i < $.definitions.powerups.length; i++ ) {306var powerup = $.definitions.powerups[ i ],307powerupOn = ( $.powerupTimers[ i ] > 0 );308$.ctxmg.beginPath();309var powerupText = $.text( {310ctx: $.ctxmg,311x: $.minimap.x + $.minimap.width + 90,312y: $.minimap.y + 4 + ( i * 12 ),313text: powerup.title,314hspacing: 1,315vspacing: 1,316halign: 'right',317valign: 'top',318scale: 1,319snap: 1,320render: 1321} );322if( powerupOn ) {323$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + ( 0.25 + ( ( $.powerupTimers[ i ] / 300 ) * 0.75 ) ) + ')';324} else {325$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';326}327$.ctxmg.fill();328if( powerupOn ) {329var powerupBar = {330x: powerupText.ex + 5,331y: powerupText.sy,332width: 110,333height: 5334};335$.ctxmg.fillStyle = 'hsl(' + powerup.hue + ', ' + powerup.saturation + '%, ' + powerup.lightness + '%)';336$.ctxmg.fillRect( powerupBar.x, powerupBar.y, ( $.powerupTimers[ i ] / 300 ) * powerupBar.width, powerupBar.height );337}338}339340/*==============================================================================341Instructions342==============================================================================*/343if( $.instructionTick < $.instructionTickMax ){344$.instructionTick += $.dt;345$.ctxmg.beginPath();346$.text( {347ctx: $.ctxmg,348x: $.cw / 2 - 10,349y: $.ch - 20,350text: 'MOVE\nAIM/FIRE\nAUTOFIRE\nPAUSE\nMUTE',351hspacing: 1,352vspacing: 17,353halign: 'right',354valign: 'bottom',355scale: 2,356snap: 1,357render: 1358} );359if( $.instructionTick < $.instructionTickMax * 0.25 ) {360var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 0.5;361} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {362var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 0.5;363} else {364var alpha = 0.5;365}366alpha = Math.min( 1, Math.max( 0, alpha ) );367368$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';369$.ctxmg.fill();370371$.ctxmg.beginPath();372$.text( {373ctx: $.ctxmg,374x: $.cw / 2 + 10,375y: $.ch - 20,376text: 'WASD/ARROWS\nMOUSE\nF\nP\nM',377hspacing: 1,378vspacing: 17,379halign: 'left',380valign: 'bottom',381scale: 2,382snap: 1,383render: 1384} );385if( $.instructionTick < $.instructionTickMax * 0.25 ) {386var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 1;387} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {388var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 1;389} else {390var alpha = 1;391}392alpha = Math.min( 1, Math.max( 0, alpha ) );393394$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';395$.ctxmg.fill();396}397398/*==============================================================================399Slow Enemies Screen Cover400==============================================================================*/401if( $.powerupTimers[ 1 ] > 0 ) {402$.ctxmg.fillStyle = 'hsla(200, 100%, 20%, 0.05)';403$.ctxmg.fillRect( 0, 0, $.cw, $.ch );404}405406/*==============================================================================407Health408==============================================================================*/409$.ctxmg.beginPath();410var healthText = $.text( {411ctx: $.ctxmg,412x: 20,413y: 20,414text: 'HEALTH',415hspacing: 1,416vspacing: 1,417halign: 'top',418valign: 'left',419scale: 2,420snap: 1,421render: 1422} );423$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';424$.ctxmg.fill();425var healthBar = {426x: healthText.ex + 10,427y: healthText.sy,428width: 110,429height: 10430};431$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';432$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height );433$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';434$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height / 2 );435$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 40%, 1)';436$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height );437$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 75%, 1)';438$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height / 2 );439440if( $.hero.takingDamage && $.hero.life > 0.01 ) {441$.particleEmitters.push( new $.ParticleEmitter( {442x: -$.screen.x + healthBar.x + $.hero.life * healthBar.width,443y: -$.screen.y + healthBar.y + healthBar.height / 2,444count: 1,445spawnRange: 2,446friction: 0.85,447minSpeed: 2,448maxSpeed: 20,449minDirection: $.pi / 2 - 0.2,450maxDirection: $.pi / 2 + 0.2,451hue: $.hero.life * 120,452saturation: 100453} ) );454}455456/*==============================================================================457Progress458==============================================================================*/459$.ctxmg.beginPath();460var progressText = $.text( {461ctx: $.ctxmg,462x: healthBar.x + healthBar.width + 40,463y: 20,464text: 'PROGRESS',465hspacing: 1,466vspacing: 1,467halign: 'top',468valign: 'left',469scale: 2,470snap: 1,471render: 1472} );473$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';474$.ctxmg.fill();475var progressBar = {476x: progressText.ex + 10,477y: progressText.sy,478width: healthBar.width,479height: healthBar.height480};481$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';482$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height );483$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';484$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height / 2 );485$.ctxmg.fillStyle = 'hsla(0, 0%, 50%, 1)';486$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height );487$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';488$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height / 2 );489490if( $.level.kills == $.level.killsToLevel ) {491$.particleEmitters.push( new $.ParticleEmitter( {492x: -$.screen.x + progressBar.x + progressBar.width,493y: -$.screen.y + progressBar.y + progressBar.height / 2,494count: 30,495spawnRange: 5,496friction: 0.95,497minSpeed: 2,498maxSpeed: 25,499minDirection: 0,500minDirection: $.pi / 2 - $.pi / 4,501maxDirection: $.pi / 2 + $.pi / 4,502hue: 0,503saturation: 0504} ) );505}506507/*==============================================================================508Score509==============================================================================*/510$.ctxmg.beginPath();511var scoreLabel = $.text( {512ctx: $.ctxmg,513x: progressBar.x + progressBar.width + 40,514y: 20,515text: 'SCORE',516hspacing: 1,517vspacing: 1,518halign: 'top',519valign: 'left',520scale: 2,521snap: 1,522render: 1523} );524$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';525$.ctxmg.fill();526527$.ctxmg.beginPath();528var scoreText = $.text( {529ctx: $.ctxmg,530x: scoreLabel.ex + 10,531y: 20,532text: $.util.pad( $.score, 6 ),533hspacing: 1,534vspacing: 1,535halign: 'top',536valign: 'left',537scale: 2,538snap: 1,539render: 1540} );541$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';542$.ctxmg.fill();543544$.ctxmg.beginPath();545var bestLabel = $.text( {546ctx: $.ctxmg,547x: scoreText.ex + 40,548y: 20,549text: 'BEST',550hspacing: 1,551vspacing: 1,552halign: 'top',553valign: 'left',554scale: 2,555snap: 1,556render: 1557} );558$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';559$.ctxmg.fill();560561$.ctxmg.beginPath();562var bestText = $.text( {563ctx: $.ctxmg,564x: bestLabel.ex + 10,565y: 20,566text: $.util.pad( Math.max( $.storage['score'], $.score ), 6 ),567hspacing: 1,568vspacing: 1,569halign: 'top',570valign: 'left',571scale: 2,572snap: 1,573render: 1574} );575$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';576$.ctxmg.fill();577};578579$.renderMinimap = function() {580$.ctxmg.fillStyle = $.minimap.color;581$.ctxmg.fillRect( $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height );582583$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.1)';584$.ctxmg.fillRect(585Math.floor( $.minimap.x + -$.screen.x * $.minimap.scale ),586Math.floor( $.minimap.y + -$.screen.y * $.minimap.scale ),587Math.floor( $.cw * $.minimap.scale ),588Math.floor( $.ch * $.minimap.scale )589);590591//$.ctxmg.beginPath();592for( var i = 0; i < $.enemies.length; i++ ){593var enemy = $.enemies[ i ],594x = $.minimap.x + Math.floor( enemy.x * $.minimap.scale ),595y = $.minimap.y + Math.floor( enemy.y * $.minimap.scale );596if( $.util.pointInRect( x + 1, y + 1, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {597//$.ctxmg.rect( x, y, 2, 2 );598$.ctxmg.fillStyle = 'hsl(' + enemy.hue + ', ' + enemy.saturation + '%, 50%)';599$.ctxmg.fillRect( x, y, 2, 2 );600}601}602//$.ctxmg.fillStyle = '#f00';603//$.ctxmg.fill();604605$.ctxmg.beginPath();606for( var i = 0; i < $.bullets.length; i++ ){607var bullet = $.bullets[ i ],608x = $.minimap.x + Math.floor( bullet.x * $.minimap.scale ),609y = $.minimap.y + Math.floor( bullet.y * $.minimap.scale );610if( $.util.pointInRect( x, y, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {611$.ctxmg.rect( x, y, 1, 1 );612}613}614$.ctxmg.fillStyle = '#fff';615$.ctxmg.fill();616617$.ctxmg.fillStyle = $.hero.fillStyle;618$.ctxmg.fillRect( $.minimap.x + Math.floor( $.hero.x * $.minimap.scale ), $.minimap.y + Math.floor( $.hero.y * $.minimap.scale ), 2, 2 );619620$.ctxmg.strokeStyle = $.minimap.strokeColor;621$.ctxmg.strokeRect( $.minimap.x - 0.5, $.minimap.y - 0.5, $.minimap.width + 1, $.minimap.height + 1 );622};623624/*==============================================================================625Enemy Spawning626==============================================================================*/627$.getSpawnCoordinates = function( radius ) {628var quadrant = Math.floor( $.util.rand( 0, 4 ) ),629x,630y,631start;632633if( quadrant === 0){634x = $.util.rand( 0, $.ww );635y = -radius;636start = 'top';637} else if( quadrant === 1 ){638x = $.ww + radius;639y = $.util.rand( 0, $.wh );640start = 'right';641} else if( quadrant === 2 ) {642x = $.util.rand( 0, $.ww );643y = $.wh + radius;644start = 'bottom';645} else {646x = -radius;647y = $.util.rand( 0, $.wh );648start = 'left';649}650651return { x: x, y: y, start: start };652};653654$.spawnEnemy = function( type ) {655var params = $.definitions.enemies[ type ],656coordinates = $.getSpawnCoordinates( params.radius );657params.x = coordinates.x;658params.y = coordinates.y;659params.start = coordinates.start;660params.type = type;661return new $.Enemy( params );662};663664$.spawnEnemies = function() {665var floorTick = Math.floor( $.tick );666for( var i = 0; i < $.level.distributionCount; i++ ) {667var timeCheck = $.level.distribution[ i ];668if( $.levelDiffOffset > 0 ){669timeCheck = Math.max( 1, timeCheck - ( $.levelDiffOffset * 2) );670}671if( floorTick % timeCheck === 0 ) {672$.enemies.push( $.spawnEnemy( i ) );673}674}675};676677/*==============================================================================678Events679==============================================================================*/680$.mousemovecb = function( e ) {681e.preventDefault();682$.mouse.ax = e.pageX;683$.mouse.ay = e.pageY;684$.mousescreen();685};686687$.mousescreen = function() {688$.mouse.sx = $.mouse.ax - $.cOffset.left;689$.mouse.sy = $.mouse.ay - $.cOffset.top;690$.mouse.x = $.mouse.sx - $.screen.x;691$.mouse.y = $.mouse.sy - $.screen.y;692};693694$.mousedowncb = function( e ) {695e.preventDefault();696$.mouse.down = 1;697};698699$.mouseupcb = function( e ) {700e.preventDefault();701$.mouse.down = 0;702};703704$.keydowncb = function( e ) {705var e = ( e.keyCode ? e.keyCode : e.which );706if( e === 38 || e === 87 ){ $.keys.state.up = 1; }707if( e === 39 || e === 68 ){ $.keys.state.right = 1; }708if( e === 40 || e === 83 ){ $.keys.state.down = 1; }709if( e === 37 || e === 65 ){ $.keys.state.left = 1; }710if( e === 70 ){ $.keys.state.f = 1; }711if( e === 77 ){ $.keys.state.m = 1; }712if( e === 80 ){ $.keys.state.p = 1; }713}714715$.keyupcb = function( e ) {716var e = ( e.keyCode ? e.keyCode : e.which );717if( e === 38 || e === 87 ){ $.keys.state.up = 0; }718if( e === 39 || e === 68 ){ $.keys.state.right = 0; }719if( e === 40 || e === 83 ){ $.keys.state.down = 0; }720if( e === 37 || e === 65 ){ $.keys.state.left = 0; }721if( e === 70 ){ $.keys.state.f = 0; }722if( e === 77 ){ $.keys.state.m = 0; }723if( e === 80 ){ $.keys.state.p = 0; }724}725726$.resizecb = function( e ) {727var rect = $.cmg.getBoundingClientRect();728$.cOffset = {729left: rect.left,730top: rect.top731}732}733734$.blurcb = function() {735if( $.state == 'play' ){736$.setState( 'pause' );737}738}739740$.bindEvents = function() {741window.addEventListener( 'mousemove', $.mousemovecb );742window.addEventListener( 'mousedown', $.mousedowncb );743window.addEventListener( 'mouseup', $.mouseupcb );744window.addEventListener( 'keydown', $.keydowncb );745window.addEventListener( 'keyup', $.keyupcb );746window.addEventListener( 'resize', $.resizecb );747window.addEventListener( 'blur', $.blurcb );748};749750/*==============================================================================751Miscellaneous752==============================================================================*/753$.clearScreen = function() {754$.ctxmg.clearRect( 0, 0, $.cw, $.ch );755};756757$.updateDelta = function() {758var now = Date.now();759$.dt = ( now - $.lt ) / ( 1000 / 60 );760$.dt = ( $.dt < 0 ) ? 0.001 : $.dt;761$.dt = ( $.dt > 10 ) ? 10 : $.dt;762$.lt = now;763$.elapsed += $.dt;764};765766$.updateScreen = function() {767var xSnap,768xModify,769ySnap,770yModify;771772if( $.hero.x < $.cw / 2 ) {773xModify = $.hero.x / $.cw;774} else if( $.hero.x > $.ww - $.cw / 2 ) {775xModify = 1 - ( $.ww - $.hero.x ) / $.cw;776} else {777xModify = 0.5;778}779780if( $.hero.y < $.ch / 2 ) {781yModify = $.hero.y / $.ch;782} else if( $.hero.y > $.wh - $.ch / 2 ) {783yModify = 1 - ( $.wh - $.hero.y ) / $.ch;784} else {785yModify = 0.5;786}787788xSnap = ( ( $.cw * xModify - $.hero.x ) - $.screen.x ) / 30;789ySnap = ( ( $.ch * yModify - $.hero.y ) - $.screen.y ) / 30;790791// ease to new coordinates792$.screen.x += xSnap * $.dt;793$.screen.y += ySnap * $.dt;794795// update rumble levels, keep X and Y changes consistent, apply rumble796if( $.rumble.level > 0 ) {797$.rumble.level -= $.rumble.decay;798$.rumble.level = ( $.rumble.level < 0 ) ? 0 : $.rumble.level;799$.rumble.x = $.util.rand( -$.rumble.level, $.rumble.level );800$.rumble.y = $.util.rand( -$.rumble.level, $.rumble.level );801} else {802$.rumble.x = 0;803$.rumble.y = 0;804}805806//$.screen.x -= $.rumble.x;807//$.screen.y -= $.rumble.y;808809// animate background canvas810$.cbg1.style.marginLeft =811-( ( $.cbg1.width - $.cw ) / 2 ) // half the difference from bg to viewport812- ( ( $.cbg1.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below813* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg814- $.rumble.x + 'px';815$.cbg1.style.marginTop =816-( ( $.cbg1.height - $.ch ) / 2 )817- ( ( $.cbg1.height - $.ch ) / 2 )818* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )819- $.rumble.y + 'px';820$.cbg2.style.marginLeft =821-( ( $.cbg2.width - $.cw ) / 2 ) // half the difference from bg to viewport822- ( ( $.cbg2.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below823* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg824- $.rumble.x + 'px';825$.cbg2.style.marginTop =826-( ( $.cbg2.height - $.ch ) / 2 )827- ( ( $.cbg2.height - $.ch ) / 2 )828* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )829- $.rumble.y + 'px';830$.cbg3.style.marginLeft =831-( ( $.cbg3.width - $.cw ) / 2 ) // half the difference from bg to viewport832- ( ( $.cbg3.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below833* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg834- $.rumble.x + 'px';835$.cbg3.style.marginTop =836-( ( $.cbg3.height - $.ch ) / 2 )837- ( ( $.cbg3.height - $.ch ) / 2 )838* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )839- $.rumble.y + 'px';840$.cbg4.style.marginLeft =841-( ( $.cbg4.width - $.cw ) / 2 ) // half the difference from bg to viewport842- ( ( $.cbg4.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below843* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg844- $.rumble.x + 'px';845$.cbg4.style.marginTop =846-( ( $.cbg4.height - $.ch ) / 2 )847- ( ( $.cbg4.height - $.ch ) / 2 )848* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )849- $.rumble.y + 'px';850851$.mousescreen();852};853854$.updateLevel = function() {855if( $.level.kills >= $.level.killsToLevel ) {856if( $.level.current + 1 < $.levelCount ){857$.level.current++;858$.level.kills = 0;859$.level.killsToLevel = $.definitions.levels[ $.level.current ].killsToLevel;860$.level.distribution = $.definitions.levels[ $.level.current ].distribution;861$.level.distributionCount = $.level.distribution.length;862} else {863$.level.current++;864$.level.kills = 0;865// no more level definitions, so take the last level and increase the spawn rate slightly866//for( var i = 0; i < $.level.distributionCount; i++ ) {867//$.level.distribution[ i ] = Math.max( 1, $.level.distribution[ i ] - 5 );868//}869}870$.levelDiffOffset = $.level.current + 1 - $.levelCount;871$.levelPops.push( new $.LevelPop( {872level: $.level.current + 1873} ) );874}875};876877$.updatePowerupTimers = function() {878// HEALTH879if( $.powerupTimers[ 0 ] > 0 ){880if( $.hero.life < 1 ) {881$.hero.life += 0.001;882}883if( $.hero.life > 1 ) {884$.hero.life = 1;885}886$.powerupTimers[ 0 ] -= $.dt;887}888889// SLOW ENEMIES890if( $.powerupTimers[ 1 ] > 0 ){891$.slow = 1;892$.powerupTimers[ 1 ] -= $.dt;893} else {894$.slow = 0;895}896897// FAST SHOT898if( $.powerupTimers[ 2 ] > 0 ){899$.hero.weapon.fireRate = 2;900$.hero.weapon.bullet.speed = 14;901$.powerupTimers[ 2 ] -= $.dt;902} else {903$.hero.weapon.fireRate = 5;904$.hero.weapon.bullet.speed = 10;905}906907// TRIPLE SHOT908if( $.powerupTimers[ 3 ] > 0 ){909$.hero.weapon.count = 3;910$.powerupTimers[ 3 ] -= $.dt;911} else {912$.hero.weapon.count = 1;913}914915// PIERCE SHOT916if( $.powerupTimers[ 4 ] > 0 ){917$.hero.weapon.bullet.piercing = 1;918$.powerupTimers[ 4 ] -= $.dt;919} else {920$.hero.weapon.bullet.piercing = 0;921}922};923924$.spawnPowerup = function( x, y ) {925if( Math.random() < 0.1 ) {926var min = ( $.hero.life < 0.9 ) ? 0 : 1,927type = Math.floor( $.util.rand( min, $.definitions.powerups.length ) ),928params = $.definitions.powerups[ type ];929params.type = type;930params.x = x;931params.y = y;932$.powerups.push( new $.Powerup( params ) );933}934};935936/*==============================================================================937States938==============================================================================*/939$.setState = function( state ) {940// handle clean up between states941$.buttons.length = 0;942943if( state == 'menu' ) {944$.mouse.down = 0;945$.mouse.ax = 0;946$.mouse.ay = 0;947948$.reset();949950var playButton = new $.Button( {951x: $.cw / 2 + 1,952y: $.ch / 2 - 24,953lockedWidth: 299,954lockedHeight: 49,955scale: 3,956title: 'PLAY',957action: function() {958$.reset();959$.audio.play( 'levelup' );960$.setState( 'play' );961}962} );963$.buttons.push( playButton );964965var statsButton = new $.Button( {966x: $.cw / 2 + 1,967y: playButton.ey + 25,968lockedWidth: 299,969lockedHeight: 49,970scale: 3,971title: 'STATS',972action: function() {973$.setState( 'stats' );974}975} );976$.buttons.push( statsButton );977978var creditsButton = new $.Button( {979x: $.cw / 2 + 1,980y: statsButton.ey + 26,981lockedWidth: 299,982lockedHeight: 49,983scale: 3,984title: 'CREDITS',985action: function() {986$.setState( 'credits' );987}988} ) ;989$.buttons.push( creditsButton );990}991992if( state == 'stats' ) {993$.mouse.down = 0;994995var clearButton = new $.Button( {996x: $.cw / 2 + 1,997y: 426,998lockedWidth: 299,999lockedHeight: 49,1000scale: 3,1001title: 'CLEAR DATA',1002action: function() {1003$.mouse.down = 0;1004if( window.confirm( 'Are you sure you want to clear all locally stored game data? This cannot be undone.') ) {1005$.clearStorage();1006$.mouse.down = 0;1007}1008}1009} );1010$.buttons.push( clearButton );10111012var menuButton = new $.Button( {1013x: $.cw / 2 + 1,1014y: clearButton.ey + 25,1015lockedWidth: 299,1016lockedHeight: 49,1017scale: 3,1018title: 'MENU',1019action: function() {1020$.setState( 'menu' );1021}1022} );1023$.buttons.push( menuButton );1024}10251026if( state == 'credits' ) {1027$.mouse.down = 0;10281029var js13kButton = new $.Button( {1030x: $.cw / 2 + 1,1031y: 476,1032lockedWidth: 299,1033lockedHeight: 49,1034scale: 3,1035title: 'JS13KGAMES',1036action: function() {1037location.href = 'http://js13kgames.com';1038$.mouse.down = 0;1039}1040} );1041$.buttons.push( js13kButton );10421043var menuButton = new $.Button( {1044x: $.cw / 2 + 1,1045y: js13kButton.ey + 25,1046lockedWidth: 299,1047lockedHeight: 49,1048scale: 3,1049title: 'MENU',1050action: function() {1051$.setState( 'menu' );1052}1053} );1054$.buttons.push( menuButton );1055}10561057if( state == 'pause' ) {1058$.mouse.down = 0;1059$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );1060var resumeButton = new $.Button( {1061x: $.cw / 2 + 1,1062y: $.ch / 2 + 26,1063lockedWidth: 299,1064lockedHeight: 49,1065scale: 3,1066title: 'RESUME',1067action: function() {1068$.lt = Date.now() + 1000;1069$.setState( 'play' );1070}1071} );1072$.buttons.push( resumeButton );10731074var menuButton = new $.Button( {1075x: $.cw / 2 + 1,1076y: resumeButton.ey + 25,1077lockedWidth: 299,1078lockedHeight: 49,1079scale: 3,1080title: 'MENU',1081action: function() {1082$.mouse.down = 0;1083if( window.confirm( 'Are you sure you want to end this game and return to the menu?') ) {1084$.mousescreen();1085$.setState( 'menu' );1086}1087}1088} );1089$.buttons.push( menuButton );1090}10911092if( state == 'gameover' ) {1093$.mouse.down = 0;10941095$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );1096var resumeButton = new $.Button( {1097x: $.cw / 2 + 1,1098y: 426,1099lockedWidth: 299,1100lockedHeight: 49,1101scale: 3,1102title: 'PLAY AGAIN',1103action: function() {1104$.reset();1105$.audio.play( 'levelup' );1106$.setState( 'play' );1107}1108} );1109$.buttons.push( resumeButton );11101111var menuButton = new $.Button( {1112x: $.cw / 2 + 1,1113y: resumeButton.ey + 25,1114lockedWidth: 299,1115lockedHeight: 49,1116scale: 3,1117title: 'MENU',1118action: function() {1119$.setState( 'menu' );1120}1121} );1122$.buttons.push( menuButton );11231124$.storage['score'] = Math.max( $.storage['score'], $.score );1125$.storage['level'] = Math.max( $.storage['level'], $.level.current );1126$.storage['rounds'] += 1;1127$.storage['kills'] += $.kills;1128$.storage['bullets'] += $.bulletsFired;1129$.storage['powerups'] += $.powerupsCollected;1130$.storage['time'] += Math.floor( $.elapsed );1131$.updateStorage();1132}11331134// set state1135$.state = state;1136};11371138$.setupStates = function() {1139$.states['menu'] = function() {1140$.clearScreen();1141$.updateScreen();11421143var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }1144i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }11451146$.ctxmg.beginPath();1147var title = $.text( {1148ctx: $.ctxmg,1149x: $.cw / 2,1150y: $.ch / 2 - 100,1151text: 'RADIUS RAID',1152hspacing: 2,1153vspacing: 1,1154halign: 'center',1155valign: 'bottom',1156scale: 10,1157snap: 1,1158render: 11159} );1160gradient = $.ctxmg.createLinearGradient( title.sx, title.sy, title.sx, title.ey );1161gradient.addColorStop( 0, '#fff' );1162gradient.addColorStop( 1, '#999' );1163$.ctxmg.fillStyle = gradient;1164$.ctxmg.fill();11651166$.ctxmg.beginPath();1167var bottomInfo = $.text( {1168ctx: $.ctxmg,1169x: $.cw / 2,1170y: $.ch - 172,1171text: 'CREATED BY JACK RUGILE FOR JS13KGAMES 2013',1172hspacing: 1,1173vspacing: 1,1174halign: 'center',1175valign: 'bottom',1176scale: 1,1177snap: 1,1178render: 11179} );1180$.ctxmg.fillStyle = '#666';1181$.ctxmg.fill();11821183};11841185$.states['stats'] = function() {1186$.clearScreen();11871188$.ctxmg.beginPath();1189var statsTitle = $.text( {1190ctx: $.ctxmg,1191x: $.cw / 2,1192y: 150,1193text: 'STATS',1194hspacing: 3,1195vspacing: 1,1196halign: 'center',1197valign: 'bottom',1198scale: 10,1199snap: 1,1200render: 11201} );1202var gradient = $.ctxmg.createLinearGradient( statsTitle.sx, statsTitle.sy, statsTitle.sx, statsTitle.ey );1203gradient.addColorStop( 0, '#fff' );1204gradient.addColorStop( 1, '#999' );1205$.ctxmg.fillStyle = gradient;1206$.ctxmg.fill();12071208$.ctxmg.beginPath();1209var statKeys = $.text( {1210ctx: $.ctxmg,1211x: $.cw / 2 - 10,1212y: statsTitle.ey + 39,1213text: 'BEST SCORE\nBEST LEVEL\nROUNDS PLAYED\nENEMIES KILLED\nBULLETS FIRED\nPOWERUPS COLLECTED\nTIME ELAPSED',1214hspacing: 1,1215vspacing: 17,1216halign: 'right',1217valign: 'top',1218scale: 2,1219snap: 1,1220render: 11221} );1222$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';1223$.ctxmg.fill();12241225$.ctxmg.beginPath();1226var statsValues = $.text( {1227ctx: $.ctxmg,1228x: $.cw / 2 + 10,1229y: statsTitle.ey + 39,1230text:1231$.util.commas( $.storage['score'] ) + '\n' +1232( $.storage['level'] + 1 ) + '\n' +1233$.util.commas( $.storage['rounds'] ) + '\n' +1234$.util.commas( $.storage['kills'] ) + '\n' +1235$.util.commas( $.storage['bullets'] ) + '\n' +1236$.util.commas( $.storage['powerups'] ) + '\n' +1237$.util.convertTime( ( $.storage['time'] * ( 1000 / 60 ) ) / 1000 )1238,1239hspacing: 1,1240vspacing: 17,1241halign: 'left',1242valign: 'top',1243scale: 2,1244snap: 1,1245render: 11246} );1247$.ctxmg.fillStyle = '#fff';1248$.ctxmg.fill();12491250var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }1251i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }1252};12531254$.states['credits'] = function() {1255$.clearScreen();12561257$.ctxmg.beginPath();1258var creditsTitle = $.text( {1259ctx: $.ctxmg,1260x: $.cw / 2,1261y: 100,1262text: 'CREDITS',1263hspacing: 3,1264vspacing: 1,1265halign: 'center',1266valign: 'bottom',1267scale: 10,1268snap: 1,1269render: 11270} );1271var gradient = $.ctxmg.createLinearGradient( creditsTitle.sx, creditsTitle.sy, creditsTitle.sx, creditsTitle.ey );1272gradient.addColorStop( 0, '#fff' );1273gradient.addColorStop( 1, '#999' );1274$.ctxmg.fillStyle = gradient;1275$.ctxmg.fill();12761277$.ctxmg.beginPath();1278var creditKeys = $.text( {1279ctx: $.ctxmg,1280x: $.cw / 2 - 10,1281y: creditsTitle.ey + 49,1282text: 'CREATED FOR JS13KGAMES BY\nINSPIRATION AND SUPPORT\n\nAUDIO PROCESSING\nGAME INSPIRATION AND IDEAS\n\nHTML5 CANVAS REFERENCE\n\nGAME MATH REFERENCE',1283hspacing: 1,1284vspacing: 17,1285halign: 'right',1286valign: 'top',1287scale: 2,1288snap: 1,1289render: 11290} );1291$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';1292$.ctxmg.fill();12931294$.ctxmg.beginPath();1295var creditValues = $.text( {1296ctx: $.ctxmg,1297x: $.cw / 2 + 10,1298y: creditsTitle.ey + 49,1299text: '@JACKRUGILE\n@REZONER, @LOKTAR00, @END3R,\n@AUSTINHALLOCK, @CHANDLERPRALL\nJSFXR BY @MARKUSNEUBRAND\nASTEROIDS, CELL WARFARE,\nSPACE PIPS, AND MANY MORE\nNIHILOGIC HTML5\nCANVAS CHEAT SHEET\nBILLY LAMBERTA FOUNDATION\nHTML5 ANIMATION WITH JAVASCRIPT',1300hspacing: 1,1301vspacing: 17,1302halign: 'left',1303valign: 'top',1304scale: 2,1305snap: 1,1306render: 11307} );1308$.ctxmg.fillStyle = '#fff';1309$.ctxmg.fill();13101311var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }1312i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }1313};13141315$.states['play'] = function() {1316$.updateDelta();1317$.updateScreen();1318$.updateLevel();1319$.updatePowerupTimers();1320$.spawnEnemies();1321$.enemyOffsetMod += ( $.slow ) ? $.dt / 3 : $.dt;13221323// update entities1324var i = $.enemies.length; while( i-- ){ $.enemies[ i ].update( i ) }1325i = $.explosions.length; while( i-- ){ $.explosions[ i ].update( i ) }1326i = $.powerups.length; while( i-- ){ $.powerups[ i ].update( i ) }1327i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].update( i ) }1328i = $.textPops.length; while( i-- ){ $.textPops[ i ].update( i ) }1329i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].update( i ) }1330i = $.bullets.length; while( i-- ){ $.bullets[ i ].update( i ) }1331$.hero.update();13321333// render entities1334$.clearScreen();1335$.ctxmg.save();1336$.ctxmg.translate( $.screen.x - $.rumble.x, $.screen.y - $.rumble.y );1337i = $.enemies.length; while( i-- ){ $.enemies[ i ].render( i ) }1338i = $.explosions.length; while( i-- ){ $.explosions[ i ].render( i ) }1339i = $.powerups.length; while( i-- ){ $.powerups[ i ].render( i ) }1340i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].render( i ) }1341i = $.textPops.length; while( i-- ){ $.textPops[ i ].render( i ) }1342i = $.bullets.length; while( i-- ){ $.bullets[ i ].render( i ) }1343$.hero.render();1344$.ctxmg.restore();1345i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].render( i ) }1346$.renderInterface();1347$.renderMinimap();13481349// handle gameover1350if( $.hero.life <= 0 ) {1351var alpha = ( ( $.gameoverTick / $.gameoverTickMax ) * 0.8 );1352alpha = Math.min( 1, Math.max( 0, alpha ) );1353$.ctxmg.fillStyle = 'hsla(0, 100%, 0%, ' + alpha + ')';1354$.ctxmg.fillRect( 0, 0, $.cw, $.ch );1355if( $.gameoverTick < $.gameoverTickMax ){1356$.gameoverTick += $.dt;1357} else {1358$.setState( 'gameover' );1359}13601361if( !$.gameoverExplosion ) {1362$.audio.play( 'death' );1363$.rumble.level = 25;1364$.explosions.push( new $.Explosion( {1365x: $.hero.x + $.util.rand( -10, 10 ),1366y: $.hero.y + $.util.rand( -10, 10 ),1367radius: 50,1368hue: 0,1369saturation: 01370} ) );1371$.particleEmitters.push( new $.ParticleEmitter( {1372x: $.hero.x,1373y: $.hero.y,1374count: 45,1375spawnRange: 10,1376friction: 0.95,1377minSpeed: 2,1378maxSpeed: 20,1379minDirection: 0,1380maxDirection: $.twopi,1381hue: 0,1382saturation: 01383} ) );1384for( var i = 0; i < $.powerupTimers.length; i++ ){1385$.powerupTimers[ i ] = 0;1386}1387$.gameoverExplosion = 1;1388}1389}13901391// update tick1392$.tick += $.dt;13931394// listen for pause1395if( $.keys.pressed.p ){1396$.setState( 'pause' );1397}13981399// always listen for autofire toggle1400if( $.keys.pressed.f ){1401$.autofire = ~~!$.autofire;1402$.storage['autofire'] = $.autofire;1403$.updateStorage();1404}1405};14061407$.states['pause'] = function() {1408$.clearScreen();1409$.ctxmg.putImageData( $.screenshot, 0, 0 );14101411$.ctxmg.fillStyle = 'hsla(0, 0%, 0%, 0.4)';1412$.ctxmg.fillRect( 0, 0, $.cw, $.ch );14131414$.ctxmg.beginPath();1415var pauseText = $.text( {1416ctx: $.ctxmg,1417x: $.cw / 2,1418y: $.ch / 2 - 50,1419text: 'PAUSED',1420hspacing: 3,1421vspacing: 1,1422halign: 'center',1423valign: 'bottom',1424scale: 10,1425snap: 1,1426render: 11427} );1428var gradient = $.ctxmg.createLinearGradient( pauseText.sx, pauseText.sy, pauseText.sx, pauseText.ey );1429gradient.addColorStop( 0, '#fff' );1430gradient.addColorStop( 1, '#999' );1431$.ctxmg.fillStyle = gradient;1432$.ctxmg.fill();14331434var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }1435i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }14361437if( $.keys.pressed.p ){1438$.setState( 'play' );1439}1440};14411442$.states['gameover'] = function() {1443$.clearScreen();1444$.ctxmg.putImageData( $.screenshot, 0, 0 );14451446var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }1447i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }14481449$.ctxmg.beginPath();1450var gameoverTitle = $.text( {1451ctx: $.ctxmg,1452x: $.cw / 2,1453y: 150,1454text: 'GAME OVER',1455hspacing: 3,1456vspacing: 1,1457halign: 'center',1458valign: 'bottom',1459scale: 10,1460snap: 1,1461render: 11462} );1463var gradient = $.ctxmg.createLinearGradient( gameoverTitle.sx, gameoverTitle.sy, gameoverTitle.sx, gameoverTitle.ey );1464gradient.addColorStop( 0, '#f22' );1465gradient.addColorStop( 1, '#b00' );1466$.ctxmg.fillStyle = gradient;1467$.ctxmg.fill();14681469$.ctxmg.beginPath();1470var gameoverStatsKeys = $.text( {1471ctx: $.ctxmg,1472x: $.cw / 2 - 10,1473y: gameoverTitle.ey + 51,1474text: 'SCORE\nLEVEL\nKILLS\nBULLETS\nPOWERUPS\nTIME',1475hspacing: 1,1476vspacing: 17,1477halign: 'right',1478valign: 'top',1479scale: 2,1480snap: 1,1481render: 11482} );1483$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';1484$.ctxmg.fill();14851486$.ctxmg.beginPath();1487var gameoverStatsValues = $.text( {1488ctx: $.ctxmg,1489x: $.cw / 2 + 10,1490y: gameoverTitle.ey + 51,1491text:1492$.util.commas( $.score ) + '\n' +1493( $.level.current + 1 ) + '\n' +1494$.util.commas( $.kills ) + '\n' +1495$.util.commas( $.bulletsFired ) + '\n' +1496$.util.commas( $.powerupsCollected ) + '\n' +1497$.util.convertTime( ( $.elapsed * ( 1000 / 60 ) ) / 1000 )1498,1499hspacing: 1,1500vspacing: 17,1501halign: 'left',1502valign: 'top',1503scale: 2,1504snap: 1,1505render: 11506} );1507$.ctxmg.fillStyle = '#fff';1508$.ctxmg.fill();1509};1510}15111512/*==============================================================================1513Loop1514==============================================================================*/1515$.loop = function() {1516requestAnimFrame( $.loop );15171518// setup the pressed state for all keys1519for( var k in $.keys.state ) {1520if( $.keys.state[ k ] && !$.okeys[ k ] ) {1521$.keys.pressed[ k ] = 1;1522} else {1523$.keys.pressed[ k ] = 0;1524}1525}15261527// run the current state1528$.states[ $.state ]();15291530// always listen for mute toggle1531if( $.keys.pressed.m ){1532$.mute = ~~!$.mute;1533var i = $.audio.references.length;1534while( i-- ) {1535$.audio.references[ i ].volume = ~~!$.mute;1536}1537$.storage['mute'] = $.mute;1538$.updateStorage();1539}15401541// move current keys into old keys1542$.okeys = {};1543for( var k in $.keys.state ) {1544$.okeys[ k ] = $.keys.state[ k ];1545}1546};15471548/*==============================================================================1549Start Game on Load1550==============================================================================*/1551window.addEventListener( 'load', function() {1552document.documentElement.className += ' loaded';1553$.init();1554});15551556