Lucas Kent e39465ad2f Changes to be committed:
new file:   Files/flashplayer_32_sa.exe
	new file:   favicon.ico
	new file:   globe.gif
	new file:   imgs/download.png
	new file:   imgs/zuck.jpg
	new file:   index.html
	new file:   other.ico
	new file:   script.js
	new file:   site.webmanifest
	new file:   sitemap.html
	new file:   styles/backround.css
	new file:   styles/border.css
	new file:   styles/fonts/Titillium_Web/OFL.txt
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Black.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Bold.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Italic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Light.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-Regular.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf
	new file:   styles/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf
	new file:   styles/fonts/webfontkit-20221027-163353/generator_config.txt
	new file:   styles/fonts/webfontkit-20221027-163353/specimen_files/grid_12-825-55-15.css
	new file:   styles/fonts/webfontkit-20221027-163353/specimen_files/specimen_stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-163353/stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-demo.html
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff
	new file:   styles/fonts/webfontkit-20221027-163353/titilliumweb-extralight-webfont.woff2
	new file:   styles/fonts/webfontkit-20221027-165950/generator_config.txt
	new file:   styles/fonts/webfontkit-20221027-165950/specimen_files/grid_12-825-55-15.css
	new file:   styles/fonts/webfontkit-20221027-165950/specimen_files/specimen_stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-165950/stylesheet.css
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-demo.html
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff
	new file:   styles/fonts/webfontkit-20221027-165950/titilliumweb-bold-webfont.woff2
	new file:   styles/style.css
	new file:   tools/2048/.gitignore
	new file:   tools/2048/.jshintrc
	new file:   tools/2048/CONTRIBUTING.md
	new file:   tools/2048/LICENSE.txt
	new file:   tools/2048/README.md
	new file:   tools/2048/Rakefile
	new file:   tools/2048/favicon.ico
	new file:   tools/2048/index.html
	new file:   tools/2048/js/animframe_polyfill.js
	new file:   tools/2048/js/application.js
	new file:   tools/2048/js/bind_polyfill.js
	new file:   tools/2048/js/classlist_polyfill.js
	new file:   tools/2048/js/game_manager.js
	new file:   tools/2048/js/grid.js
	new file:   tools/2048/js/html_actuator.js
	new file:   tools/2048/js/keyboard_input_manager.js
	new file:   tools/2048/js/local_storage_manager.js
	new file:   tools/2048/js/tile.js
    new file:   tools/2048/meta/apple-touch-icon.png
	new file:   tools/webretro/cores/neocd_libretro.js
	new file:   tools/webretro/cores/neocd_libretro.wasm
	new file:   tools/webretro/cores/nestopia_libretro.js
	new file:   tools/webretro/cores/nestopia_libretro.wasm
	new file:   tools/webretro/cores/o2em_libretro.js
	new file:   tools/webretro/cores/o2em_libretro.wasm
	new file:   tools/webretro/cores/opera_libretro.js
	new file:   tools/webretro/cores/opera_libretro.wasm
2022-11-02 08:40:01 -04:00

1555 lines
42 KiB
JavaScript

/*==============================================================================
Init
==============================================================================*/
$.init = function() {
$.setupStorage();
$.wrap = document.getElementById( 'wrap' );
$.wrapInner = document.getElementById( 'wrap-inner' );
$.cbg1 = document.getElementById( 'cbg1' );
$.cbg2 = document.getElementById( 'cbg2' );
$.cbg3 = document.getElementById( 'cbg3' );
$.cbg4 = document.getElementById( 'cbg4' );
$.cmg = document.getElementById( 'cmg' );
$.cfg = document.getElementById( 'cfg' );
$.ctxbg1 = $.cbg1.getContext( '2d' );
$.ctxbg2 = $.cbg2.getContext( '2d' );
$.ctxbg3 = $.cbg3.getContext( '2d' );
$.ctxbg4 = $.cbg4.getContext( '2d' );
$.ctxmg = $.cmg.getContext( '2d' );
$.ctxfg = $.cfg.getContext( '2d' );
$.cw = $.cmg.width = $.cfg.width = 800;
$.ch = $.cmg.height = $.cfg.height = 600;
$.wrap.style.width = $.wrapInner.style.width = $.cw + 'px';
$.wrap.style.height = $.wrapInner.style.height = $.ch + 'px';
$.wrap.style.marginLeft = ( -$.cw / 2 ) - 10 + 'px';
$.wrap.style.marginTop = ( -$.ch / 2 ) - 10 + 'px';
$.ww = Math.floor( $.cw * 2 );
$.wh = Math.floor( $.ch * 2 );
$.cbg1.width = Math.floor( $.cw * 1.1 );
$.cbg1.height = Math.floor( $.ch * 1.1 );
$.cbg2.width = Math.floor( $.cw * 1.15 );
$.cbg2.height = Math.floor( $.ch * 1.15 );
$.cbg3.width = Math.floor( $.cw * 1.2 );
$.cbg3.height = Math.floor( $.ch * 1.2 );
$.cbg4.width = Math.floor( $.cw * 1.25 );
$.cbg4.height = Math.floor( $.ch * 1.25 );
$.screen = {
x: ( $.ww - $.cw ) / -2,
y: ( $.wh - $.ch ) / -2
};
$.mute = $.storage['mute'];
$.autofire = $.storage['autofire'];
$.slowEnemyDivider = 3;
$.keys = {
state: {
up: 0,
down: 0,
left: 0,
right: 0,
f: 0,
m: 0,
p: 0
},
pressed: {
up: 0,
down: 0,
left: 0,
right: 0,
f: 0,
m: 0,
p: 0
}
};
$.okeys = {};
$.mouse = {
x: $.ww / 2,
y: $.wh / 2,
sx: 0,
sy: 0,
ax: window.innerWidth / 2,
ay: 0,
down: 0
};
$.buttons = [];
$.minimap = {
x: 20,
y: $.ch - Math.floor( $.ch * 0.1 ) - 20,
width: Math.floor( $.cw * 0.1 ),
height: Math.floor( $.ch * 0.1 ),
scale: Math.floor( $.cw * 0.1 ) / $.ww,
color: 'hsla(0, 0%, 0%, 0.85)',
strokeColor: '#3a3a3a'
},
$.cOffset = {
left: 0,
top: 0
};
$.levelCount = $.definitions.levels.length;
$.states = {};
$.state = '';
$.enemies = [];
$.bullets = [];
$.explosions = [];
$.powerups = [];
$.particleEmitters = [];
$.textPops = [];
$.levelPops = [];
$.powerupTimers = [];
$.resizecb();
$.bindEvents();
$.setupStates();
$.renderBackground1();
$.renderBackground2();
$.renderBackground3();
$.renderBackground4();
$.renderForeground();
$.renderFavicon();
$.setState( 'menu' );
$.loop();
};
/*==============================================================================
Reset
==============================================================================*/
$.reset = function() {
$.indexGlobal = 0;
$.dt = 1;
$.lt = 0;
$.elapsed = 0;
$.tick = 0;
$.gameoverTick = 0;
$.gameoverTickMax = 200;
$.gameoverExplosion = 0;
$.instructionTick = 0;
$.instructionTickMax = 400;
$.levelDiffOffset = 0;
$.enemyOffsetMod = 0;
$.slow = 0;
$.screen = {
x: ( $.ww - $.cw ) / -2,
y: ( $.wh - $.ch ) / -2
};
$.rumble = {
x: 0,
y: 0,
level: 0,
decay: 0.4
};
$.mouse.down = 0;
$.level = {
current: 0,
kills: 0,
killsToLevel: $.definitions.levels[ 0 ].killsToLevel,
distribution: $.definitions.levels[ 0 ].distribution,
distributionCount: $.definitions.levels[ 0 ].distribution.length
};
$.enemies.length = 0;
$.bullets.length = 0;
$.explosions.length = 0;
$.powerups.length = 0;
$.particleEmitters.length = 0;
$.textPops.length = 0;
$.levelPops.length = 0;
$.powerupTimers.length = 0;
for( var i = 0; i < $.definitions.powerups.length; i++ ) {
$.powerupTimers.push( 0 );
}
$.kills = 0;
$.bulletsFired = 0;
$.powerupsCollected = 0;
$.score = 0;
$.hero = new $.Hero();
$.levelPops.push( new $.LevelPop( {
level: 1
} ) );
};
/*==============================================================================
Create Favicon
==============================================================================*/
$.renderFavicon = function() {
var favicon = document.getElementById( 'favicon' ),
favc = document.createElement( 'canvas' ),
favctx = favc.getContext( '2d' ),
faviconGrid = [
[ 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
[ 1, , , , , , , , , , , , , , , 1 ],
[ 1, , , , , , , , , , , , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],
[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , 1, 1, , , 1, 1, , , , , 1 ],
[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],
[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],
[ 1, , , , , , , , , , , , , , , 1 ],
[ 1, , , , , , , , , , , , , , , 1 ],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1 ]
];
favc.width = favc.height = 16;
favctx.beginPath();
for( var y = 0; y < 16; y++ ) {
for( var x = 0; x < 16; x++ ) {
if( faviconGrid[ y ][ x ] === 1 ) {
favctx.rect( x, y, 1, 1 );
}
}
}
favctx.fill();
favicon.href = favc.toDataURL();
};
/*==============================================================================
Render Backgrounds
==============================================================================*/
$.renderBackground1 = function() {
var gradient = $.ctxbg1.createRadialGradient( $.cbg1.width / 2, $.cbg1.height / 2, 0, $.cbg1.width / 2, $.cbg1.height / 2, $.cbg1.height );
gradient.addColorStop( 0, 'hsla(0, 0%, 100%, 0.1)' );
gradient.addColorStop( 0.65, 'hsla(0, 0%, 100%, 0)' );
$.ctxbg1.fillStyle = gradient;
$.ctxbg1.fillRect( 0, 0, $.cbg1.width, $.cbg1.height );
var i = 2000;
while( i-- ) {
$.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 ) + ')' );
}
var i = 800;
while( i-- ) {
$.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 ) + ')' );
}
}
$.renderBackground2 = function() {
var i = 80;
while( i-- ) {
$.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 ) + ')' );
}
}
$.renderBackground3 = function() {
var i = 40;
while( i-- ) {
$.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 ) + ')' );
}
}
$.renderBackground4 = function() {
var size = 50;
$.ctxbg4.fillStyle = 'hsla(0, 0%, 50%, 0.05)';
var i = Math.round( $.cbg4.height / size );
while( i-- ) {
$.ctxbg4.fillRect( 0, i * size + 25, $.cbg4.width, 1 );
}
i = Math.round( $.cbg4.width / size );
while( i-- ) {
$.ctxbg4.fillRect( i * size, 0, 1, $.cbg4.height );
}
}
/*==============================================================================
Render Foreground
==============================================================================*/
$.renderForeground = function() {
var gradient = $.ctxfg.createRadialGradient( $.cw / 2, $.ch / 2, $.ch / 3, $.cw / 2, $.ch / 2, $.ch );
gradient.addColorStop( 0, 'hsla(0, 0%, 0%, 0)' );
gradient.addColorStop( 1, 'hsla(0, 0%, 0%, 0.5)' );
$.ctxfg.fillStyle = gradient;
$.ctxfg.fillRect( 0, 0, $.cw, $.ch );
$.ctxfg.fillStyle = 'hsla(0, 0%, 50%, 0.1)';
var i = Math.round( $.ch / 2 );
while( i-- ) {
$.ctxfg.fillRect( 0, i * 2, $.cw, 1 );
}
var gradient2 = $.ctxfg.createLinearGradient( $.cw, 0, 0, $.ch );
gradient2.addColorStop( 0, 'hsla(0, 0%, 100%, 0.04)' );
gradient2.addColorStop( 0.75, 'hsla(0, 0%, 100%, 0)' );
$.ctxfg.beginPath();
$.ctxfg.moveTo( 0, 0 );
$.ctxfg.lineTo( $.cw, 0 );
$.ctxfg.lineTo( 0, $.ch );
$.ctxfg.closePath();
$.ctxfg.fillStyle = gradient2;
$.ctxfg.fill();
}
/*==============================================================================
User Interface / UI / GUI / Minimap
==============================================================================*/
$.renderInterface = function() {
/*==============================================================================
Powerup Timers
==============================================================================*/
for( var i = 0; i < $.definitions.powerups.length; i++ ) {
var powerup = $.definitions.powerups[ i ],
powerupOn = ( $.powerupTimers[ i ] > 0 );
$.ctxmg.beginPath();
var powerupText = $.text( {
ctx: $.ctxmg,
x: $.minimap.x + $.minimap.width + 90,
y: $.minimap.y + 4 + ( i * 12 ),
text: powerup.title,
hspacing: 1,
vspacing: 1,
halign: 'right',
valign: 'top',
scale: 1,
snap: 1,
render: 1
} );
if( powerupOn ) {
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + ( 0.25 + ( ( $.powerupTimers[ i ] / 300 ) * 0.75 ) ) + ')';
} else {
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
}
$.ctxmg.fill();
if( powerupOn ) {
var powerupBar = {
x: powerupText.ex + 5,
y: powerupText.sy,
width: 110,
height: 5
};
$.ctxmg.fillStyle = 'hsl(' + powerup.hue + ', ' + powerup.saturation + '%, ' + powerup.lightness + '%)';
$.ctxmg.fillRect( powerupBar.x, powerupBar.y, ( $.powerupTimers[ i ] / 300 ) * powerupBar.width, powerupBar.height );
}
}
/*==============================================================================
Instructions
==============================================================================*/
if( $.instructionTick < $.instructionTickMax ){
$.instructionTick += $.dt;
$.ctxmg.beginPath();
$.text( {
ctx: $.ctxmg,
x: $.cw / 2 - 10,
y: $.ch - 20,
text: 'MOVE\nAIM/FIRE\nAUTOFIRE\nPAUSE\nMUTE',
hspacing: 1,
vspacing: 17,
halign: 'right',
valign: 'bottom',
scale: 2,
snap: 1,
render: 1
} );
if( $.instructionTick < $.instructionTickMax * 0.25 ) {
var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 0.5;
} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {
var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 0.5;
} else {
var alpha = 0.5;
}
alpha = Math.min( 1, Math.max( 0, alpha ) );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';
$.ctxmg.fill();
$.ctxmg.beginPath();
$.text( {
ctx: $.ctxmg,
x: $.cw / 2 + 10,
y: $.ch - 20,
text: 'WASD/ARROWS\nMOUSE\nF\nP\nM',
hspacing: 1,
vspacing: 17,
halign: 'left',
valign: 'bottom',
scale: 2,
snap: 1,
render: 1
} );
if( $.instructionTick < $.instructionTickMax * 0.25 ) {
var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 1;
} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {
var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 1;
} else {
var alpha = 1;
}
alpha = Math.min( 1, Math.max( 0, alpha ) );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';
$.ctxmg.fill();
}
/*==============================================================================
Slow Enemies Screen Cover
==============================================================================*/
if( $.powerupTimers[ 1 ] > 0 ) {
$.ctxmg.fillStyle = 'hsla(200, 100%, 20%, 0.05)';
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
}
/*==============================================================================
Health
==============================================================================*/
$.ctxmg.beginPath();
var healthText = $.text( {
ctx: $.ctxmg,
x: 20,
y: 20,
text: 'HEALTH',
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
var healthBar = {
x: healthText.ex + 10,
y: healthText.sy,
width: 110,
height: 10
};
$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';
$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height / 2 );
$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 40%, 1)';
$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height );
$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 75%, 1)';
$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height / 2 );
if( $.hero.takingDamage && $.hero.life > 0.01 ) {
$.particleEmitters.push( new $.ParticleEmitter( {
x: -$.screen.x + healthBar.x + $.hero.life * healthBar.width,
y: -$.screen.y + healthBar.y + healthBar.height / 2,
count: 1,
spawnRange: 2,
friction: 0.85,
minSpeed: 2,
maxSpeed: 20,
minDirection: $.pi / 2 - 0.2,
maxDirection: $.pi / 2 + 0.2,
hue: $.hero.life * 120,
saturation: 100
} ) );
}
/*==============================================================================
Progress
==============================================================================*/
$.ctxmg.beginPath();
var progressText = $.text( {
ctx: $.ctxmg,
x: healthBar.x + healthBar.width + 40,
y: 20,
text: 'PROGRESS',
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
var progressBar = {
x: progressText.ex + 10,
y: progressText.sy,
width: healthBar.width,
height: healthBar.height
};
$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';
$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height / 2 );
$.ctxmg.fillStyle = 'hsla(0, 0%, 50%, 1)';
$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height / 2 );
if( $.level.kills == $.level.killsToLevel ) {
$.particleEmitters.push( new $.ParticleEmitter( {
x: -$.screen.x + progressBar.x + progressBar.width,
y: -$.screen.y + progressBar.y + progressBar.height / 2,
count: 30,
spawnRange: 5,
friction: 0.95,
minSpeed: 2,
maxSpeed: 25,
minDirection: 0,
minDirection: $.pi / 2 - $.pi / 4,
maxDirection: $.pi / 2 + $.pi / 4,
hue: 0,
saturation: 0
} ) );
}
/*==============================================================================
Score
==============================================================================*/
$.ctxmg.beginPath();
var scoreLabel = $.text( {
ctx: $.ctxmg,
x: progressBar.x + progressBar.width + 40,
y: 20,
text: 'SCORE',
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var scoreText = $.text( {
ctx: $.ctxmg,
x: scoreLabel.ex + 10,
y: 20,
text: $.util.pad( $.score, 6 ),
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var bestLabel = $.text( {
ctx: $.ctxmg,
x: scoreText.ex + 40,
y: 20,
text: 'BEST',
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var bestText = $.text( {
ctx: $.ctxmg,
x: bestLabel.ex + 10,
y: 20,
text: $.util.pad( Math.max( $.storage['score'], $.score ), 6 ),
hspacing: 1,
vspacing: 1,
halign: 'top',
valign: 'left',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
$.ctxmg.fill();
};
$.renderMinimap = function() {
$.ctxmg.fillStyle = $.minimap.color;
$.ctxmg.fillRect( $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.1)';
$.ctxmg.fillRect(
Math.floor( $.minimap.x + -$.screen.x * $.minimap.scale ),
Math.floor( $.minimap.y + -$.screen.y * $.minimap.scale ),
Math.floor( $.cw * $.minimap.scale ),
Math.floor( $.ch * $.minimap.scale )
);
//$.ctxmg.beginPath();
for( var i = 0; i < $.enemies.length; i++ ){
var enemy = $.enemies[ i ],
x = $.minimap.x + Math.floor( enemy.x * $.minimap.scale ),
y = $.minimap.y + Math.floor( enemy.y * $.minimap.scale );
if( $.util.pointInRect( x + 1, y + 1, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {
//$.ctxmg.rect( x, y, 2, 2 );
$.ctxmg.fillStyle = 'hsl(' + enemy.hue + ', ' + enemy.saturation + '%, 50%)';
$.ctxmg.fillRect( x, y, 2, 2 );
}
}
//$.ctxmg.fillStyle = '#f00';
//$.ctxmg.fill();
$.ctxmg.beginPath();
for( var i = 0; i < $.bullets.length; i++ ){
var bullet = $.bullets[ i ],
x = $.minimap.x + Math.floor( bullet.x * $.minimap.scale ),
y = $.minimap.y + Math.floor( bullet.y * $.minimap.scale );
if( $.util.pointInRect( x, y, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {
$.ctxmg.rect( x, y, 1, 1 );
}
}
$.ctxmg.fillStyle = '#fff';
$.ctxmg.fill();
$.ctxmg.fillStyle = $.hero.fillStyle;
$.ctxmg.fillRect( $.minimap.x + Math.floor( $.hero.x * $.minimap.scale ), $.minimap.y + Math.floor( $.hero.y * $.minimap.scale ), 2, 2 );
$.ctxmg.strokeStyle = $.minimap.strokeColor;
$.ctxmg.strokeRect( $.minimap.x - 0.5, $.minimap.y - 0.5, $.minimap.width + 1, $.minimap.height + 1 );
};
/*==============================================================================
Enemy Spawning
==============================================================================*/
$.getSpawnCoordinates = function( radius ) {
var quadrant = Math.floor( $.util.rand( 0, 4 ) ),
x,
y,
start;
if( quadrant === 0){
x = $.util.rand( 0, $.ww );
y = -radius;
start = 'top';
} else if( quadrant === 1 ){
x = $.ww + radius;
y = $.util.rand( 0, $.wh );
start = 'right';
} else if( quadrant === 2 ) {
x = $.util.rand( 0, $.ww );
y = $.wh + radius;
start = 'bottom';
} else {
x = -radius;
y = $.util.rand( 0, $.wh );
start = 'left';
}
return { x: x, y: y, start: start };
};
$.spawnEnemy = function( type ) {
var params = $.definitions.enemies[ type ],
coordinates = $.getSpawnCoordinates( params.radius );
params.x = coordinates.x;
params.y = coordinates.y;
params.start = coordinates.start;
params.type = type;
return new $.Enemy( params );
};
$.spawnEnemies = function() {
var floorTick = Math.floor( $.tick );
for( var i = 0; i < $.level.distributionCount; i++ ) {
var timeCheck = $.level.distribution[ i ];
if( $.levelDiffOffset > 0 ){
timeCheck = Math.max( 1, timeCheck - ( $.levelDiffOffset * 2) );
}
if( floorTick % timeCheck === 0 ) {
$.enemies.push( $.spawnEnemy( i ) );
}
}
};
/*==============================================================================
Events
==============================================================================*/
$.mousemovecb = function( e ) {
e.preventDefault();
$.mouse.ax = e.pageX;
$.mouse.ay = e.pageY;
$.mousescreen();
};
$.mousescreen = function() {
$.mouse.sx = $.mouse.ax - $.cOffset.left;
$.mouse.sy = $.mouse.ay - $.cOffset.top;
$.mouse.x = $.mouse.sx - $.screen.x;
$.mouse.y = $.mouse.sy - $.screen.y;
};
$.mousedowncb = function( e ) {
e.preventDefault();
$.mouse.down = 1;
};
$.mouseupcb = function( e ) {
e.preventDefault();
$.mouse.down = 0;
};
$.keydowncb = function( e ) {
var e = ( e.keyCode ? e.keyCode : e.which );
if( e === 38 || e === 87 ){ $.keys.state.up = 1; }
if( e === 39 || e === 68 ){ $.keys.state.right = 1; }
if( e === 40 || e === 83 ){ $.keys.state.down = 1; }
if( e === 37 || e === 65 ){ $.keys.state.left = 1; }
if( e === 70 ){ $.keys.state.f = 1; }
if( e === 77 ){ $.keys.state.m = 1; }
if( e === 80 ){ $.keys.state.p = 1; }
}
$.keyupcb = function( e ) {
var e = ( e.keyCode ? e.keyCode : e.which );
if( e === 38 || e === 87 ){ $.keys.state.up = 0; }
if( e === 39 || e === 68 ){ $.keys.state.right = 0; }
if( e === 40 || e === 83 ){ $.keys.state.down = 0; }
if( e === 37 || e === 65 ){ $.keys.state.left = 0; }
if( e === 70 ){ $.keys.state.f = 0; }
if( e === 77 ){ $.keys.state.m = 0; }
if( e === 80 ){ $.keys.state.p = 0; }
}
$.resizecb = function( e ) {
var rect = $.cmg.getBoundingClientRect();
$.cOffset = {
left: rect.left,
top: rect.top
}
}
$.blurcb = function() {
if( $.state == 'play' ){
$.setState( 'pause' );
}
}
$.bindEvents = function() {
window.addEventListener( 'mousemove', $.mousemovecb );
window.addEventListener( 'mousedown', $.mousedowncb );
window.addEventListener( 'mouseup', $.mouseupcb );
window.addEventListener( 'keydown', $.keydowncb );
window.addEventListener( 'keyup', $.keyupcb );
window.addEventListener( 'resize', $.resizecb );
window.addEventListener( 'blur', $.blurcb );
};
/*==============================================================================
Miscellaneous
==============================================================================*/
$.clearScreen = function() {
$.ctxmg.clearRect( 0, 0, $.cw, $.ch );
};
$.updateDelta = function() {
var now = Date.now();
$.dt = ( now - $.lt ) / ( 1000 / 60 );
$.dt = ( $.dt < 0 ) ? 0.001 : $.dt;
$.dt = ( $.dt > 10 ) ? 10 : $.dt;
$.lt = now;
$.elapsed += $.dt;
};
$.updateScreen = function() {
var xSnap,
xModify,
ySnap,
yModify;
if( $.hero.x < $.cw / 2 ) {
xModify = $.hero.x / $.cw;
} else if( $.hero.x > $.ww - $.cw / 2 ) {
xModify = 1 - ( $.ww - $.hero.x ) / $.cw;
} else {
xModify = 0.5;
}
if( $.hero.y < $.ch / 2 ) {
yModify = $.hero.y / $.ch;
} else if( $.hero.y > $.wh - $.ch / 2 ) {
yModify = 1 - ( $.wh - $.hero.y ) / $.ch;
} else {
yModify = 0.5;
}
xSnap = ( ( $.cw * xModify - $.hero.x ) - $.screen.x ) / 30;
ySnap = ( ( $.ch * yModify - $.hero.y ) - $.screen.y ) / 30;
// ease to new coordinates
$.screen.x += xSnap * $.dt;
$.screen.y += ySnap * $.dt;
// update rumble levels, keep X and Y changes consistent, apply rumble
if( $.rumble.level > 0 ) {
$.rumble.level -= $.rumble.decay;
$.rumble.level = ( $.rumble.level < 0 ) ? 0 : $.rumble.level;
$.rumble.x = $.util.rand( -$.rumble.level, $.rumble.level );
$.rumble.y = $.util.rand( -$.rumble.level, $.rumble.level );
} else {
$.rumble.x = 0;
$.rumble.y = 0;
}
//$.screen.x -= $.rumble.x;
//$.screen.y -= $.rumble.y;
// animate background canvas
$.cbg1.style.marginLeft =
-( ( $.cbg1.width - $.cw ) / 2 ) // half the difference from bg to viewport
- ( ( $.cbg1.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
- $.rumble.x + 'px';
$.cbg1.style.marginTop =
-( ( $.cbg1.height - $.ch ) / 2 )
- ( ( $.cbg1.height - $.ch ) / 2 )
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
- $.rumble.y + 'px';
$.cbg2.style.marginLeft =
-( ( $.cbg2.width - $.cw ) / 2 ) // half the difference from bg to viewport
- ( ( $.cbg2.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
- $.rumble.x + 'px';
$.cbg2.style.marginTop =
-( ( $.cbg2.height - $.ch ) / 2 )
- ( ( $.cbg2.height - $.ch ) / 2 )
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
- $.rumble.y + 'px';
$.cbg3.style.marginLeft =
-( ( $.cbg3.width - $.cw ) / 2 ) // half the difference from bg to viewport
- ( ( $.cbg3.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
- $.rumble.x + 'px';
$.cbg3.style.marginTop =
-( ( $.cbg3.height - $.ch ) / 2 )
- ( ( $.cbg3.height - $.ch ) / 2 )
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
- $.rumble.y + 'px';
$.cbg4.style.marginLeft =
-( ( $.cbg4.width - $.cw ) / 2 ) // half the difference from bg to viewport
- ( ( $.cbg4.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
- $.rumble.x + 'px';
$.cbg4.style.marginTop =
-( ( $.cbg4.height - $.ch ) / 2 )
- ( ( $.cbg4.height - $.ch ) / 2 )
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
- $.rumble.y + 'px';
$.mousescreen();
};
$.updateLevel = function() {
if( $.level.kills >= $.level.killsToLevel ) {
if( $.level.current + 1 < $.levelCount ){
$.level.current++;
$.level.kills = 0;
$.level.killsToLevel = $.definitions.levels[ $.level.current ].killsToLevel;
$.level.distribution = $.definitions.levels[ $.level.current ].distribution;
$.level.distributionCount = $.level.distribution.length;
} else {
$.level.current++;
$.level.kills = 0;
// no more level definitions, so take the last level and increase the spawn rate slightly
//for( var i = 0; i < $.level.distributionCount; i++ ) {
//$.level.distribution[ i ] = Math.max( 1, $.level.distribution[ i ] - 5 );
//}
}
$.levelDiffOffset = $.level.current + 1 - $.levelCount;
$.levelPops.push( new $.LevelPop( {
level: $.level.current + 1
} ) );
}
};
$.updatePowerupTimers = function() {
// HEALTH
if( $.powerupTimers[ 0 ] > 0 ){
if( $.hero.life < 1 ) {
$.hero.life += 0.001;
}
if( $.hero.life > 1 ) {
$.hero.life = 1;
}
$.powerupTimers[ 0 ] -= $.dt;
}
// SLOW ENEMIES
if( $.powerupTimers[ 1 ] > 0 ){
$.slow = 1;
$.powerupTimers[ 1 ] -= $.dt;
} else {
$.slow = 0;
}
// FAST SHOT
if( $.powerupTimers[ 2 ] > 0 ){
$.hero.weapon.fireRate = 2;
$.hero.weapon.bullet.speed = 14;
$.powerupTimers[ 2 ] -= $.dt;
} else {
$.hero.weapon.fireRate = 5;
$.hero.weapon.bullet.speed = 10;
}
// TRIPLE SHOT
if( $.powerupTimers[ 3 ] > 0 ){
$.hero.weapon.count = 3;
$.powerupTimers[ 3 ] -= $.dt;
} else {
$.hero.weapon.count = 1;
}
// PIERCE SHOT
if( $.powerupTimers[ 4 ] > 0 ){
$.hero.weapon.bullet.piercing = 1;
$.powerupTimers[ 4 ] -= $.dt;
} else {
$.hero.weapon.bullet.piercing = 0;
}
};
$.spawnPowerup = function( x, y ) {
if( Math.random() < 0.1 ) {
var min = ( $.hero.life < 0.9 ) ? 0 : 1,
type = Math.floor( $.util.rand( min, $.definitions.powerups.length ) ),
params = $.definitions.powerups[ type ];
params.type = type;
params.x = x;
params.y = y;
$.powerups.push( new $.Powerup( params ) );
}
};
/*==============================================================================
States
==============================================================================*/
$.setState = function( state ) {
// handle clean up between states
$.buttons.length = 0;
if( state == 'menu' ) {
$.mouse.down = 0;
$.mouse.ax = 0;
$.mouse.ay = 0;
$.reset();
var playButton = new $.Button( {
x: $.cw / 2 + 1,
y: $.ch / 2 - 24,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'PLAY',
action: function() {
$.reset();
$.audio.play( 'levelup' );
$.setState( 'play' );
}
} );
$.buttons.push( playButton );
var statsButton = new $.Button( {
x: $.cw / 2 + 1,
y: playButton.ey + 25,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'STATS',
action: function() {
$.setState( 'stats' );
}
} );
$.buttons.push( statsButton );
var creditsButton = new $.Button( {
x: $.cw / 2 + 1,
y: statsButton.ey + 26,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'CREDITS',
action: function() {
$.setState( 'credits' );
}
} ) ;
$.buttons.push( creditsButton );
}
if( state == 'stats' ) {
$.mouse.down = 0;
var clearButton = new $.Button( {
x: $.cw / 2 + 1,
y: 426,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'CLEAR DATA',
action: function() {
$.mouse.down = 0;
if( window.confirm( 'Are you sure you want to clear all locally stored game data? This cannot be undone.') ) {
$.clearStorage();
$.mouse.down = 0;
}
}
} );
$.buttons.push( clearButton );
var menuButton = new $.Button( {
x: $.cw / 2 + 1,
y: clearButton.ey + 25,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'MENU',
action: function() {
$.setState( 'menu' );
}
} );
$.buttons.push( menuButton );
}
if( state == 'credits' ) {
$.mouse.down = 0;
var js13kButton = new $.Button( {
x: $.cw / 2 + 1,
y: 476,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'JS13KGAMES',
action: function() {
location.href = 'http://js13kgames.com';
$.mouse.down = 0;
}
} );
$.buttons.push( js13kButton );
var menuButton = new $.Button( {
x: $.cw / 2 + 1,
y: js13kButton.ey + 25,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'MENU',
action: function() {
$.setState( 'menu' );
}
} );
$.buttons.push( menuButton );
}
if( state == 'pause' ) {
$.mouse.down = 0;
$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );
var resumeButton = new $.Button( {
x: $.cw / 2 + 1,
y: $.ch / 2 + 26,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'RESUME',
action: function() {
$.lt = Date.now() + 1000;
$.setState( 'play' );
}
} );
$.buttons.push( resumeButton );
var menuButton = new $.Button( {
x: $.cw / 2 + 1,
y: resumeButton.ey + 25,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'MENU',
action: function() {
$.mouse.down = 0;
if( window.confirm( 'Are you sure you want to end this game and return to the menu?') ) {
$.mousescreen();
$.setState( 'menu' );
}
}
} );
$.buttons.push( menuButton );
}
if( state == 'gameover' ) {
$.mouse.down = 0;
$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );
var resumeButton = new $.Button( {
x: $.cw / 2 + 1,
y: 426,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'PLAY AGAIN',
action: function() {
$.reset();
$.audio.play( 'levelup' );
$.setState( 'play' );
}
} );
$.buttons.push( resumeButton );
var menuButton = new $.Button( {
x: $.cw / 2 + 1,
y: resumeButton.ey + 25,
lockedWidth: 299,
lockedHeight: 49,
scale: 3,
title: 'MENU',
action: function() {
$.setState( 'menu' );
}
} );
$.buttons.push( menuButton );
$.storage['score'] = Math.max( $.storage['score'], $.score );
$.storage['level'] = Math.max( $.storage['level'], $.level.current );
$.storage['rounds'] += 1;
$.storage['kills'] += $.kills;
$.storage['bullets'] += $.bulletsFired;
$.storage['powerups'] += $.powerupsCollected;
$.storage['time'] += Math.floor( $.elapsed );
$.updateStorage();
}
// set state
$.state = state;
};
$.setupStates = function() {
$.states['menu'] = function() {
$.clearScreen();
$.updateScreen();
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
$.ctxmg.beginPath();
var title = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: $.ch / 2 - 100,
text: 'RADIUS RAID',
hspacing: 2,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 10,
snap: 1,
render: 1
} );
gradient = $.ctxmg.createLinearGradient( title.sx, title.sy, title.sx, title.ey );
gradient.addColorStop( 0, '#fff' );
gradient.addColorStop( 1, '#999' );
$.ctxmg.fillStyle = gradient;
$.ctxmg.fill();
$.ctxmg.beginPath();
var bottomInfo = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: $.ch - 172,
text: 'CREATED BY JACK RUGILE FOR JS13KGAMES 2013',
hspacing: 1,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 1,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = '#666';
$.ctxmg.fill();
};
$.states['stats'] = function() {
$.clearScreen();
$.ctxmg.beginPath();
var statsTitle = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: 150,
text: 'STATS',
hspacing: 3,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 10,
snap: 1,
render: 1
} );
var gradient = $.ctxmg.createLinearGradient( statsTitle.sx, statsTitle.sy, statsTitle.sx, statsTitle.ey );
gradient.addColorStop( 0, '#fff' );
gradient.addColorStop( 1, '#999' );
$.ctxmg.fillStyle = gradient;
$.ctxmg.fill();
$.ctxmg.beginPath();
var statKeys = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 - 10,
y: statsTitle.ey + 39,
text: 'BEST SCORE\nBEST LEVEL\nROUNDS PLAYED\nENEMIES KILLED\nBULLETS FIRED\nPOWERUPS COLLECTED\nTIME ELAPSED',
hspacing: 1,
vspacing: 17,
halign: 'right',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var statsValues = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 + 10,
y: statsTitle.ey + 39,
text:
$.util.commas( $.storage['score'] ) + '\n' +
( $.storage['level'] + 1 ) + '\n' +
$.util.commas( $.storage['rounds'] ) + '\n' +
$.util.commas( $.storage['kills'] ) + '\n' +
$.util.commas( $.storage['bullets'] ) + '\n' +
$.util.commas( $.storage['powerups'] ) + '\n' +
$.util.convertTime( ( $.storage['time'] * ( 1000 / 60 ) ) / 1000 )
,
hspacing: 1,
vspacing: 17,
halign: 'left',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = '#fff';
$.ctxmg.fill();
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
};
$.states['credits'] = function() {
$.clearScreen();
$.ctxmg.beginPath();
var creditsTitle = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: 100,
text: 'CREDITS',
hspacing: 3,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 10,
snap: 1,
render: 1
} );
var gradient = $.ctxmg.createLinearGradient( creditsTitle.sx, creditsTitle.sy, creditsTitle.sx, creditsTitle.ey );
gradient.addColorStop( 0, '#fff' );
gradient.addColorStop( 1, '#999' );
$.ctxmg.fillStyle = gradient;
$.ctxmg.fill();
$.ctxmg.beginPath();
var creditKeys = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 - 10,
y: creditsTitle.ey + 49,
text: 'CREATED FOR JS13KGAMES BY\nINSPIRATION AND SUPPORT\n\nAUDIO PROCESSING\nGAME INSPIRATION AND IDEAS\n\nHTML5 CANVAS REFERENCE\n\nGAME MATH REFERENCE',
hspacing: 1,
vspacing: 17,
halign: 'right',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var creditValues = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 + 10,
y: creditsTitle.ey + 49,
text: '@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',
hspacing: 1,
vspacing: 17,
halign: 'left',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = '#fff';
$.ctxmg.fill();
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
};
$.states['play'] = function() {
$.updateDelta();
$.updateScreen();
$.updateLevel();
$.updatePowerupTimers();
$.spawnEnemies();
$.enemyOffsetMod += ( $.slow ) ? $.dt / 3 : $.dt;
// update entities
var i = $.enemies.length; while( i-- ){ $.enemies[ i ].update( i ) }
i = $.explosions.length; while( i-- ){ $.explosions[ i ].update( i ) }
i = $.powerups.length; while( i-- ){ $.powerups[ i ].update( i ) }
i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].update( i ) }
i = $.textPops.length; while( i-- ){ $.textPops[ i ].update( i ) }
i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].update( i ) }
i = $.bullets.length; while( i-- ){ $.bullets[ i ].update( i ) }
$.hero.update();
// render entities
$.clearScreen();
$.ctxmg.save();
$.ctxmg.translate( $.screen.x - $.rumble.x, $.screen.y - $.rumble.y );
i = $.enemies.length; while( i-- ){ $.enemies[ i ].render( i ) }
i = $.explosions.length; while( i-- ){ $.explosions[ i ].render( i ) }
i = $.powerups.length; while( i-- ){ $.powerups[ i ].render( i ) }
i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].render( i ) }
i = $.textPops.length; while( i-- ){ $.textPops[ i ].render( i ) }
i = $.bullets.length; while( i-- ){ $.bullets[ i ].render( i ) }
$.hero.render();
$.ctxmg.restore();
i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].render( i ) }
$.renderInterface();
$.renderMinimap();
// handle gameover
if( $.hero.life <= 0 ) {
var alpha = ( ( $.gameoverTick / $.gameoverTickMax ) * 0.8 );
alpha = Math.min( 1, Math.max( 0, alpha ) );
$.ctxmg.fillStyle = 'hsla(0, 100%, 0%, ' + alpha + ')';
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
if( $.gameoverTick < $.gameoverTickMax ){
$.gameoverTick += $.dt;
} else {
$.setState( 'gameover' );
}
if( !$.gameoverExplosion ) {
$.audio.play( 'death' );
$.rumble.level = 25;
$.explosions.push( new $.Explosion( {
x: $.hero.x + $.util.rand( -10, 10 ),
y: $.hero.y + $.util.rand( -10, 10 ),
radius: 50,
hue: 0,
saturation: 0
} ) );
$.particleEmitters.push( new $.ParticleEmitter( {
x: $.hero.x,
y: $.hero.y,
count: 45,
spawnRange: 10,
friction: 0.95,
minSpeed: 2,
maxSpeed: 20,
minDirection: 0,
maxDirection: $.twopi,
hue: 0,
saturation: 0
} ) );
for( var i = 0; i < $.powerupTimers.length; i++ ){
$.powerupTimers[ i ] = 0;
}
$.gameoverExplosion = 1;
}
}
// update tick
$.tick += $.dt;
// listen for pause
if( $.keys.pressed.p ){
$.setState( 'pause' );
}
// always listen for autofire toggle
if( $.keys.pressed.f ){
$.autofire = ~~!$.autofire;
$.storage['autofire'] = $.autofire;
$.updateStorage();
}
};
$.states['pause'] = function() {
$.clearScreen();
$.ctxmg.putImageData( $.screenshot, 0, 0 );
$.ctxmg.fillStyle = 'hsla(0, 0%, 0%, 0.4)';
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
$.ctxmg.beginPath();
var pauseText = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: $.ch / 2 - 50,
text: 'PAUSED',
hspacing: 3,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 10,
snap: 1,
render: 1
} );
var gradient = $.ctxmg.createLinearGradient( pauseText.sx, pauseText.sy, pauseText.sx, pauseText.ey );
gradient.addColorStop( 0, '#fff' );
gradient.addColorStop( 1, '#999' );
$.ctxmg.fillStyle = gradient;
$.ctxmg.fill();
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
if( $.keys.pressed.p ){
$.setState( 'play' );
}
};
$.states['gameover'] = function() {
$.clearScreen();
$.ctxmg.putImageData( $.screenshot, 0, 0 );
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
$.ctxmg.beginPath();
var gameoverTitle = $.text( {
ctx: $.ctxmg,
x: $.cw / 2,
y: 150,
text: 'GAME OVER',
hspacing: 3,
vspacing: 1,
halign: 'center',
valign: 'bottom',
scale: 10,
snap: 1,
render: 1
} );
var gradient = $.ctxmg.createLinearGradient( gameoverTitle.sx, gameoverTitle.sy, gameoverTitle.sx, gameoverTitle.ey );
gradient.addColorStop( 0, '#f22' );
gradient.addColorStop( 1, '#b00' );
$.ctxmg.fillStyle = gradient;
$.ctxmg.fill();
$.ctxmg.beginPath();
var gameoverStatsKeys = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 - 10,
y: gameoverTitle.ey + 51,
text: 'SCORE\nLEVEL\nKILLS\nBULLETS\nPOWERUPS\nTIME',
hspacing: 1,
vspacing: 17,
halign: 'right',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
$.ctxmg.fill();
$.ctxmg.beginPath();
var gameoverStatsValues = $.text( {
ctx: $.ctxmg,
x: $.cw / 2 + 10,
y: gameoverTitle.ey + 51,
text:
$.util.commas( $.score ) + '\n' +
( $.level.current + 1 ) + '\n' +
$.util.commas( $.kills ) + '\n' +
$.util.commas( $.bulletsFired ) + '\n' +
$.util.commas( $.powerupsCollected ) + '\n' +
$.util.convertTime( ( $.elapsed * ( 1000 / 60 ) ) / 1000 )
,
hspacing: 1,
vspacing: 17,
halign: 'left',
valign: 'top',
scale: 2,
snap: 1,
render: 1
} );
$.ctxmg.fillStyle = '#fff';
$.ctxmg.fill();
};
}
/*==============================================================================
Loop
==============================================================================*/
$.loop = function() {
requestAnimFrame( $.loop );
// setup the pressed state for all keys
for( var k in $.keys.state ) {
if( $.keys.state[ k ] && !$.okeys[ k ] ) {
$.keys.pressed[ k ] = 1;
} else {
$.keys.pressed[ k ] = 0;
}
}
// run the current state
$.states[ $.state ]();
// always listen for mute toggle
if( $.keys.pressed.m ){
$.mute = ~~!$.mute;
var i = $.audio.references.length;
while( i-- ) {
$.audio.references[ i ].volume = ~~!$.mute;
}
$.storage['mute'] = $.mute;
$.updateStorage();
}
// move current keys into old keys
$.okeys = {};
for( var k in $.keys.state ) {
$.okeys[ k ] = $.keys.state[ k ];
}
};
/*==============================================================================
Start Game on Load
==============================================================================*/
window.addEventListener( 'load', function() {
document.documentElement.className += ' loaded';
$.init();
});