Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
titaniumnetwork-dev
GitHub Repository: titaniumnetwork-dev/Incognito-old
Path: blob/main/static/src/gs/public/radius-raid/js/game.js
1325 views
1
/*==============================================================================
2
Init
3
==============================================================================*/
4
$.init = function() {
5
$.setupStorage();
6
$.wrap = document.getElementById( 'wrap' );
7
$.wrapInner = document.getElementById( 'wrap-inner' );
8
$.cbg1 = document.getElementById( 'cbg1' );
9
$.cbg2 = document.getElementById( 'cbg2' );
10
$.cbg3 = document.getElementById( 'cbg3' );
11
$.cbg4 = document.getElementById( 'cbg4' );
12
$.cmg = document.getElementById( 'cmg' );
13
$.cfg = document.getElementById( 'cfg' );
14
$.ctxbg1 = $.cbg1.getContext( '2d' );
15
$.ctxbg2 = $.cbg2.getContext( '2d' );
16
$.ctxbg3 = $.cbg3.getContext( '2d' );
17
$.ctxbg4 = $.cbg4.getContext( '2d' );
18
$.ctxmg = $.cmg.getContext( '2d' );
19
$.ctxfg = $.cfg.getContext( '2d' );
20
$.cw = $.cmg.width = $.cfg.width = 800;
21
$.ch = $.cmg.height = $.cfg.height = 600;
22
$.wrap.style.width = $.wrapInner.style.width = $.cw + 'px';
23
$.wrap.style.height = $.wrapInner.style.height = $.ch + 'px';
24
$.wrap.style.marginLeft = ( -$.cw / 2 ) - 10 + 'px';
25
$.wrap.style.marginTop = ( -$.ch / 2 ) - 10 + 'px';
26
$.ww = Math.floor( $.cw * 2 );
27
$.wh = Math.floor( $.ch * 2 );
28
$.cbg1.width = Math.floor( $.cw * 1.1 );
29
$.cbg1.height = Math.floor( $.ch * 1.1 );
30
$.cbg2.width = Math.floor( $.cw * 1.15 );
31
$.cbg2.height = Math.floor( $.ch * 1.15 );
32
$.cbg3.width = Math.floor( $.cw * 1.2 );
33
$.cbg3.height = Math.floor( $.ch * 1.2 );
34
$.cbg4.width = Math.floor( $.cw * 1.25 );
35
$.cbg4.height = Math.floor( $.ch * 1.25 );
36
37
$.screen = {
38
x: ( $.ww - $.cw ) / -2,
39
y: ( $.wh - $.ch ) / -2
40
};
41
42
$.mute = $.storage['mute'];
43
$.autofire = $.storage['autofire'];
44
$.slowEnemyDivider = 3;
45
46
$.keys = {
47
state: {
48
up: 0,
49
down: 0,
50
left: 0,
51
right: 0,
52
f: 0,
53
m: 0,
54
p: 0
55
},
56
pressed: {
57
up: 0,
58
down: 0,
59
left: 0,
60
right: 0,
61
f: 0,
62
m: 0,
63
p: 0
64
}
65
};
66
$.okeys = {};
67
$.mouse = {
68
x: $.ww / 2,
69
y: $.wh / 2,
70
sx: 0,
71
sy: 0,
72
ax: window.innerWidth / 2,
73
ay: 0,
74
down: 0
75
};
76
$.buttons = [];
77
78
$.minimap = {
79
x: 20,
80
y: $.ch - Math.floor( $.ch * 0.1 ) - 20,
81
width: Math.floor( $.cw * 0.1 ),
82
height: Math.floor( $.ch * 0.1 ),
83
scale: Math.floor( $.cw * 0.1 ) / $.ww,
84
color: 'hsla(0, 0%, 0%, 0.85)',
85
strokeColor: '#3a3a3a'
86
},
87
$.cOffset = {
88
left: 0,
89
top: 0
90
};
91
92
$.levelCount = $.definitions.levels.length;
93
$.states = {};
94
$.state = '';
95
$.enemies = [];
96
$.bullets = [];
97
$.explosions = [];
98
$.powerups = [];
99
$.particleEmitters = [];
100
$.textPops = [];
101
$.levelPops = [];
102
$.powerupTimers = [];
103
104
$.resizecb();
105
$.bindEvents();
106
$.setupStates();
107
$.renderBackground1();
108
$.renderBackground2();
109
$.renderBackground3();
110
$.renderBackground4();
111
$.renderForeground();
112
$.renderFavicon();
113
$.setState( 'menu' );
114
$.loop();
115
};
116
117
/*==============================================================================
118
Reset
119
==============================================================================*/
120
$.reset = function() {
121
$.indexGlobal = 0;
122
$.dt = 1;
123
$.lt = 0;
124
$.elapsed = 0;
125
$.tick = 0;
126
127
$.gameoverTick = 0;
128
$.gameoverTickMax = 200;
129
$.gameoverExplosion = 0;
130
131
$.instructionTick = 0;
132
$.instructionTickMax = 400;
133
134
$.levelDiffOffset = 0;
135
$.enemyOffsetMod = 0;
136
$.slow = 0;
137
138
$.screen = {
139
x: ( $.ww - $.cw ) / -2,
140
y: ( $.wh - $.ch ) / -2
141
};
142
$.rumble = {
143
x: 0,
144
y: 0,
145
level: 0,
146
decay: 0.4
147
};
148
149
$.mouse.down = 0;
150
151
$.level = {
152
current: 0,
153
kills: 0,
154
killsToLevel: $.definitions.levels[ 0 ].killsToLevel,
155
distribution: $.definitions.levels[ 0 ].distribution,
156
distributionCount: $.definitions.levels[ 0 ].distribution.length
157
};
158
159
$.enemies.length = 0;
160
$.bullets.length = 0;
161
$.explosions.length = 0;
162
$.powerups.length = 0;
163
$.particleEmitters.length = 0;
164
$.textPops.length = 0;
165
$.levelPops.length = 0;
166
$.powerupTimers.length = 0;
167
168
for( var i = 0; i < $.definitions.powerups.length; i++ ) {
169
$.powerupTimers.push( 0 );
170
}
171
172
$.kills = 0;
173
$.bulletsFired = 0;
174
$.powerupsCollected = 0;
175
$.score = 0;
176
177
$.hero = new $.Hero();
178
179
$.levelPops.push( new $.LevelPop( {
180
level: 1
181
} ) );
182
};
183
184
/*==============================================================================
185
Create Favicon
186
==============================================================================*/
187
$.renderFavicon = function() {
188
var favicon = document.getElementById( 'favicon' ),
189
favc = document.createElement( 'canvas' ),
190
favctx = favc.getContext( '2d' ),
191
faviconGrid = [
192
[ 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
193
[ 1, , , , , , , , , , , , , , , 1 ],
194
[ 1, , , , , , , , , , , , , , , 1 ],
195
[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],
196
[ 1, , , , , 1, 1, , , 1, 1, 1, 1, 1, , 0 ],
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 ],
203
[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],
204
[ , , 1, 1, 1, 1, 1, , , 1, 1, , , , , 1 ],
205
[ 1, , , , , , , , , , , , , , , 1 ],
206
[ 1, , , , , , , , , , , , , , , 1 ],
207
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1 ]
208
];
209
favc.width = favc.height = 16;
210
favctx.beginPath();
211
for( var y = 0; y < 16; y++ ) {
212
for( var x = 0; x < 16; x++ ) {
213
if( faviconGrid[ y ][ x ] === 1 ) {
214
favctx.rect( x, y, 1, 1 );
215
}
216
}
217
}
218
favctx.fill();
219
favicon.href = favc.toDataURL();
220
};
221
222
/*==============================================================================
223
Render Backgrounds
224
==============================================================================*/
225
$.renderBackground1 = function() {
226
var gradient = $.ctxbg1.createRadialGradient( $.cbg1.width / 2, $.cbg1.height / 2, 0, $.cbg1.width / 2, $.cbg1.height / 2, $.cbg1.height );
227
gradient.addColorStop( 0, 'hsla(0, 0%, 100%, 0.1)' );
228
gradient.addColorStop( 0.65, 'hsla(0, 0%, 100%, 0)' );
229
$.ctxbg1.fillStyle = gradient;
230
$.ctxbg1.fillRect( 0, 0, $.cbg1.width, $.cbg1.height );
231
232
var i = 2000;
233
while( i-- ) {
234
$.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 ) + ')' );
235
}
236
237
var i = 800;
238
while( i-- ) {
239
$.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 ) + ')' );
240
}
241
}
242
243
$.renderBackground2 = function() {
244
var i = 80;
245
while( i-- ) {
246
$.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 ) + ')' );
247
}
248
}
249
250
$.renderBackground3 = function() {
251
var i = 40;
252
while( i-- ) {
253
$.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 ) + ')' );
254
}
255
}
256
257
$.renderBackground4 = function() {
258
var size = 50;
259
$.ctxbg4.fillStyle = 'hsla(0, 0%, 50%, 0.05)';
260
var i = Math.round( $.cbg4.height / size );
261
while( i-- ) {
262
$.ctxbg4.fillRect( 0, i * size + 25, $.cbg4.width, 1 );
263
}
264
i = Math.round( $.cbg4.width / size );
265
while( i-- ) {
266
$.ctxbg4.fillRect( i * size, 0, 1, $.cbg4.height );
267
}
268
}
269
270
/*==============================================================================
271
Render Foreground
272
==============================================================================*/
273
$.renderForeground = function() {
274
var gradient = $.ctxfg.createRadialGradient( $.cw / 2, $.ch / 2, $.ch / 3, $.cw / 2, $.ch / 2, $.ch );
275
gradient.addColorStop( 0, 'hsla(0, 0%, 0%, 0)' );
276
gradient.addColorStop( 1, 'hsla(0, 0%, 0%, 0.5)' );
277
$.ctxfg.fillStyle = gradient;
278
$.ctxfg.fillRect( 0, 0, $.cw, $.ch );
279
280
$.ctxfg.fillStyle = 'hsla(0, 0%, 50%, 0.1)';
281
var i = Math.round( $.ch / 2 );
282
while( i-- ) {
283
$.ctxfg.fillRect( 0, i * 2, $.cw, 1 );
284
}
285
286
var gradient2 = $.ctxfg.createLinearGradient( $.cw, 0, 0, $.ch );
287
gradient2.addColorStop( 0, 'hsla(0, 0%, 100%, 0.04)' );
288
gradient2.addColorStop( 0.75, 'hsla(0, 0%, 100%, 0)' );
289
$.ctxfg.beginPath();
290
$.ctxfg.moveTo( 0, 0 );
291
$.ctxfg.lineTo( $.cw, 0 );
292
$.ctxfg.lineTo( 0, $.ch );
293
$.ctxfg.closePath();
294
$.ctxfg.fillStyle = gradient2;
295
$.ctxfg.fill();
296
}
297
298
/*==============================================================================
299
User Interface / UI / GUI / Minimap
300
==============================================================================*/
301
302
$.renderInterface = function() {
303
/*==============================================================================
304
Powerup Timers
305
==============================================================================*/
306
for( var i = 0; i < $.definitions.powerups.length; i++ ) {
307
var powerup = $.definitions.powerups[ i ],
308
powerupOn = ( $.powerupTimers[ i ] > 0 );
309
$.ctxmg.beginPath();
310
var powerupText = $.text( {
311
ctx: $.ctxmg,
312
x: $.minimap.x + $.minimap.width + 90,
313
y: $.minimap.y + 4 + ( i * 12 ),
314
text: powerup.title,
315
hspacing: 1,
316
vspacing: 1,
317
halign: 'right',
318
valign: 'top',
319
scale: 1,
320
snap: 1,
321
render: 1
322
} );
323
if( powerupOn ) {
324
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + ( 0.25 + ( ( $.powerupTimers[ i ] / 300 ) * 0.75 ) ) + ')';
325
} else {
326
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
327
}
328
$.ctxmg.fill();
329
if( powerupOn ) {
330
var powerupBar = {
331
x: powerupText.ex + 5,
332
y: powerupText.sy,
333
width: 110,
334
height: 5
335
};
336
$.ctxmg.fillStyle = 'hsl(' + powerup.hue + ', ' + powerup.saturation + '%, ' + powerup.lightness + '%)';
337
$.ctxmg.fillRect( powerupBar.x, powerupBar.y, ( $.powerupTimers[ i ] / 300 ) * powerupBar.width, powerupBar.height );
338
}
339
}
340
341
/*==============================================================================
342
Instructions
343
==============================================================================*/
344
if( $.instructionTick < $.instructionTickMax ){
345
$.instructionTick += $.dt;
346
$.ctxmg.beginPath();
347
$.text( {
348
ctx: $.ctxmg,
349
x: $.cw / 2 - 10,
350
y: $.ch - 20,
351
text: 'MOVE\nAIM/FIRE\nAUTOFIRE\nPAUSE\nMUTE',
352
hspacing: 1,
353
vspacing: 17,
354
halign: 'right',
355
valign: 'bottom',
356
scale: 2,
357
snap: 1,
358
render: 1
359
} );
360
if( $.instructionTick < $.instructionTickMax * 0.25 ) {
361
var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 0.5;
362
} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {
363
var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 0.5;
364
} else {
365
var alpha = 0.5;
366
}
367
alpha = Math.min( 1, Math.max( 0, alpha ) );
368
369
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';
370
$.ctxmg.fill();
371
372
$.ctxmg.beginPath();
373
$.text( {
374
ctx: $.ctxmg,
375
x: $.cw / 2 + 10,
376
y: $.ch - 20,
377
text: 'WASD/ARROWS\nMOUSE\nF\nP\nM',
378
hspacing: 1,
379
vspacing: 17,
380
halign: 'left',
381
valign: 'bottom',
382
scale: 2,
383
snap: 1,
384
render: 1
385
} );
386
if( $.instructionTick < $.instructionTickMax * 0.25 ) {
387
var alpha = ( $.instructionTick / ( $.instructionTickMax * 0.25 ) ) * 1;
388
} else if( $.instructionTick > $.instructionTickMax - $.instructionTickMax * 0.25 ) {
389
var alpha = ( ( $.instructionTickMax - $.instructionTick ) / ( $.instructionTickMax * 0.25 ) ) * 1;
390
} else {
391
var alpha = 1;
392
}
393
alpha = Math.min( 1, Math.max( 0, alpha ) );
394
395
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, ' + alpha + ')';
396
$.ctxmg.fill();
397
}
398
399
/*==============================================================================
400
Slow Enemies Screen Cover
401
==============================================================================*/
402
if( $.powerupTimers[ 1 ] > 0 ) {
403
$.ctxmg.fillStyle = 'hsla(200, 100%, 20%, 0.05)';
404
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
405
}
406
407
/*==============================================================================
408
Health
409
==============================================================================*/
410
$.ctxmg.beginPath();
411
var healthText = $.text( {
412
ctx: $.ctxmg,
413
x: 20,
414
y: 20,
415
text: 'HEALTH',
416
hspacing: 1,
417
vspacing: 1,
418
halign: 'top',
419
valign: 'left',
420
scale: 2,
421
snap: 1,
422
render: 1
423
} );
424
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
425
$.ctxmg.fill();
426
var healthBar = {
427
x: healthText.ex + 10,
428
y: healthText.sy,
429
width: 110,
430
height: 10
431
};
432
$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';
433
$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height );
434
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
435
$.ctxmg.fillRect( healthBar.x, healthBar.y, healthBar.width, healthBar.height / 2 );
436
$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 40%, 1)';
437
$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height );
438
$.ctxmg.fillStyle = 'hsla(' + $.hero.life * 120 + ', 100%, 75%, 1)';
439
$.ctxmg.fillRect( healthBar.x, healthBar.y, $.hero.life * healthBar.width, healthBar.height / 2 );
440
441
if( $.hero.takingDamage && $.hero.life > 0.01 ) {
442
$.particleEmitters.push( new $.ParticleEmitter( {
443
x: -$.screen.x + healthBar.x + $.hero.life * healthBar.width,
444
y: -$.screen.y + healthBar.y + healthBar.height / 2,
445
count: 1,
446
spawnRange: 2,
447
friction: 0.85,
448
minSpeed: 2,
449
maxSpeed: 20,
450
minDirection: $.pi / 2 - 0.2,
451
maxDirection: $.pi / 2 + 0.2,
452
hue: $.hero.life * 120,
453
saturation: 100
454
} ) );
455
}
456
457
/*==============================================================================
458
Progress
459
==============================================================================*/
460
$.ctxmg.beginPath();
461
var progressText = $.text( {
462
ctx: $.ctxmg,
463
x: healthBar.x + healthBar.width + 40,
464
y: 20,
465
text: 'PROGRESS',
466
hspacing: 1,
467
vspacing: 1,
468
halign: 'top',
469
valign: 'left',
470
scale: 2,
471
snap: 1,
472
render: 1
473
} );
474
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
475
$.ctxmg.fill();
476
var progressBar = {
477
x: progressText.ex + 10,
478
y: progressText.sy,
479
width: healthBar.width,
480
height: healthBar.height
481
};
482
$.ctxmg.fillStyle = 'hsla(0, 0%, 20%, 1)';
483
$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height );
484
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.25)';
485
$.ctxmg.fillRect( progressBar.x, progressBar.y, progressBar.width, progressBar.height / 2 );
486
$.ctxmg.fillStyle = 'hsla(0, 0%, 50%, 1)';
487
$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height );
488
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
489
$.ctxmg.fillRect( progressBar.x, progressBar.y, ( $.level.kills / $.level.killsToLevel ) * progressBar.width, progressBar.height / 2 );
490
491
if( $.level.kills == $.level.killsToLevel ) {
492
$.particleEmitters.push( new $.ParticleEmitter( {
493
x: -$.screen.x + progressBar.x + progressBar.width,
494
y: -$.screen.y + progressBar.y + progressBar.height / 2,
495
count: 30,
496
spawnRange: 5,
497
friction: 0.95,
498
minSpeed: 2,
499
maxSpeed: 25,
500
minDirection: 0,
501
minDirection: $.pi / 2 - $.pi / 4,
502
maxDirection: $.pi / 2 + $.pi / 4,
503
hue: 0,
504
saturation: 0
505
} ) );
506
}
507
508
/*==============================================================================
509
Score
510
==============================================================================*/
511
$.ctxmg.beginPath();
512
var scoreLabel = $.text( {
513
ctx: $.ctxmg,
514
x: progressBar.x + progressBar.width + 40,
515
y: 20,
516
text: 'SCORE',
517
hspacing: 1,
518
vspacing: 1,
519
halign: 'top',
520
valign: 'left',
521
scale: 2,
522
snap: 1,
523
render: 1
524
} );
525
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
526
$.ctxmg.fill();
527
528
$.ctxmg.beginPath();
529
var scoreText = $.text( {
530
ctx: $.ctxmg,
531
x: scoreLabel.ex + 10,
532
y: 20,
533
text: $.util.pad( $.score, 6 ),
534
hspacing: 1,
535
vspacing: 1,
536
halign: 'top',
537
valign: 'left',
538
scale: 2,
539
snap: 1,
540
render: 1
541
} );
542
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
543
$.ctxmg.fill();
544
545
$.ctxmg.beginPath();
546
var bestLabel = $.text( {
547
ctx: $.ctxmg,
548
x: scoreText.ex + 40,
549
y: 20,
550
text: 'BEST',
551
hspacing: 1,
552
vspacing: 1,
553
halign: 'top',
554
valign: 'left',
555
scale: 2,
556
snap: 1,
557
render: 1
558
} );
559
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
560
$.ctxmg.fill();
561
562
$.ctxmg.beginPath();
563
var bestText = $.text( {
564
ctx: $.ctxmg,
565
x: bestLabel.ex + 10,
566
y: 20,
567
text: $.util.pad( Math.max( $.storage['score'], $.score ), 6 ),
568
hspacing: 1,
569
vspacing: 1,
570
halign: 'top',
571
valign: 'left',
572
scale: 2,
573
snap: 1,
574
render: 1
575
} );
576
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 1)';
577
$.ctxmg.fill();
578
};
579
580
$.renderMinimap = function() {
581
$.ctxmg.fillStyle = $.minimap.color;
582
$.ctxmg.fillRect( $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height );
583
584
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.1)';
585
$.ctxmg.fillRect(
586
Math.floor( $.minimap.x + -$.screen.x * $.minimap.scale ),
587
Math.floor( $.minimap.y + -$.screen.y * $.minimap.scale ),
588
Math.floor( $.cw * $.minimap.scale ),
589
Math.floor( $.ch * $.minimap.scale )
590
);
591
592
//$.ctxmg.beginPath();
593
for( var i = 0; i < $.enemies.length; i++ ){
594
var enemy = $.enemies[ i ],
595
x = $.minimap.x + Math.floor( enemy.x * $.minimap.scale ),
596
y = $.minimap.y + Math.floor( enemy.y * $.minimap.scale );
597
if( $.util.pointInRect( x + 1, y + 1, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {
598
//$.ctxmg.rect( x, y, 2, 2 );
599
$.ctxmg.fillStyle = 'hsl(' + enemy.hue + ', ' + enemy.saturation + '%, 50%)';
600
$.ctxmg.fillRect( x, y, 2, 2 );
601
}
602
}
603
//$.ctxmg.fillStyle = '#f00';
604
//$.ctxmg.fill();
605
606
$.ctxmg.beginPath();
607
for( var i = 0; i < $.bullets.length; i++ ){
608
var bullet = $.bullets[ i ],
609
x = $.minimap.x + Math.floor( bullet.x * $.minimap.scale ),
610
y = $.minimap.y + Math.floor( bullet.y * $.minimap.scale );
611
if( $.util.pointInRect( x, y, $.minimap.x, $.minimap.y, $.minimap.width, $.minimap.height ) ) {
612
$.ctxmg.rect( x, y, 1, 1 );
613
}
614
}
615
$.ctxmg.fillStyle = '#fff';
616
$.ctxmg.fill();
617
618
$.ctxmg.fillStyle = $.hero.fillStyle;
619
$.ctxmg.fillRect( $.minimap.x + Math.floor( $.hero.x * $.minimap.scale ), $.minimap.y + Math.floor( $.hero.y * $.minimap.scale ), 2, 2 );
620
621
$.ctxmg.strokeStyle = $.minimap.strokeColor;
622
$.ctxmg.strokeRect( $.minimap.x - 0.5, $.minimap.y - 0.5, $.minimap.width + 1, $.minimap.height + 1 );
623
};
624
625
/*==============================================================================
626
Enemy Spawning
627
==============================================================================*/
628
$.getSpawnCoordinates = function( radius ) {
629
var quadrant = Math.floor( $.util.rand( 0, 4 ) ),
630
x,
631
y,
632
start;
633
634
if( quadrant === 0){
635
x = $.util.rand( 0, $.ww );
636
y = -radius;
637
start = 'top';
638
} else if( quadrant === 1 ){
639
x = $.ww + radius;
640
y = $.util.rand( 0, $.wh );
641
start = 'right';
642
} else if( quadrant === 2 ) {
643
x = $.util.rand( 0, $.ww );
644
y = $.wh + radius;
645
start = 'bottom';
646
} else {
647
x = -radius;
648
y = $.util.rand( 0, $.wh );
649
start = 'left';
650
}
651
652
return { x: x, y: y, start: start };
653
};
654
655
$.spawnEnemy = function( type ) {
656
var params = $.definitions.enemies[ type ],
657
coordinates = $.getSpawnCoordinates( params.radius );
658
params.x = coordinates.x;
659
params.y = coordinates.y;
660
params.start = coordinates.start;
661
params.type = type;
662
return new $.Enemy( params );
663
};
664
665
$.spawnEnemies = function() {
666
var floorTick = Math.floor( $.tick );
667
for( var i = 0; i < $.level.distributionCount; i++ ) {
668
var timeCheck = $.level.distribution[ i ];
669
if( $.levelDiffOffset > 0 ){
670
timeCheck = Math.max( 1, timeCheck - ( $.levelDiffOffset * 2) );
671
}
672
if( floorTick % timeCheck === 0 ) {
673
$.enemies.push( $.spawnEnemy( i ) );
674
}
675
}
676
};
677
678
/*==============================================================================
679
Events
680
==============================================================================*/
681
$.mousemovecb = function( e ) {
682
e.preventDefault();
683
$.mouse.ax = e.pageX;
684
$.mouse.ay = e.pageY;
685
$.mousescreen();
686
};
687
688
$.mousescreen = function() {
689
$.mouse.sx = $.mouse.ax - $.cOffset.left;
690
$.mouse.sy = $.mouse.ay - $.cOffset.top;
691
$.mouse.x = $.mouse.sx - $.screen.x;
692
$.mouse.y = $.mouse.sy - $.screen.y;
693
};
694
695
$.mousedowncb = function( e ) {
696
e.preventDefault();
697
$.mouse.down = 1;
698
};
699
700
$.mouseupcb = function( e ) {
701
e.preventDefault();
702
$.mouse.down = 0;
703
};
704
705
$.keydowncb = function( e ) {
706
var e = ( e.keyCode ? e.keyCode : e.which );
707
if( e === 38 || e === 87 ){ $.keys.state.up = 1; }
708
if( e === 39 || e === 68 ){ $.keys.state.right = 1; }
709
if( e === 40 || e === 83 ){ $.keys.state.down = 1; }
710
if( e === 37 || e === 65 ){ $.keys.state.left = 1; }
711
if( e === 70 ){ $.keys.state.f = 1; }
712
if( e === 77 ){ $.keys.state.m = 1; }
713
if( e === 80 ){ $.keys.state.p = 1; }
714
}
715
716
$.keyupcb = function( e ) {
717
var e = ( e.keyCode ? e.keyCode : e.which );
718
if( e === 38 || e === 87 ){ $.keys.state.up = 0; }
719
if( e === 39 || e === 68 ){ $.keys.state.right = 0; }
720
if( e === 40 || e === 83 ){ $.keys.state.down = 0; }
721
if( e === 37 || e === 65 ){ $.keys.state.left = 0; }
722
if( e === 70 ){ $.keys.state.f = 0; }
723
if( e === 77 ){ $.keys.state.m = 0; }
724
if( e === 80 ){ $.keys.state.p = 0; }
725
}
726
727
$.resizecb = function( e ) {
728
var rect = $.cmg.getBoundingClientRect();
729
$.cOffset = {
730
left: rect.left,
731
top: rect.top
732
}
733
}
734
735
$.blurcb = function() {
736
if( $.state == 'play' ){
737
$.setState( 'pause' );
738
}
739
}
740
741
$.bindEvents = function() {
742
window.addEventListener( 'mousemove', $.mousemovecb );
743
window.addEventListener( 'mousedown', $.mousedowncb );
744
window.addEventListener( 'mouseup', $.mouseupcb );
745
window.addEventListener( 'keydown', $.keydowncb );
746
window.addEventListener( 'keyup', $.keyupcb );
747
window.addEventListener( 'resize', $.resizecb );
748
window.addEventListener( 'blur', $.blurcb );
749
};
750
751
/*==============================================================================
752
Miscellaneous
753
==============================================================================*/
754
$.clearScreen = function() {
755
$.ctxmg.clearRect( 0, 0, $.cw, $.ch );
756
};
757
758
$.updateDelta = function() {
759
var now = Date.now();
760
$.dt = ( now - $.lt ) / ( 1000 / 60 );
761
$.dt = ( $.dt < 0 ) ? 0.001 : $.dt;
762
$.dt = ( $.dt > 10 ) ? 10 : $.dt;
763
$.lt = now;
764
$.elapsed += $.dt;
765
};
766
767
$.updateScreen = function() {
768
var xSnap,
769
xModify,
770
ySnap,
771
yModify;
772
773
if( $.hero.x < $.cw / 2 ) {
774
xModify = $.hero.x / $.cw;
775
} else if( $.hero.x > $.ww - $.cw / 2 ) {
776
xModify = 1 - ( $.ww - $.hero.x ) / $.cw;
777
} else {
778
xModify = 0.5;
779
}
780
781
if( $.hero.y < $.ch / 2 ) {
782
yModify = $.hero.y / $.ch;
783
} else if( $.hero.y > $.wh - $.ch / 2 ) {
784
yModify = 1 - ( $.wh - $.hero.y ) / $.ch;
785
} else {
786
yModify = 0.5;
787
}
788
789
xSnap = ( ( $.cw * xModify - $.hero.x ) - $.screen.x ) / 30;
790
ySnap = ( ( $.ch * yModify - $.hero.y ) - $.screen.y ) / 30;
791
792
// ease to new coordinates
793
$.screen.x += xSnap * $.dt;
794
$.screen.y += ySnap * $.dt;
795
796
// update rumble levels, keep X and Y changes consistent, apply rumble
797
if( $.rumble.level > 0 ) {
798
$.rumble.level -= $.rumble.decay;
799
$.rumble.level = ( $.rumble.level < 0 ) ? 0 : $.rumble.level;
800
$.rumble.x = $.util.rand( -$.rumble.level, $.rumble.level );
801
$.rumble.y = $.util.rand( -$.rumble.level, $.rumble.level );
802
} else {
803
$.rumble.x = 0;
804
$.rumble.y = 0;
805
}
806
807
//$.screen.x -= $.rumble.x;
808
//$.screen.y -= $.rumble.y;
809
810
// animate background canvas
811
$.cbg1.style.marginLeft =
812
-( ( $.cbg1.width - $.cw ) / 2 ) // half the difference from bg to viewport
813
- ( ( $.cbg1.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
814
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
815
- $.rumble.x + 'px';
816
$.cbg1.style.marginTop =
817
-( ( $.cbg1.height - $.ch ) / 2 )
818
- ( ( $.cbg1.height - $.ch ) / 2 )
819
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
820
- $.rumble.y + 'px';
821
$.cbg2.style.marginLeft =
822
-( ( $.cbg2.width - $.cw ) / 2 ) // half the difference from bg to viewport
823
- ( ( $.cbg2.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
824
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
825
- $.rumble.x + 'px';
826
$.cbg2.style.marginTop =
827
-( ( $.cbg2.height - $.ch ) / 2 )
828
- ( ( $.cbg2.height - $.ch ) / 2 )
829
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
830
- $.rumble.y + 'px';
831
$.cbg3.style.marginLeft =
832
-( ( $.cbg3.width - $.cw ) / 2 ) // half the difference from bg to viewport
833
- ( ( $.cbg3.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
834
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
835
- $.rumble.x + 'px';
836
$.cbg3.style.marginTop =
837
-( ( $.cbg3.height - $.ch ) / 2 )
838
- ( ( $.cbg3.height - $.ch ) / 2 )
839
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
840
- $.rumble.y + 'px';
841
$.cbg4.style.marginLeft =
842
-( ( $.cbg4.width - $.cw ) / 2 ) // half the difference from bg to viewport
843
- ( ( $.cbg4.width - $.cw ) / 2 ) // half the diff again, modified by a percentage below
844
* ( ( -$.screen.x - ( $.ww - $.cw ) / 2 ) / ( ( $.ww - $.cw ) / 2) ) // viewport offset applied to bg
845
- $.rumble.x + 'px';
846
$.cbg4.style.marginTop =
847
-( ( $.cbg4.height - $.ch ) / 2 )
848
- ( ( $.cbg4.height - $.ch ) / 2 )
849
* ( ( -$.screen.y - ( $.wh - $.ch ) / 2 ) / ( ( $.wh - $.ch ) / 2) )
850
- $.rumble.y + 'px';
851
852
$.mousescreen();
853
};
854
855
$.updateLevel = function() {
856
if( $.level.kills >= $.level.killsToLevel ) {
857
if( $.level.current + 1 < $.levelCount ){
858
$.level.current++;
859
$.level.kills = 0;
860
$.level.killsToLevel = $.definitions.levels[ $.level.current ].killsToLevel;
861
$.level.distribution = $.definitions.levels[ $.level.current ].distribution;
862
$.level.distributionCount = $.level.distribution.length;
863
} else {
864
$.level.current++;
865
$.level.kills = 0;
866
// no more level definitions, so take the last level and increase the spawn rate slightly
867
//for( var i = 0; i < $.level.distributionCount; i++ ) {
868
//$.level.distribution[ i ] = Math.max( 1, $.level.distribution[ i ] - 5 );
869
//}
870
}
871
$.levelDiffOffset = $.level.current + 1 - $.levelCount;
872
$.levelPops.push( new $.LevelPop( {
873
level: $.level.current + 1
874
} ) );
875
}
876
};
877
878
$.updatePowerupTimers = function() {
879
// HEALTH
880
if( $.powerupTimers[ 0 ] > 0 ){
881
if( $.hero.life < 1 ) {
882
$.hero.life += 0.001;
883
}
884
if( $.hero.life > 1 ) {
885
$.hero.life = 1;
886
}
887
$.powerupTimers[ 0 ] -= $.dt;
888
}
889
890
// SLOW ENEMIES
891
if( $.powerupTimers[ 1 ] > 0 ){
892
$.slow = 1;
893
$.powerupTimers[ 1 ] -= $.dt;
894
} else {
895
$.slow = 0;
896
}
897
898
// FAST SHOT
899
if( $.powerupTimers[ 2 ] > 0 ){
900
$.hero.weapon.fireRate = 2;
901
$.hero.weapon.bullet.speed = 14;
902
$.powerupTimers[ 2 ] -= $.dt;
903
} else {
904
$.hero.weapon.fireRate = 5;
905
$.hero.weapon.bullet.speed = 10;
906
}
907
908
// TRIPLE SHOT
909
if( $.powerupTimers[ 3 ] > 0 ){
910
$.hero.weapon.count = 3;
911
$.powerupTimers[ 3 ] -= $.dt;
912
} else {
913
$.hero.weapon.count = 1;
914
}
915
916
// PIERCE SHOT
917
if( $.powerupTimers[ 4 ] > 0 ){
918
$.hero.weapon.bullet.piercing = 1;
919
$.powerupTimers[ 4 ] -= $.dt;
920
} else {
921
$.hero.weapon.bullet.piercing = 0;
922
}
923
};
924
925
$.spawnPowerup = function( x, y ) {
926
if( Math.random() < 0.1 ) {
927
var min = ( $.hero.life < 0.9 ) ? 0 : 1,
928
type = Math.floor( $.util.rand( min, $.definitions.powerups.length ) ),
929
params = $.definitions.powerups[ type ];
930
params.type = type;
931
params.x = x;
932
params.y = y;
933
$.powerups.push( new $.Powerup( params ) );
934
}
935
};
936
937
/*==============================================================================
938
States
939
==============================================================================*/
940
$.setState = function( state ) {
941
// handle clean up between states
942
$.buttons.length = 0;
943
944
if( state == 'menu' ) {
945
$.mouse.down = 0;
946
$.mouse.ax = 0;
947
$.mouse.ay = 0;
948
949
$.reset();
950
951
var playButton = new $.Button( {
952
x: $.cw / 2 + 1,
953
y: $.ch / 2 - 24,
954
lockedWidth: 299,
955
lockedHeight: 49,
956
scale: 3,
957
title: 'PLAY',
958
action: function() {
959
$.reset();
960
$.audio.play( 'levelup' );
961
$.setState( 'play' );
962
}
963
} );
964
$.buttons.push( playButton );
965
966
var statsButton = new $.Button( {
967
x: $.cw / 2 + 1,
968
y: playButton.ey + 25,
969
lockedWidth: 299,
970
lockedHeight: 49,
971
scale: 3,
972
title: 'STATS',
973
action: function() {
974
$.setState( 'stats' );
975
}
976
} );
977
$.buttons.push( statsButton );
978
979
var creditsButton = new $.Button( {
980
x: $.cw / 2 + 1,
981
y: statsButton.ey + 26,
982
lockedWidth: 299,
983
lockedHeight: 49,
984
scale: 3,
985
title: 'CREDITS',
986
action: function() {
987
$.setState( 'credits' );
988
}
989
} ) ;
990
$.buttons.push( creditsButton );
991
}
992
993
if( state == 'stats' ) {
994
$.mouse.down = 0;
995
996
var clearButton = new $.Button( {
997
x: $.cw / 2 + 1,
998
y: 426,
999
lockedWidth: 299,
1000
lockedHeight: 49,
1001
scale: 3,
1002
title: 'CLEAR DATA',
1003
action: function() {
1004
$.mouse.down = 0;
1005
if( window.confirm( 'Are you sure you want to clear all locally stored game data? This cannot be undone.') ) {
1006
$.clearStorage();
1007
$.mouse.down = 0;
1008
}
1009
}
1010
} );
1011
$.buttons.push( clearButton );
1012
1013
var menuButton = new $.Button( {
1014
x: $.cw / 2 + 1,
1015
y: clearButton.ey + 25,
1016
lockedWidth: 299,
1017
lockedHeight: 49,
1018
scale: 3,
1019
title: 'MENU',
1020
action: function() {
1021
$.setState( 'menu' );
1022
}
1023
} );
1024
$.buttons.push( menuButton );
1025
}
1026
1027
if( state == 'credits' ) {
1028
$.mouse.down = 0;
1029
1030
var js13kButton = new $.Button( {
1031
x: $.cw / 2 + 1,
1032
y: 476,
1033
lockedWidth: 299,
1034
lockedHeight: 49,
1035
scale: 3,
1036
title: 'JS13KGAMES',
1037
action: function() {
1038
location.href = 'http://js13kgames.com';
1039
$.mouse.down = 0;
1040
}
1041
} );
1042
$.buttons.push( js13kButton );
1043
1044
var menuButton = new $.Button( {
1045
x: $.cw / 2 + 1,
1046
y: js13kButton.ey + 25,
1047
lockedWidth: 299,
1048
lockedHeight: 49,
1049
scale: 3,
1050
title: 'MENU',
1051
action: function() {
1052
$.setState( 'menu' );
1053
}
1054
} );
1055
$.buttons.push( menuButton );
1056
}
1057
1058
if( state == 'pause' ) {
1059
$.mouse.down = 0;
1060
$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );
1061
var resumeButton = new $.Button( {
1062
x: $.cw / 2 + 1,
1063
y: $.ch / 2 + 26,
1064
lockedWidth: 299,
1065
lockedHeight: 49,
1066
scale: 3,
1067
title: 'RESUME',
1068
action: function() {
1069
$.lt = Date.now() + 1000;
1070
$.setState( 'play' );
1071
}
1072
} );
1073
$.buttons.push( resumeButton );
1074
1075
var menuButton = new $.Button( {
1076
x: $.cw / 2 + 1,
1077
y: resumeButton.ey + 25,
1078
lockedWidth: 299,
1079
lockedHeight: 49,
1080
scale: 3,
1081
title: 'MENU',
1082
action: function() {
1083
$.mouse.down = 0;
1084
if( window.confirm( 'Are you sure you want to end this game and return to the menu?') ) {
1085
$.mousescreen();
1086
$.setState( 'menu' );
1087
}
1088
}
1089
} );
1090
$.buttons.push( menuButton );
1091
}
1092
1093
if( state == 'gameover' ) {
1094
$.mouse.down = 0;
1095
1096
$.screenshot = $.ctxmg.getImageData( 0, 0, $.cw, $.ch );
1097
var resumeButton = new $.Button( {
1098
x: $.cw / 2 + 1,
1099
y: 426,
1100
lockedWidth: 299,
1101
lockedHeight: 49,
1102
scale: 3,
1103
title: 'PLAY AGAIN',
1104
action: function() {
1105
$.reset();
1106
$.audio.play( 'levelup' );
1107
$.setState( 'play' );
1108
}
1109
} );
1110
$.buttons.push( resumeButton );
1111
1112
var menuButton = new $.Button( {
1113
x: $.cw / 2 + 1,
1114
y: resumeButton.ey + 25,
1115
lockedWidth: 299,
1116
lockedHeight: 49,
1117
scale: 3,
1118
title: 'MENU',
1119
action: function() {
1120
$.setState( 'menu' );
1121
}
1122
} );
1123
$.buttons.push( menuButton );
1124
1125
$.storage['score'] = Math.max( $.storage['score'], $.score );
1126
$.storage['level'] = Math.max( $.storage['level'], $.level.current );
1127
$.storage['rounds'] += 1;
1128
$.storage['kills'] += $.kills;
1129
$.storage['bullets'] += $.bulletsFired;
1130
$.storage['powerups'] += $.powerupsCollected;
1131
$.storage['time'] += Math.floor( $.elapsed );
1132
$.updateStorage();
1133
}
1134
1135
// set state
1136
$.state = state;
1137
};
1138
1139
$.setupStates = function() {
1140
$.states['menu'] = function() {
1141
$.clearScreen();
1142
$.updateScreen();
1143
1144
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
1145
i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
1146
1147
$.ctxmg.beginPath();
1148
var title = $.text( {
1149
ctx: $.ctxmg,
1150
x: $.cw / 2,
1151
y: $.ch / 2 - 100,
1152
text: 'RADIUS RAID',
1153
hspacing: 2,
1154
vspacing: 1,
1155
halign: 'center',
1156
valign: 'bottom',
1157
scale: 10,
1158
snap: 1,
1159
render: 1
1160
} );
1161
gradient = $.ctxmg.createLinearGradient( title.sx, title.sy, title.sx, title.ey );
1162
gradient.addColorStop( 0, '#fff' );
1163
gradient.addColorStop( 1, '#999' );
1164
$.ctxmg.fillStyle = gradient;
1165
$.ctxmg.fill();
1166
1167
$.ctxmg.beginPath();
1168
var bottomInfo = $.text( {
1169
ctx: $.ctxmg,
1170
x: $.cw / 2,
1171
y: $.ch - 172,
1172
text: 'CREATED BY JACK RUGILE FOR JS13KGAMES 2013',
1173
hspacing: 1,
1174
vspacing: 1,
1175
halign: 'center',
1176
valign: 'bottom',
1177
scale: 1,
1178
snap: 1,
1179
render: 1
1180
} );
1181
$.ctxmg.fillStyle = '#666';
1182
$.ctxmg.fill();
1183
1184
};
1185
1186
$.states['stats'] = function() {
1187
$.clearScreen();
1188
1189
$.ctxmg.beginPath();
1190
var statsTitle = $.text( {
1191
ctx: $.ctxmg,
1192
x: $.cw / 2,
1193
y: 150,
1194
text: 'STATS',
1195
hspacing: 3,
1196
vspacing: 1,
1197
halign: 'center',
1198
valign: 'bottom',
1199
scale: 10,
1200
snap: 1,
1201
render: 1
1202
} );
1203
var gradient = $.ctxmg.createLinearGradient( statsTitle.sx, statsTitle.sy, statsTitle.sx, statsTitle.ey );
1204
gradient.addColorStop( 0, '#fff' );
1205
gradient.addColorStop( 1, '#999' );
1206
$.ctxmg.fillStyle = gradient;
1207
$.ctxmg.fill();
1208
1209
$.ctxmg.beginPath();
1210
var statKeys = $.text( {
1211
ctx: $.ctxmg,
1212
x: $.cw / 2 - 10,
1213
y: statsTitle.ey + 39,
1214
text: 'BEST SCORE\nBEST LEVEL\nROUNDS PLAYED\nENEMIES KILLED\nBULLETS FIRED\nPOWERUPS COLLECTED\nTIME ELAPSED',
1215
hspacing: 1,
1216
vspacing: 17,
1217
halign: 'right',
1218
valign: 'top',
1219
scale: 2,
1220
snap: 1,
1221
render: 1
1222
} );
1223
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
1224
$.ctxmg.fill();
1225
1226
$.ctxmg.beginPath();
1227
var statsValues = $.text( {
1228
ctx: $.ctxmg,
1229
x: $.cw / 2 + 10,
1230
y: statsTitle.ey + 39,
1231
text:
1232
$.util.commas( $.storage['score'] ) + '\n' +
1233
( $.storage['level'] + 1 ) + '\n' +
1234
$.util.commas( $.storage['rounds'] ) + '\n' +
1235
$.util.commas( $.storage['kills'] ) + '\n' +
1236
$.util.commas( $.storage['bullets'] ) + '\n' +
1237
$.util.commas( $.storage['powerups'] ) + '\n' +
1238
$.util.convertTime( ( $.storage['time'] * ( 1000 / 60 ) ) / 1000 )
1239
,
1240
hspacing: 1,
1241
vspacing: 17,
1242
halign: 'left',
1243
valign: 'top',
1244
scale: 2,
1245
snap: 1,
1246
render: 1
1247
} );
1248
$.ctxmg.fillStyle = '#fff';
1249
$.ctxmg.fill();
1250
1251
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
1252
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
1253
};
1254
1255
$.states['credits'] = function() {
1256
$.clearScreen();
1257
1258
$.ctxmg.beginPath();
1259
var creditsTitle = $.text( {
1260
ctx: $.ctxmg,
1261
x: $.cw / 2,
1262
y: 100,
1263
text: 'CREDITS',
1264
hspacing: 3,
1265
vspacing: 1,
1266
halign: 'center',
1267
valign: 'bottom',
1268
scale: 10,
1269
snap: 1,
1270
render: 1
1271
} );
1272
var gradient = $.ctxmg.createLinearGradient( creditsTitle.sx, creditsTitle.sy, creditsTitle.sx, creditsTitle.ey );
1273
gradient.addColorStop( 0, '#fff' );
1274
gradient.addColorStop( 1, '#999' );
1275
$.ctxmg.fillStyle = gradient;
1276
$.ctxmg.fill();
1277
1278
$.ctxmg.beginPath();
1279
var creditKeys = $.text( {
1280
ctx: $.ctxmg,
1281
x: $.cw / 2 - 10,
1282
y: creditsTitle.ey + 49,
1283
text: 'CREATED FOR JS13KGAMES BY\nINSPIRATION AND SUPPORT\n\nAUDIO PROCESSING\nGAME INSPIRATION AND IDEAS\n\nHTML5 CANVAS REFERENCE\n\nGAME MATH REFERENCE',
1284
hspacing: 1,
1285
vspacing: 17,
1286
halign: 'right',
1287
valign: 'top',
1288
scale: 2,
1289
snap: 1,
1290
render: 1
1291
} );
1292
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
1293
$.ctxmg.fill();
1294
1295
$.ctxmg.beginPath();
1296
var creditValues = $.text( {
1297
ctx: $.ctxmg,
1298
x: $.cw / 2 + 10,
1299
y: creditsTitle.ey + 49,
1300
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',
1301
hspacing: 1,
1302
vspacing: 17,
1303
halign: 'left',
1304
valign: 'top',
1305
scale: 2,
1306
snap: 1,
1307
render: 1
1308
} );
1309
$.ctxmg.fillStyle = '#fff';
1310
$.ctxmg.fill();
1311
1312
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
1313
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
1314
};
1315
1316
$.states['play'] = function() {
1317
$.updateDelta();
1318
$.updateScreen();
1319
$.updateLevel();
1320
$.updatePowerupTimers();
1321
$.spawnEnemies();
1322
$.enemyOffsetMod += ( $.slow ) ? $.dt / 3 : $.dt;
1323
1324
// update entities
1325
var i = $.enemies.length; while( i-- ){ $.enemies[ i ].update( i ) }
1326
i = $.explosions.length; while( i-- ){ $.explosions[ i ].update( i ) }
1327
i = $.powerups.length; while( i-- ){ $.powerups[ i ].update( i ) }
1328
i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].update( i ) }
1329
i = $.textPops.length; while( i-- ){ $.textPops[ i ].update( i ) }
1330
i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].update( i ) }
1331
i = $.bullets.length; while( i-- ){ $.bullets[ i ].update( i ) }
1332
$.hero.update();
1333
1334
// render entities
1335
$.clearScreen();
1336
$.ctxmg.save();
1337
$.ctxmg.translate( $.screen.x - $.rumble.x, $.screen.y - $.rumble.y );
1338
i = $.enemies.length; while( i-- ){ $.enemies[ i ].render( i ) }
1339
i = $.explosions.length; while( i-- ){ $.explosions[ i ].render( i ) }
1340
i = $.powerups.length; while( i-- ){ $.powerups[ i ].render( i ) }
1341
i = $.particleEmitters.length; while( i-- ){ $.particleEmitters[ i ].render( i ) }
1342
i = $.textPops.length; while( i-- ){ $.textPops[ i ].render( i ) }
1343
i = $.bullets.length; while( i-- ){ $.bullets[ i ].render( i ) }
1344
$.hero.render();
1345
$.ctxmg.restore();
1346
i = $.levelPops.length; while( i-- ){ $.levelPops[ i ].render( i ) }
1347
$.renderInterface();
1348
$.renderMinimap();
1349
1350
// handle gameover
1351
if( $.hero.life <= 0 ) {
1352
var alpha = ( ( $.gameoverTick / $.gameoverTickMax ) * 0.8 );
1353
alpha = Math.min( 1, Math.max( 0, alpha ) );
1354
$.ctxmg.fillStyle = 'hsla(0, 100%, 0%, ' + alpha + ')';
1355
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
1356
if( $.gameoverTick < $.gameoverTickMax ){
1357
$.gameoverTick += $.dt;
1358
} else {
1359
$.setState( 'gameover' );
1360
}
1361
1362
if( !$.gameoverExplosion ) {
1363
$.audio.play( 'death' );
1364
$.rumble.level = 25;
1365
$.explosions.push( new $.Explosion( {
1366
x: $.hero.x + $.util.rand( -10, 10 ),
1367
y: $.hero.y + $.util.rand( -10, 10 ),
1368
radius: 50,
1369
hue: 0,
1370
saturation: 0
1371
} ) );
1372
$.particleEmitters.push( new $.ParticleEmitter( {
1373
x: $.hero.x,
1374
y: $.hero.y,
1375
count: 45,
1376
spawnRange: 10,
1377
friction: 0.95,
1378
minSpeed: 2,
1379
maxSpeed: 20,
1380
minDirection: 0,
1381
maxDirection: $.twopi,
1382
hue: 0,
1383
saturation: 0
1384
} ) );
1385
for( var i = 0; i < $.powerupTimers.length; i++ ){
1386
$.powerupTimers[ i ] = 0;
1387
}
1388
$.gameoverExplosion = 1;
1389
}
1390
}
1391
1392
// update tick
1393
$.tick += $.dt;
1394
1395
// listen for pause
1396
if( $.keys.pressed.p ){
1397
$.setState( 'pause' );
1398
}
1399
1400
// always listen for autofire toggle
1401
if( $.keys.pressed.f ){
1402
$.autofire = ~~!$.autofire;
1403
$.storage['autofire'] = $.autofire;
1404
$.updateStorage();
1405
}
1406
};
1407
1408
$.states['pause'] = function() {
1409
$.clearScreen();
1410
$.ctxmg.putImageData( $.screenshot, 0, 0 );
1411
1412
$.ctxmg.fillStyle = 'hsla(0, 0%, 0%, 0.4)';
1413
$.ctxmg.fillRect( 0, 0, $.cw, $.ch );
1414
1415
$.ctxmg.beginPath();
1416
var pauseText = $.text( {
1417
ctx: $.ctxmg,
1418
x: $.cw / 2,
1419
y: $.ch / 2 - 50,
1420
text: 'PAUSED',
1421
hspacing: 3,
1422
vspacing: 1,
1423
halign: 'center',
1424
valign: 'bottom',
1425
scale: 10,
1426
snap: 1,
1427
render: 1
1428
} );
1429
var gradient = $.ctxmg.createLinearGradient( pauseText.sx, pauseText.sy, pauseText.sx, pauseText.ey );
1430
gradient.addColorStop( 0, '#fff' );
1431
gradient.addColorStop( 1, '#999' );
1432
$.ctxmg.fillStyle = gradient;
1433
$.ctxmg.fill();
1434
1435
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
1436
i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
1437
1438
if( $.keys.pressed.p ){
1439
$.setState( 'play' );
1440
}
1441
};
1442
1443
$.states['gameover'] = function() {
1444
$.clearScreen();
1445
$.ctxmg.putImageData( $.screenshot, 0, 0 );
1446
1447
var i = $.buttons.length; while( i-- ){ $.buttons[ i ].update( i ) }
1448
i = $.buttons.length; while( i-- ){ $.buttons[ i ].render( i ) }
1449
1450
$.ctxmg.beginPath();
1451
var gameoverTitle = $.text( {
1452
ctx: $.ctxmg,
1453
x: $.cw / 2,
1454
y: 150,
1455
text: 'GAME OVER',
1456
hspacing: 3,
1457
vspacing: 1,
1458
halign: 'center',
1459
valign: 'bottom',
1460
scale: 10,
1461
snap: 1,
1462
render: 1
1463
} );
1464
var gradient = $.ctxmg.createLinearGradient( gameoverTitle.sx, gameoverTitle.sy, gameoverTitle.sx, gameoverTitle.ey );
1465
gradient.addColorStop( 0, '#f22' );
1466
gradient.addColorStop( 1, '#b00' );
1467
$.ctxmg.fillStyle = gradient;
1468
$.ctxmg.fill();
1469
1470
$.ctxmg.beginPath();
1471
var gameoverStatsKeys = $.text( {
1472
ctx: $.ctxmg,
1473
x: $.cw / 2 - 10,
1474
y: gameoverTitle.ey + 51,
1475
text: 'SCORE\nLEVEL\nKILLS\nBULLETS\nPOWERUPS\nTIME',
1476
hspacing: 1,
1477
vspacing: 17,
1478
halign: 'right',
1479
valign: 'top',
1480
scale: 2,
1481
snap: 1,
1482
render: 1
1483
} );
1484
$.ctxmg.fillStyle = 'hsla(0, 0%, 100%, 0.5)';
1485
$.ctxmg.fill();
1486
1487
$.ctxmg.beginPath();
1488
var gameoverStatsValues = $.text( {
1489
ctx: $.ctxmg,
1490
x: $.cw / 2 + 10,
1491
y: gameoverTitle.ey + 51,
1492
text:
1493
$.util.commas( $.score ) + '\n' +
1494
( $.level.current + 1 ) + '\n' +
1495
$.util.commas( $.kills ) + '\n' +
1496
$.util.commas( $.bulletsFired ) + '\n' +
1497
$.util.commas( $.powerupsCollected ) + '\n' +
1498
$.util.convertTime( ( $.elapsed * ( 1000 / 60 ) ) / 1000 )
1499
,
1500
hspacing: 1,
1501
vspacing: 17,
1502
halign: 'left',
1503
valign: 'top',
1504
scale: 2,
1505
snap: 1,
1506
render: 1
1507
} );
1508
$.ctxmg.fillStyle = '#fff';
1509
$.ctxmg.fill();
1510
};
1511
}
1512
1513
/*==============================================================================
1514
Loop
1515
==============================================================================*/
1516
$.loop = function() {
1517
requestAnimFrame( $.loop );
1518
1519
// setup the pressed state for all keys
1520
for( var k in $.keys.state ) {
1521
if( $.keys.state[ k ] && !$.okeys[ k ] ) {
1522
$.keys.pressed[ k ] = 1;
1523
} else {
1524
$.keys.pressed[ k ] = 0;
1525
}
1526
}
1527
1528
// run the current state
1529
$.states[ $.state ]();
1530
1531
// always listen for mute toggle
1532
if( $.keys.pressed.m ){
1533
$.mute = ~~!$.mute;
1534
var i = $.audio.references.length;
1535
while( i-- ) {
1536
$.audio.references[ i ].volume = ~~!$.mute;
1537
}
1538
$.storage['mute'] = $.mute;
1539
$.updateStorage();
1540
}
1541
1542
// move current keys into old keys
1543
$.okeys = {};
1544
for( var k in $.keys.state ) {
1545
$.okeys[ k ] = $.keys.state[ k ];
1546
}
1547
};
1548
1549
/*==============================================================================
1550
Start Game on Load
1551
==============================================================================*/
1552
window.addEventListener( 'load', function() {
1553
document.documentElement.className += ' loaded';
1554
$.init();
1555
});
1556