littlejsengine 1.9.1 → 1.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/{build → dist}/littlejs.d.ts +48 -43
- package/{build → dist}/littlejs.esm.js +256 -147
- package/dist/littlejs.esm.min.js +1 -0
- package/{build → dist}/littlejs.js +256 -147
- package/dist/littlejs.min.js +1 -0
- package/{build → dist}/littlejs.release.js +249 -144
- package/examples/breakout/game.js +2 -2
- package/examples/breakout/gameObjects.js +3 -3
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/build.js +1 -1
- package/examples/electron/game.js +49 -38
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/index.html +1 -1
- package/examples/js13k/build.js +1 -1
- package/examples/js13k/game.js +10 -9
- package/examples/js13k/index.html +13 -13
- package/examples/js13k/tiles.png +0 -0
- package/examples/logo.png +0 -0
- package/examples/module/game.js +45 -41
- package/examples/module/index.html +1 -1
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +1 -1
- package/examples/platformer/data/gameLevelData.tmx +143 -0
- package/examples/platformer/data/gameLevelData.tsx +4 -0
- package/examples/platformer/game.js +31 -11
- package/examples/platformer/gameCharacter.js +9 -7
- package/examples/platformer/gameEffects.js +105 -164
- package/examples/platformer/gameLevel.js +164 -181
- package/examples/platformer/gameLevelData.js +181 -0
- package/examples/platformer/gameObjects.js +71 -26
- package/examples/platformer/gamePlayer.js +3 -2
- package/examples/platformer/index.html +8 -7
- package/examples/platformer/tiles.png +0 -0
- package/examples/platformer/tilesLevel.png +0 -0
- package/examples/puzzle/game.js +12 -12
- package/examples/puzzle/index.html +2 -2
- package/examples/screenshot.jpg +0 -0
- package/examples/starter/build.js +1 -1
- package/examples/starter/game.js +6 -6
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +2 -2
- package/examples/typescript/build.bat +4 -1
- package/examples/typescript/game.js +34 -31
- package/examples/typescript/game.ts +40 -36
- package/examples/typescript/index.html +1 -1
- package/examples/typescript/tiles.png +0 -0
- package/package.json +3 -3
- package/reference.md +409 -0
- package/src/engine.js +46 -41
- package/src/engineAudio.js +22 -19
- package/src/engineBuild.js +9 -2
- package/src/engineDebug.js +7 -3
- package/src/engineDraw.js +8 -7
- package/src/engineInput.js +5 -5
- package/src/engineMedals.js +3 -3
- package/src/engineObject.js +2 -2
- package/src/engineParticles.js +16 -15
- package/src/engineSettings.js +3 -3
- package/src/engineTileLayer.js +3 -3
- package/src/engineUtilities.js +139 -38
- package/src/engineWebGL.js +2 -8
- package/build/littlejs.esm.min.js +0 -1
- package/build/littlejs.min.js +0 -1
- package/index.d.ts +0 -2094
|
@@ -71,7 +71,7 @@ function min(valueA, valueB) { return Math.min(valueA, valueB); }
|
|
|
71
71
|
* @memberof Utilities */
|
|
72
72
|
function max(valueA, valueB) { return Math.max(valueA, valueB); }
|
|
73
73
|
|
|
74
|
-
/** Returns the sign of value passed in
|
|
74
|
+
/** Returns the sign of value passed in
|
|
75
75
|
* @param {Number} value
|
|
76
76
|
* @return {Number}
|
|
77
77
|
* @memberof Utilities */
|
|
@@ -118,7 +118,7 @@ function lerp(percent, valueA, valueB) { return valueA + clamp(percent) * (value
|
|
|
118
118
|
function distanceWrap(valueA, valueB, wrapSize=1)
|
|
119
119
|
{ const d = (valueA - valueB) % wrapSize; return d*2 % wrapSize - d; }
|
|
120
120
|
|
|
121
|
-
/** Linearly interpolates between values passed in with
|
|
121
|
+
/** Linearly interpolates between values passed in with wrapping
|
|
122
122
|
* @param {Number} percent
|
|
123
123
|
* @param {Number} valueA
|
|
124
124
|
* @param {Number} valueB
|
|
@@ -135,7 +135,7 @@ function lerpWrap(percent, valueA, valueB, wrapSize=1)
|
|
|
135
135
|
* @memberof Utilities */
|
|
136
136
|
function distanceAngle(angleA, angleB) { return distanceWrap(angleA, angleB, 2*PI); }
|
|
137
137
|
|
|
138
|
-
/** Linearly interpolates between the angles passed in with
|
|
138
|
+
/** Linearly interpolates between the angles passed in with wrapping
|
|
139
139
|
* @param {Number} percent
|
|
140
140
|
* @param {Number} angleA
|
|
141
141
|
* @param {Number} angleB
|
|
@@ -156,13 +156,13 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
156
156
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
157
157
|
|
|
158
158
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
159
|
-
* @param {Vector2} pointA
|
|
160
|
-
* @param {Vector2} sizeA
|
|
161
|
-
* @param {Vector2} pointB
|
|
162
|
-
* @param {Vector2} sizeB - Size of box B
|
|
163
|
-
* @return {Boolean}
|
|
159
|
+
* @param {Vector2} pointA - Center of box A
|
|
160
|
+
* @param {Vector2} sizeA - Size of box A
|
|
161
|
+
* @param {Vector2} pointB - Center of box B
|
|
162
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
163
|
+
* @return {Boolean} - True if overlapping
|
|
164
164
|
* @memberof Utilities */
|
|
165
|
-
function isOverlapping(pointA, sizeA, pointB, sizeB)
|
|
165
|
+
function isOverlapping(pointA, sizeA, pointB, sizeB=vec2())
|
|
166
166
|
{
|
|
167
167
|
return abs(pointA.x - pointB.x)*2 < sizeA.x + sizeB.x
|
|
168
168
|
&& abs(pointA.y - pointB.y)*2 < sizeA.y + sizeB.y;
|
|
@@ -222,8 +222,8 @@ function randInCircle(radius=1, minRadius=0)
|
|
|
222
222
|
{ return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
|
|
223
223
|
|
|
224
224
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
225
|
-
* @param {Color} [colorA=
|
|
226
|
-
* @param {Color} [colorB=
|
|
225
|
+
* @param {Color} [colorA=(1,1,1,1)]
|
|
226
|
+
* @param {Color} [colorB=(0,0,0,1)]
|
|
227
227
|
* @param {Boolean} [linear]
|
|
228
228
|
* @return {Color}
|
|
229
229
|
* @memberof Random */
|
|
@@ -294,7 +294,11 @@ class RandomGenerator
|
|
|
294
294
|
* @memberof Utilities
|
|
295
295
|
*/
|
|
296
296
|
function vec2(x=0, y)
|
|
297
|
-
{
|
|
297
|
+
{
|
|
298
|
+
return typeof x === 'number' ?
|
|
299
|
+
new Vector2(x, y == undefined? x : y) :
|
|
300
|
+
new Vector2(x.x, x.y);
|
|
301
|
+
}
|
|
298
302
|
|
|
299
303
|
/**
|
|
300
304
|
* Check if object is a valid Vector2
|
|
@@ -302,7 +306,7 @@ function vec2(x=0, y)
|
|
|
302
306
|
* @return {Boolean}
|
|
303
307
|
* @memberof Utilities
|
|
304
308
|
*/
|
|
305
|
-
function isVector2(v) { return
|
|
309
|
+
function isVector2(v) { return v instanceof Vector2; }
|
|
306
310
|
|
|
307
311
|
/**
|
|
308
312
|
* 2D Vector object with vector math library
|
|
@@ -333,27 +337,47 @@ class Vector2
|
|
|
333
337
|
/** Returns a copy of this vector plus the vector passed in
|
|
334
338
|
* @param {Vector2} v - other vector
|
|
335
339
|
* @return {Vector2} */
|
|
336
|
-
add(v)
|
|
340
|
+
add(v)
|
|
341
|
+
{
|
|
342
|
+
ASSERT(isVector2(v));
|
|
343
|
+
return new Vector2(this.x + v.x, this.y + v.y);
|
|
344
|
+
}
|
|
337
345
|
|
|
338
346
|
/** Returns a copy of this vector minus the vector passed in
|
|
339
347
|
* @param {Vector2} v - other vector
|
|
340
348
|
* @return {Vector2} */
|
|
341
|
-
subtract(v)
|
|
349
|
+
subtract(v)
|
|
350
|
+
{
|
|
351
|
+
ASSERT(isVector2(v));
|
|
352
|
+
return new Vector2(this.x - v.x, this.y - v.y);
|
|
353
|
+
}
|
|
342
354
|
|
|
343
355
|
/** Returns a copy of this vector times the vector passed in
|
|
344
356
|
* @param {Vector2} v - other vector
|
|
345
357
|
* @return {Vector2} */
|
|
346
|
-
multiply(v)
|
|
358
|
+
multiply(v)
|
|
359
|
+
{
|
|
360
|
+
ASSERT(isVector2(v));
|
|
361
|
+
return new Vector2(this.x * v.x, this.y * v.y);
|
|
362
|
+
}
|
|
347
363
|
|
|
348
364
|
/** Returns a copy of this vector divided by the vector passed in
|
|
349
365
|
* @param {Vector2} v - other vector
|
|
350
366
|
* @return {Vector2} */
|
|
351
|
-
divide(v)
|
|
367
|
+
divide(v)
|
|
368
|
+
{
|
|
369
|
+
ASSERT(isVector2(v));
|
|
370
|
+
return new Vector2(this.x / v.x, this.y / v.y);
|
|
371
|
+
}
|
|
352
372
|
|
|
353
373
|
/** Returns a copy of this vector scaled by the vector passed in
|
|
354
374
|
* @param {Number} s - scale
|
|
355
375
|
* @return {Vector2} */
|
|
356
|
-
scale(s)
|
|
376
|
+
scale(s)
|
|
377
|
+
{
|
|
378
|
+
ASSERT(!isVector2(s));
|
|
379
|
+
return new Vector2(this.x * s, this.y * s);
|
|
380
|
+
}
|
|
357
381
|
|
|
358
382
|
/** Returns the length of this vector
|
|
359
383
|
* @return {Number} */
|
|
@@ -366,32 +390,56 @@ class Vector2
|
|
|
366
390
|
/** Returns the distance from this vector to vector passed in
|
|
367
391
|
* @param {Vector2} v - other vector
|
|
368
392
|
* @return {Number} */
|
|
369
|
-
distance(v)
|
|
393
|
+
distance(v)
|
|
394
|
+
{
|
|
395
|
+
ASSERT(isVector2(v));
|
|
396
|
+
return this.distanceSquared(v)**.5;
|
|
397
|
+
}
|
|
370
398
|
|
|
371
399
|
/** Returns the distance squared from this vector to vector passed in
|
|
372
400
|
* @param {Vector2} v - other vector
|
|
373
401
|
* @return {Number} */
|
|
374
|
-
distanceSquared(v)
|
|
402
|
+
distanceSquared(v)
|
|
403
|
+
{
|
|
404
|
+
ASSERT(isVector2(v));
|
|
405
|
+
return (this.x - v.x)**2 + (this.y - v.y)**2;
|
|
406
|
+
}
|
|
375
407
|
|
|
376
408
|
/** Returns a new vector in same direction as this one with the length passed in
|
|
377
409
|
* @param {Number} [length]
|
|
378
410
|
* @return {Vector2} */
|
|
379
|
-
normalize(length=1)
|
|
411
|
+
normalize(length=1)
|
|
412
|
+
{
|
|
413
|
+
const l = this.length();
|
|
414
|
+
return l ? this.scale(length/l) : new Vector2(0, length);
|
|
415
|
+
}
|
|
380
416
|
|
|
381
417
|
/** Returns a new vector clamped to length passed in
|
|
382
418
|
* @param {Number} [length]
|
|
383
419
|
* @return {Vector2} */
|
|
384
|
-
clampLength(length=1)
|
|
420
|
+
clampLength(length=1)
|
|
421
|
+
{
|
|
422
|
+
const l = this.length();
|
|
423
|
+
return l > length ? this.scale(length/l) : this;
|
|
424
|
+
}
|
|
385
425
|
|
|
386
426
|
/** Returns the dot product of this and the vector passed in
|
|
387
427
|
* @param {Vector2} v - other vector
|
|
388
428
|
* @return {Number} */
|
|
389
|
-
dot(v)
|
|
429
|
+
dot(v)
|
|
430
|
+
{
|
|
431
|
+
ASSERT(isVector2(v));
|
|
432
|
+
return this.x*v.x + this.y*v.y;
|
|
433
|
+
}
|
|
390
434
|
|
|
391
435
|
/** Returns the cross product of this and the vector passed in
|
|
392
436
|
* @param {Vector2} v - other vector
|
|
393
437
|
* @return {Number} */
|
|
394
|
-
cross(v)
|
|
438
|
+
cross(v)
|
|
439
|
+
{
|
|
440
|
+
ASSERT(isVector2(v));
|
|
441
|
+
return this.x*v.y - this.y*v.x;
|
|
442
|
+
}
|
|
395
443
|
|
|
396
444
|
/** Returns the angle of this vector, up is angle 0
|
|
397
445
|
* @return {Number} */
|
|
@@ -402,7 +450,11 @@ class Vector2
|
|
|
402
450
|
* @param {Number} [length]
|
|
403
451
|
* @return {Vector2} */
|
|
404
452
|
setAngle(angle=0, length=1)
|
|
405
|
-
{
|
|
453
|
+
{
|
|
454
|
+
this.x = length*Math.sin(angle);
|
|
455
|
+
this.y = length*Math.cos(angle);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
406
458
|
|
|
407
459
|
/** Returns copy of this vector rotated by the angle passed in
|
|
408
460
|
* @param {Number} angle
|
|
@@ -413,9 +465,20 @@ class Vector2
|
|
|
413
465
|
return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
|
|
414
466
|
}
|
|
415
467
|
|
|
468
|
+
/** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
469
|
+
* @param {Number} [direction]
|
|
470
|
+
* @param {Number} [length] */
|
|
471
|
+
setDirection(direction, length=1)
|
|
472
|
+
{
|
|
473
|
+
ASSERT(direction==0 || direction==1 || direction==2 || direction==3);
|
|
474
|
+
return vec2(direction%2 ? direction-1 ? -length : length : 0,
|
|
475
|
+
direction%2 ? 0 : direction ? -length : length);
|
|
476
|
+
}
|
|
477
|
+
|
|
416
478
|
/** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
417
479
|
* @return {Number} */
|
|
418
|
-
direction()
|
|
480
|
+
direction()
|
|
481
|
+
{ return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
|
|
419
482
|
|
|
420
483
|
/** Returns a copy of this vector that has been inverted
|
|
421
484
|
* @return {Vector2} */
|
|
@@ -434,24 +497,34 @@ class Vector2
|
|
|
434
497
|
* @param {Number} percent
|
|
435
498
|
* @return {Vector2} */
|
|
436
499
|
lerp(v, percent)
|
|
437
|
-
{
|
|
500
|
+
{
|
|
501
|
+
ASSERT(isVector2(v));
|
|
502
|
+
return this.add(v.subtract(this).scale(clamp(percent)));
|
|
503
|
+
}
|
|
438
504
|
|
|
439
505
|
/** Returns true if this vector is within the bounds of an array size passed in
|
|
440
506
|
* @param {Vector2} arraySize
|
|
441
507
|
* @return {Boolean} */
|
|
442
|
-
arrayCheck(arraySize)
|
|
508
|
+
arrayCheck(arraySize)
|
|
509
|
+
{
|
|
510
|
+
ASSERT(isVector2(arraySize));
|
|
511
|
+
return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y;
|
|
512
|
+
}
|
|
443
513
|
|
|
444
514
|
/** Returns this vector expressed as a string
|
|
445
515
|
* @param {Number} digits - precision to display
|
|
446
516
|
* @return {String} */
|
|
447
517
|
toString(digits=3)
|
|
448
|
-
{
|
|
518
|
+
{
|
|
519
|
+
if (debug)
|
|
520
|
+
return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
|
|
521
|
+
}
|
|
449
522
|
}
|
|
450
523
|
|
|
451
524
|
///////////////////////////////////////////////////////////////////////////////
|
|
452
525
|
|
|
453
526
|
/**
|
|
454
|
-
* Create a color object with RGBA values
|
|
527
|
+
* Create a color object with RGBA values, white by default
|
|
455
528
|
* @param {Number} [r=1] - red
|
|
456
529
|
* @param {Number} [g=1] - green
|
|
457
530
|
* @param {Number} [b=1] - blue
|
|
@@ -462,7 +535,7 @@ class Vector2
|
|
|
462
535
|
function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
463
536
|
|
|
464
537
|
/**
|
|
465
|
-
* Create a color object with HSLA values
|
|
538
|
+
* Create a color object with HSLA values, white by default
|
|
466
539
|
* @param {Number} [h=0] - hue
|
|
467
540
|
* @param {Number} [s=0] - saturation
|
|
468
541
|
* @param {Number} [l=1] - lightness
|
|
@@ -472,14 +545,22 @@ function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
|
472
545
|
*/
|
|
473
546
|
function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
474
547
|
|
|
548
|
+
/**
|
|
549
|
+
* Check if object is a valid Color
|
|
550
|
+
* @param {any} c
|
|
551
|
+
* @return {Boolean}
|
|
552
|
+
* @memberof Utilities
|
|
553
|
+
*/
|
|
554
|
+
function isColor(c) { return c instanceof Color; }
|
|
555
|
+
|
|
475
556
|
/**
|
|
476
557
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
477
558
|
* @example
|
|
478
559
|
* let a = new Color; // white
|
|
479
560
|
* let b = new Color(1, 0, 0); // red
|
|
480
561
|
* let c = new Color(0, 0, 0, 0); // transparent black
|
|
481
|
-
* let d =
|
|
482
|
-
* let e =
|
|
562
|
+
* let d = rgb(0, 0, 1); // blue using rgb color
|
|
563
|
+
* let e = hsl(.3, 1, .5); // green using hsl color
|
|
483
564
|
*/
|
|
484
565
|
class Color
|
|
485
566
|
{
|
|
@@ -507,22 +588,38 @@ class Color
|
|
|
507
588
|
/** Returns a copy of this color plus the color passed in
|
|
508
589
|
* @param {Color} c - other color
|
|
509
590
|
* @return {Color} */
|
|
510
|
-
add(c)
|
|
591
|
+
add(c)
|
|
592
|
+
{
|
|
593
|
+
ASSERT(isColor(c));
|
|
594
|
+
return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a);
|
|
595
|
+
}
|
|
511
596
|
|
|
512
597
|
/** Returns a copy of this color minus the color passed in
|
|
513
598
|
* @param {Color} c - other color
|
|
514
599
|
* @return {Color} */
|
|
515
|
-
subtract(c)
|
|
600
|
+
subtract(c)
|
|
601
|
+
{
|
|
602
|
+
ASSERT(isColor(c));
|
|
603
|
+
return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a);
|
|
604
|
+
}
|
|
516
605
|
|
|
517
606
|
/** Returns a copy of this color times the color passed in
|
|
518
607
|
* @param {Color} c - other color
|
|
519
608
|
* @return {Color} */
|
|
520
|
-
multiply(c)
|
|
609
|
+
multiply(c)
|
|
610
|
+
{
|
|
611
|
+
ASSERT(isColor(c));
|
|
612
|
+
return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a);
|
|
613
|
+
}
|
|
521
614
|
|
|
522
615
|
/** Returns a copy of this color divided by the color passed in
|
|
523
616
|
* @param {Color} c - other color
|
|
524
617
|
* @return {Color} */
|
|
525
|
-
divide(c)
|
|
618
|
+
divide(c)
|
|
619
|
+
{
|
|
620
|
+
ASSERT(isColor(c));
|
|
621
|
+
return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a);
|
|
622
|
+
}
|
|
526
623
|
|
|
527
624
|
/** Returns a copy of this color scaled by the value passed in, alpha can be scaled separately
|
|
528
625
|
* @param {Number} scale
|
|
@@ -539,7 +636,11 @@ class Color
|
|
|
539
636
|
* @param {Color} c - other color
|
|
540
637
|
* @param {Number} percent
|
|
541
638
|
* @return {Color} */
|
|
542
|
-
lerp(c, percent)
|
|
639
|
+
lerp(c, percent)
|
|
640
|
+
{
|
|
641
|
+
ASSERT(isColor(c));
|
|
642
|
+
return this.add(c.subtract(this).scale(clamp(percent)));
|
|
643
|
+
}
|
|
543
644
|
|
|
544
645
|
/** Sets this color given a hue, saturation, lightness, and alpha
|
|
545
646
|
* @param {Number} [h] - hue
|
|
@@ -776,7 +877,7 @@ let tileSizeDefault = vec2(16);
|
|
|
776
877
|
* @type {Number}
|
|
777
878
|
* @default
|
|
778
879
|
* @memberof Settings */
|
|
779
|
-
let tileFixBleedScale = .
|
|
880
|
+
let tileFixBleedScale = .1;
|
|
780
881
|
|
|
781
882
|
///////////////////////////////////////////////////////////////////////////////
|
|
782
883
|
// Object settings
|
|
@@ -787,7 +888,7 @@ let tileFixBleedScale = .3;
|
|
|
787
888
|
* @memberof Settings */
|
|
788
889
|
let enablePhysicsSolver = true;
|
|
789
890
|
|
|
790
|
-
/** Default object mass for
|
|
891
|
+
/** Default object mass for collision calcuations (how heavy objects are)
|
|
791
892
|
* @type {Number}
|
|
792
893
|
* @default
|
|
793
894
|
* @memberof Settings */
|
|
@@ -870,7 +971,7 @@ let touchGamepadEnable = false;
|
|
|
870
971
|
* @memberof Settings */
|
|
871
972
|
let touchGamepadAnalog = true;
|
|
872
973
|
|
|
873
|
-
/** Size of
|
|
974
|
+
/** Size of virtual gamepad for touch devices in pixels
|
|
874
975
|
* @type {Number}
|
|
875
976
|
* @default
|
|
876
977
|
* @memberof Settings */
|
|
@@ -1157,7 +1258,7 @@ function setDebugKey(key) { debugKey = key; }
|
|
|
1157
1258
|
* - Automatically adds self to object list
|
|
1158
1259
|
* - Will be updated and rendered each frame
|
|
1159
1260
|
* - Renders as a sprite from a tilesheet by default
|
|
1160
|
-
* - Can have color and
|
|
1261
|
+
* - Can have color and additive color applied
|
|
1161
1262
|
* - 2D Physics and collision system
|
|
1162
1263
|
* - Sorted by renderOrder
|
|
1163
1264
|
* - Objects can have children attached
|
|
@@ -1436,7 +1537,7 @@ class EngineObject
|
|
|
1436
1537
|
}
|
|
1437
1538
|
|
|
1438
1539
|
/** Destroy this object, destroy it's children, detach it's parent, and mark it for removal */
|
|
1439
|
-
destroy()
|
|
1540
|
+
destroy()
|
|
1440
1541
|
{
|
|
1441
1542
|
if (this.destroyed)
|
|
1442
1543
|
return;
|
|
@@ -1625,13 +1726,9 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
|
1625
1726
|
if (typeof pos === 'number')
|
|
1626
1727
|
{
|
|
1627
1728
|
const textureInfo = textureInfos[textureIndex];
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
1632
|
-
}
|
|
1633
|
-
else
|
|
1634
|
-
pos = vec2();
|
|
1729
|
+
ASSERT(textureInfo, 'Texture not loaded');
|
|
1730
|
+
const cols = textureInfo.size.x / size.x |0;
|
|
1731
|
+
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
1635
1732
|
}
|
|
1636
1733
|
|
|
1637
1734
|
// return a tile info object
|
|
@@ -1720,6 +1817,11 @@ function worldToScreen(worldPos)
|
|
|
1720
1817
|
);
|
|
1721
1818
|
}
|
|
1722
1819
|
|
|
1820
|
+
/** Get the camera's visible area in world space
|
|
1821
|
+
* @return {Vector2}
|
|
1822
|
+
* @memberof Draw */
|
|
1823
|
+
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
1824
|
+
|
|
1723
1825
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
1724
1826
|
* @param {Vector2} pos - Center of the tile in world space
|
|
1725
1827
|
* @param {Vector2} [size=(1,1)] - Size of the tile in world space
|
|
@@ -2354,9 +2456,9 @@ if (isTouchDevice)
|
|
|
2354
2456
|
// handle all touch events the same way
|
|
2355
2457
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2356
2458
|
{
|
|
2357
|
-
// fix stalled audio
|
|
2358
|
-
if (soundEnable)
|
|
2359
|
-
|
|
2459
|
+
// fix stalled audio requiring user interaction
|
|
2460
|
+
if (soundEnable && audioContext && audioContext.state != 'running')
|
|
2461
|
+
zzfx(0);
|
|
2360
2462
|
|
|
2361
2463
|
// check if touching and pass to mouse events
|
|
2362
2464
|
const touching = e.touches.length;
|
|
@@ -2397,7 +2499,7 @@ function createTouchGamepad()
|
|
|
2397
2499
|
touchGamepadStick = vec2();
|
|
2398
2500
|
|
|
2399
2501
|
const touchHandler = ontouchstart;
|
|
2400
|
-
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2502
|
+
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2401
2503
|
{
|
|
2402
2504
|
// clear touch gamepad input
|
|
2403
2505
|
touchGamepadStick = vec2();
|
|
@@ -2502,7 +2604,7 @@ function touchGamepadRender()
|
|
|
2502
2604
|
const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
2503
2605
|
for (let i=4; i--;)
|
|
2504
2606
|
{
|
|
2505
|
-
const pos = rightCenter.add(vec2().
|
|
2607
|
+
const pos = rightCenter.add(vec2().setDirection(i, touchGamepadSize/2));
|
|
2506
2608
|
overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
|
|
2507
2609
|
overlayContext.beginPath();
|
|
2508
2610
|
overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
|
|
@@ -2527,7 +2629,7 @@ function touchGamepadRender()
|
|
|
2527
2629
|
|
|
2528
2630
|
|
|
2529
2631
|
/**
|
|
2530
|
-
* Sound Object - Stores a
|
|
2632
|
+
* Sound Object - Stores a sound for later use and can be played positionally
|
|
2531
2633
|
*
|
|
2532
2634
|
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
2533
2635
|
* @example
|
|
@@ -2542,7 +2644,7 @@ class Sound
|
|
|
2542
2644
|
/** Create a sound object and cache the zzfx samples for later use
|
|
2543
2645
|
* @param {Array} zzfxSound - Array of zzfx parameters, ex. [.5,.5]
|
|
2544
2646
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
2545
|
-
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
2647
|
+
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
2546
2648
|
*/
|
|
2547
2649
|
constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
|
|
2548
2650
|
{
|
|
@@ -2661,22 +2763,19 @@ class SoundWave extends Sound
|
|
|
2661
2763
|
this.randomness = randomness;
|
|
2662
2764
|
|
|
2663
2765
|
if (!soundEnable) return;
|
|
2664
|
-
if (!soundDecoderContext)
|
|
2665
|
-
soundDecoderContext = new AudioContext;
|
|
2666
2766
|
|
|
2667
2767
|
fetch(filename)
|
|
2668
2768
|
.then(response => response.arrayBuffer())
|
|
2669
|
-
.then(arrayBuffer =>
|
|
2769
|
+
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
|
|
2670
2770
|
.then(audioBuffer =>
|
|
2671
2771
|
{
|
|
2672
2772
|
this.sampleChannels = [];
|
|
2673
2773
|
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
2674
|
-
this.sampleChannels[i] = audioBuffer.getChannelData(i);
|
|
2774
|
+
this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
|
|
2675
2775
|
this.sampleRate = audioBuffer.sampleRate;
|
|
2676
2776
|
});
|
|
2677
2777
|
}
|
|
2678
2778
|
}
|
|
2679
|
-
let soundDecoderContext; // audio context used only to decode audio files
|
|
2680
2779
|
|
|
2681
2780
|
/**
|
|
2682
2781
|
* Music Object - Stores a zzfx music track for later use
|
|
@@ -2725,24 +2824,24 @@ class Music extends Sound
|
|
|
2725
2824
|
|
|
2726
2825
|
/** Play the music
|
|
2727
2826
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
2728
|
-
* @param {Boolean} [loop
|
|
2827
|
+
* @param {Boolean} [loop] - True if the music should loop
|
|
2729
2828
|
* @return {AudioBufferSourceNode} - The audio source node
|
|
2730
2829
|
*/
|
|
2731
|
-
playMusic(volume, loop
|
|
2830
|
+
playMusic(volume, loop=false)
|
|
2732
2831
|
{ return super.play(undefined, volume, 1, 1, loop); }
|
|
2733
2832
|
}
|
|
2734
2833
|
|
|
2735
2834
|
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
2736
|
-
* @param {String}
|
|
2835
|
+
* @param {String} filename - Location of sound file to play
|
|
2737
2836
|
* @param {Number} [volume] - How much to scale volume by
|
|
2738
2837
|
* @param {Boolean} [loop] - True if the music should loop
|
|
2739
2838
|
* @return {HTMLAudioElement} - The audio element for this sound
|
|
2740
2839
|
* @memberof Audio */
|
|
2741
|
-
function playAudioFile(
|
|
2840
|
+
function playAudioFile(filename, volume=1, loop=false)
|
|
2742
2841
|
{
|
|
2743
2842
|
if (!soundEnable) return;
|
|
2744
2843
|
|
|
2745
|
-
const audio = new Audio(
|
|
2844
|
+
const audio = new Audio(filename);
|
|
2746
2845
|
audio.volume = soundVolume * volume;
|
|
2747
2846
|
audio.loop = loop;
|
|
2748
2847
|
audio.play();
|
|
@@ -2790,8 +2889,14 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
2790
2889
|
///////////////////////////////////////////////////////////////////////////////
|
|
2791
2890
|
|
|
2792
2891
|
/** Audio context used by the engine
|
|
2892
|
+
* @type {AudioContext}
|
|
2793
2893
|
* @memberof Audio */
|
|
2794
|
-
let audioContext;
|
|
2894
|
+
let audioContext = new AudioContext;
|
|
2895
|
+
|
|
2896
|
+
/** Keep track if audio was suspended when last sound was played
|
|
2897
|
+
* @type {Boolean}
|
|
2898
|
+
* @memberof Audio */
|
|
2899
|
+
let audioSuspended = false;
|
|
2795
2900
|
|
|
2796
2901
|
/** Play cached audio samples with given settings
|
|
2797
2902
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
@@ -2806,16 +2911,16 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
2806
2911
|
{
|
|
2807
2912
|
if (!soundEnable) return;
|
|
2808
2913
|
|
|
2809
|
-
// create audio context if needed
|
|
2810
|
-
if (!audioContext)
|
|
2811
|
-
audioContext = new AudioContext;
|
|
2812
|
-
|
|
2813
2914
|
// prevent sounds from building up if they can't be played
|
|
2814
|
-
|
|
2915
|
+
const audioWasSuspended = audioSuspended;
|
|
2916
|
+
if (audioSuspended = audioContext.state != 'running')
|
|
2815
2917
|
{
|
|
2816
2918
|
// fix stalled audio
|
|
2817
2919
|
audioContext.resume();
|
|
2818
|
-
|
|
2920
|
+
|
|
2921
|
+
// prevent suspended sounds from building up
|
|
2922
|
+
if (audioWasSuspended)
|
|
2923
|
+
return;
|
|
2819
2924
|
}
|
|
2820
2925
|
|
|
2821
2926
|
// create buffer and source
|
|
@@ -3083,7 +3188,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
3083
3188
|
/**
|
|
3084
3189
|
* LittleJS Tile Layer System
|
|
3085
3190
|
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
3086
|
-
* -
|
|
3191
|
+
* - Unlimited numbers of layers, allocates canvases as needed
|
|
3087
3192
|
* - Interfaces with EngineObject for collision
|
|
3088
3193
|
* - Collision layer is separate from visible layers
|
|
3089
3194
|
* - It is recommended to have a visible layer that matches the collision
|
|
@@ -3135,7 +3240,7 @@ function getTileCollisionData(pos)
|
|
|
3135
3240
|
|
|
3136
3241
|
/** Check if collision with another object should occur
|
|
3137
3242
|
* @param {Vector2} pos
|
|
3138
|
-
* @param {Vector2} [size=(
|
|
3243
|
+
* @param {Vector2} [size=(0,0)]
|
|
3139
3244
|
* @param {EngineObject} [object]
|
|
3140
3245
|
* @return {Boolean}
|
|
3141
3246
|
* @memberof TileCollision */
|
|
@@ -3220,7 +3325,7 @@ class TileLayerData
|
|
|
3220
3325
|
* @param {Number} [direction] - Integer direction of tile, in 90 degree increments
|
|
3221
3326
|
* @param {Boolean} [mirror] - If the tile should be mirrored along the x axis
|
|
3222
3327
|
* @param {Color} [color] - Color of the tile */
|
|
3223
|
-
constructor(tile, direction=0, mirror=false, color=new Color
|
|
3328
|
+
constructor(tile, direction=0, mirror=false, color=new Color)
|
|
3224
3329
|
{
|
|
3225
3330
|
/** @property {Number} - The tile to use, untextured if undefined */
|
|
3226
3331
|
this.tile = tile;
|
|
@@ -3460,12 +3565,12 @@ class TileLayer extends EngineObject
|
|
|
3460
3565
|
* @example
|
|
3461
3566
|
* // create a particle emitter
|
|
3462
3567
|
* let pos = vec2(2,3);
|
|
3463
|
-
* let
|
|
3568
|
+
* let particleEmitter = new ParticleEmitter
|
|
3464
3569
|
* (
|
|
3465
|
-
* pos, 0, 1, 0, 500, PI,
|
|
3466
|
-
* tile(0, 16),
|
|
3467
|
-
*
|
|
3468
|
-
*
|
|
3570
|
+
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
3571
|
+
* tile(0, 16), // tileInfo
|
|
3572
|
+
* rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
|
|
3573
|
+
* rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
|
|
3469
3574
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
3470
3575
|
* .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
3471
3576
|
* .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
|
|
@@ -3652,16 +3757,17 @@ class ParticleEmitter extends EngineObject
|
|
|
3652
3757
|
|
|
3653
3758
|
// build particle
|
|
3654
3759
|
const particle = new Particle(pos, this.tileInfo, angle, colorStart, colorEnd, particleTime, sizeStart, sizeEnd, this.fadeRate, this.additive, this.trailScale, this.localSpace && this, this.particleDestroyCallback);
|
|
3655
|
-
particle.velocity
|
|
3656
|
-
particle.
|
|
3657
|
-
particle.
|
|
3658
|
-
particle.
|
|
3659
|
-
particle.
|
|
3660
|
-
particle.
|
|
3661
|
-
particle.
|
|
3662
|
-
particle.
|
|
3663
|
-
particle.
|
|
3664
|
-
particle.
|
|
3760
|
+
particle.velocity = vec2().setAngle(velocityAngle, speed);
|
|
3761
|
+
particle.angleVelocity = angleSpeed;
|
|
3762
|
+
particle.fadeRate = this.fadeRate;
|
|
3763
|
+
particle.damping = this.damping;
|
|
3764
|
+
particle.angleDamping = this.angleDamping;
|
|
3765
|
+
particle.elasticity = this.elasticity;
|
|
3766
|
+
particle.friction = this.friction;
|
|
3767
|
+
particle.gravityScale = this.gravityScale;
|
|
3768
|
+
particle.collideTiles = this.collideTiles;
|
|
3769
|
+
particle.renderOrder = this.renderOrder;
|
|
3770
|
+
particle.mirror = !!randInt(2);
|
|
3665
3771
|
|
|
3666
3772
|
// call particle create callaback
|
|
3667
3773
|
this.particleCreateCallback && this.particleCreateCallback(particle);
|
|
@@ -3872,8 +3978,8 @@ class Medal
|
|
|
3872
3978
|
// draw containing rect and clip to that region
|
|
3873
3979
|
context.save();
|
|
3874
3980
|
context.beginPath();
|
|
3875
|
-
context.fillStyle =
|
|
3876
|
-
context.strokeStyle =
|
|
3981
|
+
context.fillStyle = new Color(.9,.9,.9).toString();
|
|
3982
|
+
context.strokeStyle = new Color(0,0,0).toString();
|
|
3877
3983
|
context.lineWidth = 3;
|
|
3878
3984
|
context.rect(x, y, width, medalDisplaySize.y);
|
|
3879
3985
|
context.fill();
|
|
@@ -4052,7 +4158,7 @@ class Newgrounds
|
|
|
4052
4158
|
}
|
|
4053
4159
|
|
|
4054
4160
|
// build the input object
|
|
4055
|
-
const input =
|
|
4161
|
+
const input =
|
|
4056
4162
|
{
|
|
4057
4163
|
'app_id': this.app_id,
|
|
4058
4164
|
'session_id': this.session_id,
|
|
@@ -4267,8 +4373,6 @@ function glCreateTexture(image)
|
|
|
4267
4373
|
const filter = canvasPixelated ? gl_NEAREST : gl_LINEAR;
|
|
4268
4374
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
|
|
4269
4375
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
|
|
4270
|
-
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE);
|
|
4271
|
-
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE);
|
|
4272
4376
|
|
|
4273
4377
|
return texture;
|
|
4274
4378
|
}
|
|
@@ -4325,7 +4429,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4325
4429
|
ASSERT(typeof rgba == 'number' && typeof rgbaAdditive == 'number', 'invalid color');
|
|
4326
4430
|
|
|
4327
4431
|
// flush if there is not enough room or if different blend mode
|
|
4328
|
-
if (glInstanceCount >= gl_MAX_INSTANCES
|
|
4432
|
+
if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
|
|
4329
4433
|
glFlush();
|
|
4330
4434
|
|
|
4331
4435
|
let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
|
|
@@ -4346,7 +4450,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4346
4450
|
///////////////////////////////////////////////////////////////////////////////
|
|
4347
4451
|
// post processing - can be enabled to pass other canvases through a final shader
|
|
4348
4452
|
|
|
4349
|
-
let glPostShader,
|
|
4453
|
+
let glPostShader, glPostTexture, glPostIncludeOverlay;
|
|
4350
4454
|
|
|
4351
4455
|
/** Set up a post processing shader
|
|
4352
4456
|
* @param {String} shaderCode
|
|
@@ -4382,7 +4486,6 @@ function glInitPostProcess(shaderCode, includeOverlay=false)
|
|
|
4382
4486
|
);
|
|
4383
4487
|
|
|
4384
4488
|
// create buffer and texture
|
|
4385
|
-
glPostArrayBuffer = glContext.createBuffer();
|
|
4386
4489
|
glPostTexture = glCreateTexture(undefined);
|
|
4387
4490
|
glPostIncludeOverlay = includeOverlay;
|
|
4388
4491
|
|
|
@@ -4454,10 +4557,7 @@ gl_NEAREST = 9728,
|
|
|
4454
4557
|
gl_LINEAR = 9729,
|
|
4455
4558
|
gl_TEXTURE_MAG_FILTER = 10240,
|
|
4456
4559
|
gl_TEXTURE_MIN_FILTER = 10241,
|
|
4457
|
-
gl_TEXTURE_WRAP_S = 10242,
|
|
4458
|
-
gl_TEXTURE_WRAP_T = 10243,
|
|
4459
4560
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4460
|
-
gl_CLAMP_TO_EDGE = 33071,
|
|
4461
4561
|
gl_TEXTURE0 = 33984,
|
|
4462
4562
|
gl_ARRAY_BUFFER = 34962,
|
|
4463
4563
|
gl_STATIC_DRAW = 35044,
|
|
@@ -4474,7 +4574,7 @@ gl_MAX_INSTANCES = 1e4,
|
|
|
4474
4574
|
gl_INSTANCE_BYTE_STRIDE = gl_INDICIES_PER_INSTANCE * 4, // 11 * 4
|
|
4475
4575
|
gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
|
|
4476
4576
|
/**
|
|
4477
|
-
* LittleJS - The Tiny JavaScript Game Engine
|
|
4577
|
+
* LittleJS - The Tiny Fast JavaScript Game Engine
|
|
4478
4578
|
* MIT License - Copyright 2021 Frank Force
|
|
4479
4579
|
*
|
|
4480
4580
|
* Engine Features
|
|
@@ -4505,9 +4605,9 @@ const engineName = 'LittleJS';
|
|
|
4505
4605
|
* @type {String}
|
|
4506
4606
|
* @default
|
|
4507
4607
|
* @memberof Engine */
|
|
4508
|
-
const engineVersion = '1.9.
|
|
4608
|
+
const engineVersion = '1.9.3';
|
|
4509
4609
|
|
|
4510
|
-
/** Frames per second to update
|
|
4610
|
+
/** Frames per second to update
|
|
4511
4611
|
* @type {Number}
|
|
4512
4612
|
* @default
|
|
4513
4613
|
* @memberof Engine */
|
|
@@ -4524,7 +4624,7 @@ const timeDelta = 1/frameRate;
|
|
|
4524
4624
|
* @memberof Engine */
|
|
4525
4625
|
let engineObjects = [];
|
|
4526
4626
|
|
|
4527
|
-
/** Array
|
|
4627
|
+
/** Array with only objects set to collide with other objects this frame (for optimization)
|
|
4528
4628
|
* @type {Array}
|
|
4529
4629
|
* @memberof Engine */
|
|
4530
4630
|
let engineObjectsCollide = [];
|
|
@@ -4534,7 +4634,7 @@ let engineObjectsCollide = [];
|
|
|
4534
4634
|
* @memberof Engine */
|
|
4535
4635
|
let frame = 0;
|
|
4536
4636
|
|
|
4537
|
-
/** Current engine time since start in seconds
|
|
4637
|
+
/** Current engine time since start in seconds
|
|
4538
4638
|
* @type {Number}
|
|
4539
4639
|
* @memberof Engine */
|
|
4540
4640
|
let time = 0;
|
|
@@ -4560,12 +4660,12 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
4560
4660
|
|
|
4561
4661
|
///////////////////////////////////////////////////////////////////////////////
|
|
4562
4662
|
|
|
4563
|
-
/**
|
|
4564
|
-
* @param {Function} gameInit
|
|
4565
|
-
* @param {Function} gameUpdate
|
|
4566
|
-
* @param {Function} gameUpdatePost
|
|
4567
|
-
* @param {Function} gameRender
|
|
4568
|
-
* @param {Function} gameRenderPost
|
|
4663
|
+
/** Startup LittleJS engine with your callback functions
|
|
4664
|
+
* @param {Function} gameInit - Called once after the engine starts up, setup the game
|
|
4665
|
+
* @param {Function} gameUpdate - Called every frame at 60 frames per second, handle input and update the game state
|
|
4666
|
+
* @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
|
|
4667
|
+
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
4668
|
+
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
4569
4669
|
* @param {Array} [imageSources=['tiles.png']] - Image to load
|
|
4570
4670
|
* @memberof Engine */
|
|
4571
4671
|
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
|
|
@@ -4588,32 +4688,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4588
4688
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
4589
4689
|
if (!debugSpeedUp)
|
|
4590
4690
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
|
|
4591
|
-
|
|
4592
|
-
if (canvasFixedSize.x)
|
|
4593
|
-
{
|
|
4594
|
-
// clear canvas and set fixed size
|
|
4595
|
-
mainCanvas.width = canvasFixedSize.x;
|
|
4596
|
-
mainCanvas.height = canvasFixedSize.y;
|
|
4597
|
-
|
|
4598
|
-
// fit to window by adding space on top or bottom if necessary
|
|
4599
|
-
const aspect = innerWidth / innerHeight;
|
|
4600
|
-
const fixedAspect = mainCanvas.width / mainCanvas.height;
|
|
4601
|
-
(glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
|
|
4602
|
-
(glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
|
|
4603
|
-
}
|
|
4604
|
-
else
|
|
4605
|
-
{
|
|
4606
|
-
// clear canvas and set size to same as window
|
|
4607
|
-
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
4608
|
-
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
4609
|
-
}
|
|
4610
|
-
|
|
4611
|
-
// clear overlay canvas and set size
|
|
4612
|
-
overlayCanvas.width = mainCanvas.width;
|
|
4613
|
-
overlayCanvas.height = mainCanvas.height;
|
|
4614
|
-
|
|
4615
|
-
// save canvas size
|
|
4616
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
4691
|
+
updateCanvas();
|
|
4617
4692
|
|
|
4618
4693
|
if (paused)
|
|
4619
4694
|
{
|
|
@@ -4687,6 +4762,35 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4687
4762
|
requestAnimationFrame(engineUpdate);
|
|
4688
4763
|
}
|
|
4689
4764
|
|
|
4765
|
+
function updateCanvas()
|
|
4766
|
+
{
|
|
4767
|
+
if (canvasFixedSize.x)
|
|
4768
|
+
{
|
|
4769
|
+
// clear canvas and set fixed size
|
|
4770
|
+
mainCanvas.width = canvasFixedSize.x;
|
|
4771
|
+
mainCanvas.height = canvasFixedSize.y;
|
|
4772
|
+
|
|
4773
|
+
// fit to window by adding space on top or bottom if necessary
|
|
4774
|
+
const aspect = innerWidth / innerHeight;
|
|
4775
|
+
const fixedAspect = mainCanvas.width / mainCanvas.height;
|
|
4776
|
+
(glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
|
|
4777
|
+
(glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
|
|
4778
|
+
}
|
|
4779
|
+
else
|
|
4780
|
+
{
|
|
4781
|
+
// clear canvas and set size to same as window
|
|
4782
|
+
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
4783
|
+
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
4784
|
+
}
|
|
4785
|
+
|
|
4786
|
+
// clear overlay canvas and set size
|
|
4787
|
+
overlayCanvas.width = mainCanvas.width;
|
|
4788
|
+
overlayCanvas.height = mainCanvas.height;
|
|
4789
|
+
|
|
4790
|
+
// save canvas size
|
|
4791
|
+
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
4792
|
+
}
|
|
4793
|
+
|
|
4690
4794
|
// setup html
|
|
4691
4795
|
const styleBody =
|
|
4692
4796
|
'margin:0;overflow:hidden;' + // fill the window
|
|
@@ -4711,6 +4815,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4711
4815
|
const styleCanvas = 'position:absolute;' + // position
|
|
4712
4816
|
'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
|
|
4713
4817
|
(glCanvas||mainCanvas).style.cssText = mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
4818
|
+
updateCanvas();
|
|
4714
4819
|
|
|
4715
4820
|
// create promises for loading images
|
|
4716
4821
|
const promises = imageSources.map((src, textureIndex)=>
|
|
@@ -4907,9 +5012,9 @@ function drawEngineSplashScreen(t)
|
|
|
4907
5012
|
|
|
4908
5013
|
// big stack
|
|
4909
5014
|
rect(50,20,10,-10,color(0,1));
|
|
4910
|
-
rect(50,20,6,-10,color(0,2));
|
|
4911
|
-
rect(50,20,3,-10,color(0,3));
|
|
4912
|
-
rect(50,
|
|
5015
|
+
rect(50,20,6.5,-10,color(0,2));
|
|
5016
|
+
rect(50,20,3.5,-10,color(0,3));
|
|
5017
|
+
rect(50,20,10,-10);
|
|
4913
5018
|
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
4914
5019
|
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
4915
5020
|
circle(55,2,11.4,.5,PI-.5);
|
|
@@ -4928,7 +5033,7 @@ function drawEngineSplashScreen(t)
|
|
|
4928
5033
|
|
|
4929
5034
|
// engine outline
|
|
4930
5035
|
circle(36,30,10,PI/2,PI*3/2);
|
|
4931
|
-
circle(
|
|
5036
|
+
circle(48,30,10,PI/2,PI*3/2);
|
|
4932
5037
|
circle(60,30,10);
|
|
4933
5038
|
line(36,20,60,20);
|
|
4934
5039
|
|