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
|
@@ -56,11 +56,15 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
56
56
|
///////////////////////////////////////////////////////////////////////////////
|
|
57
57
|
// Debug helper functions
|
|
58
58
|
|
|
59
|
-
/** Asserts if the
|
|
59
|
+
/** Asserts if the expression is false, does not do anything in release builds
|
|
60
60
|
* @param {Boolean} assert
|
|
61
|
-
* @param {Object} output
|
|
61
|
+
* @param {Object} [output]
|
|
62
62
|
* @memberof Debug */
|
|
63
|
-
function ASSERT(assert, output)
|
|
63
|
+
function ASSERT(assert, output)
|
|
64
|
+
{
|
|
65
|
+
if (enableAsserts)
|
|
66
|
+
output ? console.assert(assert, output) : console.assert(assert);
|
|
67
|
+
}
|
|
64
68
|
|
|
65
69
|
/** Draw a debug rectangle in world space
|
|
66
70
|
* @param {Vector2} pos
|
|
@@ -449,7 +453,7 @@ function min(valueA, valueB) { return Math.min(valueA, valueB); }
|
|
|
449
453
|
* @memberof Utilities */
|
|
450
454
|
function max(valueA, valueB) { return Math.max(valueA, valueB); }
|
|
451
455
|
|
|
452
|
-
/** Returns the sign of value passed in
|
|
456
|
+
/** Returns the sign of value passed in
|
|
453
457
|
* @param {Number} value
|
|
454
458
|
* @return {Number}
|
|
455
459
|
* @memberof Utilities */
|
|
@@ -496,7 +500,7 @@ function lerp(percent, valueA, valueB) { return valueA + clamp(percent) * (value
|
|
|
496
500
|
function distanceWrap(valueA, valueB, wrapSize=1)
|
|
497
501
|
{ const d = (valueA - valueB) % wrapSize; return d*2 % wrapSize - d; }
|
|
498
502
|
|
|
499
|
-
/** Linearly interpolates between values passed in with
|
|
503
|
+
/** Linearly interpolates between values passed in with wrapping
|
|
500
504
|
* @param {Number} percent
|
|
501
505
|
* @param {Number} valueA
|
|
502
506
|
* @param {Number} valueB
|
|
@@ -513,7 +517,7 @@ function lerpWrap(percent, valueA, valueB, wrapSize=1)
|
|
|
513
517
|
* @memberof Utilities */
|
|
514
518
|
function distanceAngle(angleA, angleB) { return distanceWrap(angleA, angleB, 2*PI); }
|
|
515
519
|
|
|
516
|
-
/** Linearly interpolates between the angles passed in with
|
|
520
|
+
/** Linearly interpolates between the angles passed in with wrapping
|
|
517
521
|
* @param {Number} percent
|
|
518
522
|
* @param {Number} angleA
|
|
519
523
|
* @param {Number} angleB
|
|
@@ -534,13 +538,13 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
534
538
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
535
539
|
|
|
536
540
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
537
|
-
* @param {Vector2} pointA
|
|
538
|
-
* @param {Vector2} sizeA
|
|
539
|
-
* @param {Vector2} pointB
|
|
540
|
-
* @param {Vector2} sizeB - Size of box B
|
|
541
|
-
* @return {Boolean}
|
|
541
|
+
* @param {Vector2} pointA - Center of box A
|
|
542
|
+
* @param {Vector2} sizeA - Size of box A
|
|
543
|
+
* @param {Vector2} pointB - Center of box B
|
|
544
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
545
|
+
* @return {Boolean} - True if overlapping
|
|
542
546
|
* @memberof Utilities */
|
|
543
|
-
function isOverlapping(pointA, sizeA, pointB, sizeB)
|
|
547
|
+
function isOverlapping(pointA, sizeA, pointB, sizeB=vec2())
|
|
544
548
|
{
|
|
545
549
|
return abs(pointA.x - pointB.x)*2 < sizeA.x + sizeB.x
|
|
546
550
|
&& abs(pointA.y - pointB.y)*2 < sizeA.y + sizeB.y;
|
|
@@ -600,8 +604,8 @@ function randInCircle(radius=1, minRadius=0)
|
|
|
600
604
|
{ return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
|
|
601
605
|
|
|
602
606
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
603
|
-
* @param {Color} [colorA=
|
|
604
|
-
* @param {Color} [colorB=
|
|
607
|
+
* @param {Color} [colorA=(1,1,1,1)]
|
|
608
|
+
* @param {Color} [colorB=(0,0,0,1)]
|
|
605
609
|
* @param {Boolean} [linear]
|
|
606
610
|
* @return {Color}
|
|
607
611
|
* @memberof Random */
|
|
@@ -672,7 +676,11 @@ class RandomGenerator
|
|
|
672
676
|
* @memberof Utilities
|
|
673
677
|
*/
|
|
674
678
|
function vec2(x=0, y)
|
|
675
|
-
{
|
|
679
|
+
{
|
|
680
|
+
return typeof x === 'number' ?
|
|
681
|
+
new Vector2(x, y == undefined? x : y) :
|
|
682
|
+
new Vector2(x.x, x.y);
|
|
683
|
+
}
|
|
676
684
|
|
|
677
685
|
/**
|
|
678
686
|
* Check if object is a valid Vector2
|
|
@@ -680,7 +688,7 @@ function vec2(x=0, y)
|
|
|
680
688
|
* @return {Boolean}
|
|
681
689
|
* @memberof Utilities
|
|
682
690
|
*/
|
|
683
|
-
function isVector2(v) { return
|
|
691
|
+
function isVector2(v) { return v instanceof Vector2; }
|
|
684
692
|
|
|
685
693
|
/**
|
|
686
694
|
* 2D Vector object with vector math library
|
|
@@ -711,27 +719,47 @@ class Vector2
|
|
|
711
719
|
/** Returns a copy of this vector plus the vector passed in
|
|
712
720
|
* @param {Vector2} v - other vector
|
|
713
721
|
* @return {Vector2} */
|
|
714
|
-
add(v)
|
|
722
|
+
add(v)
|
|
723
|
+
{
|
|
724
|
+
ASSERT(isVector2(v));
|
|
725
|
+
return new Vector2(this.x + v.x, this.y + v.y);
|
|
726
|
+
}
|
|
715
727
|
|
|
716
728
|
/** Returns a copy of this vector minus the vector passed in
|
|
717
729
|
* @param {Vector2} v - other vector
|
|
718
730
|
* @return {Vector2} */
|
|
719
|
-
subtract(v)
|
|
731
|
+
subtract(v)
|
|
732
|
+
{
|
|
733
|
+
ASSERT(isVector2(v));
|
|
734
|
+
return new Vector2(this.x - v.x, this.y - v.y);
|
|
735
|
+
}
|
|
720
736
|
|
|
721
737
|
/** Returns a copy of this vector times the vector passed in
|
|
722
738
|
* @param {Vector2} v - other vector
|
|
723
739
|
* @return {Vector2} */
|
|
724
|
-
multiply(v)
|
|
740
|
+
multiply(v)
|
|
741
|
+
{
|
|
742
|
+
ASSERT(isVector2(v));
|
|
743
|
+
return new Vector2(this.x * v.x, this.y * v.y);
|
|
744
|
+
}
|
|
725
745
|
|
|
726
746
|
/** Returns a copy of this vector divided by the vector passed in
|
|
727
747
|
* @param {Vector2} v - other vector
|
|
728
748
|
* @return {Vector2} */
|
|
729
|
-
divide(v)
|
|
749
|
+
divide(v)
|
|
750
|
+
{
|
|
751
|
+
ASSERT(isVector2(v));
|
|
752
|
+
return new Vector2(this.x / v.x, this.y / v.y);
|
|
753
|
+
}
|
|
730
754
|
|
|
731
755
|
/** Returns a copy of this vector scaled by the vector passed in
|
|
732
756
|
* @param {Number} s - scale
|
|
733
757
|
* @return {Vector2} */
|
|
734
|
-
scale(s)
|
|
758
|
+
scale(s)
|
|
759
|
+
{
|
|
760
|
+
ASSERT(!isVector2(s));
|
|
761
|
+
return new Vector2(this.x * s, this.y * s);
|
|
762
|
+
}
|
|
735
763
|
|
|
736
764
|
/** Returns the length of this vector
|
|
737
765
|
* @return {Number} */
|
|
@@ -744,32 +772,56 @@ class Vector2
|
|
|
744
772
|
/** Returns the distance from this vector to vector passed in
|
|
745
773
|
* @param {Vector2} v - other vector
|
|
746
774
|
* @return {Number} */
|
|
747
|
-
distance(v)
|
|
775
|
+
distance(v)
|
|
776
|
+
{
|
|
777
|
+
ASSERT(isVector2(v));
|
|
778
|
+
return this.distanceSquared(v)**.5;
|
|
779
|
+
}
|
|
748
780
|
|
|
749
781
|
/** Returns the distance squared from this vector to vector passed in
|
|
750
782
|
* @param {Vector2} v - other vector
|
|
751
783
|
* @return {Number} */
|
|
752
|
-
distanceSquared(v)
|
|
784
|
+
distanceSquared(v)
|
|
785
|
+
{
|
|
786
|
+
ASSERT(isVector2(v));
|
|
787
|
+
return (this.x - v.x)**2 + (this.y - v.y)**2;
|
|
788
|
+
}
|
|
753
789
|
|
|
754
790
|
/** Returns a new vector in same direction as this one with the length passed in
|
|
755
791
|
* @param {Number} [length]
|
|
756
792
|
* @return {Vector2} */
|
|
757
|
-
normalize(length=1)
|
|
793
|
+
normalize(length=1)
|
|
794
|
+
{
|
|
795
|
+
const l = this.length();
|
|
796
|
+
return l ? this.scale(length/l) : new Vector2(0, length);
|
|
797
|
+
}
|
|
758
798
|
|
|
759
799
|
/** Returns a new vector clamped to length passed in
|
|
760
800
|
* @param {Number} [length]
|
|
761
801
|
* @return {Vector2} */
|
|
762
|
-
clampLength(length=1)
|
|
802
|
+
clampLength(length=1)
|
|
803
|
+
{
|
|
804
|
+
const l = this.length();
|
|
805
|
+
return l > length ? this.scale(length/l) : this;
|
|
806
|
+
}
|
|
763
807
|
|
|
764
808
|
/** Returns the dot product of this and the vector passed in
|
|
765
809
|
* @param {Vector2} v - other vector
|
|
766
810
|
* @return {Number} */
|
|
767
|
-
dot(v)
|
|
811
|
+
dot(v)
|
|
812
|
+
{
|
|
813
|
+
ASSERT(isVector2(v));
|
|
814
|
+
return this.x*v.x + this.y*v.y;
|
|
815
|
+
}
|
|
768
816
|
|
|
769
817
|
/** Returns the cross product of this and the vector passed in
|
|
770
818
|
* @param {Vector2} v - other vector
|
|
771
819
|
* @return {Number} */
|
|
772
|
-
cross(v)
|
|
820
|
+
cross(v)
|
|
821
|
+
{
|
|
822
|
+
ASSERT(isVector2(v));
|
|
823
|
+
return this.x*v.y - this.y*v.x;
|
|
824
|
+
}
|
|
773
825
|
|
|
774
826
|
/** Returns the angle of this vector, up is angle 0
|
|
775
827
|
* @return {Number} */
|
|
@@ -780,7 +832,11 @@ class Vector2
|
|
|
780
832
|
* @param {Number} [length]
|
|
781
833
|
* @return {Vector2} */
|
|
782
834
|
setAngle(angle=0, length=1)
|
|
783
|
-
{
|
|
835
|
+
{
|
|
836
|
+
this.x = length*Math.sin(angle);
|
|
837
|
+
this.y = length*Math.cos(angle);
|
|
838
|
+
return this;
|
|
839
|
+
}
|
|
784
840
|
|
|
785
841
|
/** Returns copy of this vector rotated by the angle passed in
|
|
786
842
|
* @param {Number} angle
|
|
@@ -791,9 +847,20 @@ class Vector2
|
|
|
791
847
|
return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
|
|
792
848
|
}
|
|
793
849
|
|
|
850
|
+
/** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
851
|
+
* @param {Number} [direction]
|
|
852
|
+
* @param {Number} [length] */
|
|
853
|
+
setDirection(direction, length=1)
|
|
854
|
+
{
|
|
855
|
+
ASSERT(direction==0 || direction==1 || direction==2 || direction==3);
|
|
856
|
+
return vec2(direction%2 ? direction-1 ? -length : length : 0,
|
|
857
|
+
direction%2 ? 0 : direction ? -length : length);
|
|
858
|
+
}
|
|
859
|
+
|
|
794
860
|
/** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
795
861
|
* @return {Number} */
|
|
796
|
-
direction()
|
|
862
|
+
direction()
|
|
863
|
+
{ return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
|
|
797
864
|
|
|
798
865
|
/** Returns a copy of this vector that has been inverted
|
|
799
866
|
* @return {Vector2} */
|
|
@@ -812,24 +879,34 @@ class Vector2
|
|
|
812
879
|
* @param {Number} percent
|
|
813
880
|
* @return {Vector2} */
|
|
814
881
|
lerp(v, percent)
|
|
815
|
-
{
|
|
882
|
+
{
|
|
883
|
+
ASSERT(isVector2(v));
|
|
884
|
+
return this.add(v.subtract(this).scale(clamp(percent)));
|
|
885
|
+
}
|
|
816
886
|
|
|
817
887
|
/** Returns true if this vector is within the bounds of an array size passed in
|
|
818
888
|
* @param {Vector2} arraySize
|
|
819
889
|
* @return {Boolean} */
|
|
820
|
-
arrayCheck(arraySize)
|
|
890
|
+
arrayCheck(arraySize)
|
|
891
|
+
{
|
|
892
|
+
ASSERT(isVector2(arraySize));
|
|
893
|
+
return this.x >= 0 && this.y >= 0 && this.x < arraySize.x && this.y < arraySize.y;
|
|
894
|
+
}
|
|
821
895
|
|
|
822
896
|
/** Returns this vector expressed as a string
|
|
823
897
|
* @param {Number} digits - precision to display
|
|
824
898
|
* @return {String} */
|
|
825
899
|
toString(digits=3)
|
|
826
|
-
{
|
|
900
|
+
{
|
|
901
|
+
if (debug)
|
|
902
|
+
return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
|
|
903
|
+
}
|
|
827
904
|
}
|
|
828
905
|
|
|
829
906
|
///////////////////////////////////////////////////////////////////////////////
|
|
830
907
|
|
|
831
908
|
/**
|
|
832
|
-
* Create a color object with RGBA values
|
|
909
|
+
* Create a color object with RGBA values, white by default
|
|
833
910
|
* @param {Number} [r=1] - red
|
|
834
911
|
* @param {Number} [g=1] - green
|
|
835
912
|
* @param {Number} [b=1] - blue
|
|
@@ -840,7 +917,7 @@ class Vector2
|
|
|
840
917
|
function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
841
918
|
|
|
842
919
|
/**
|
|
843
|
-
* Create a color object with HSLA values
|
|
920
|
+
* Create a color object with HSLA values, white by default
|
|
844
921
|
* @param {Number} [h=0] - hue
|
|
845
922
|
* @param {Number} [s=0] - saturation
|
|
846
923
|
* @param {Number} [l=1] - lightness
|
|
@@ -850,14 +927,22 @@ function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
|
850
927
|
*/
|
|
851
928
|
function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
852
929
|
|
|
930
|
+
/**
|
|
931
|
+
* Check if object is a valid Color
|
|
932
|
+
* @param {any} c
|
|
933
|
+
* @return {Boolean}
|
|
934
|
+
* @memberof Utilities
|
|
935
|
+
*/
|
|
936
|
+
function isColor(c) { return c instanceof Color; }
|
|
937
|
+
|
|
853
938
|
/**
|
|
854
939
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
855
940
|
* @example
|
|
856
941
|
* let a = new Color; // white
|
|
857
942
|
* let b = new Color(1, 0, 0); // red
|
|
858
943
|
* let c = new Color(0, 0, 0, 0); // transparent black
|
|
859
|
-
* let d =
|
|
860
|
-
* let e =
|
|
944
|
+
* let d = rgb(0, 0, 1); // blue using rgb color
|
|
945
|
+
* let e = hsl(.3, 1, .5); // green using hsl color
|
|
861
946
|
*/
|
|
862
947
|
class Color
|
|
863
948
|
{
|
|
@@ -885,22 +970,38 @@ class Color
|
|
|
885
970
|
/** Returns a copy of this color plus the color passed in
|
|
886
971
|
* @param {Color} c - other color
|
|
887
972
|
* @return {Color} */
|
|
888
|
-
add(c)
|
|
973
|
+
add(c)
|
|
974
|
+
{
|
|
975
|
+
ASSERT(isColor(c));
|
|
976
|
+
return new Color(this.r+c.r, this.g+c.g, this.b+c.b, this.a+c.a);
|
|
977
|
+
}
|
|
889
978
|
|
|
890
979
|
/** Returns a copy of this color minus the color passed in
|
|
891
980
|
* @param {Color} c - other color
|
|
892
981
|
* @return {Color} */
|
|
893
|
-
subtract(c)
|
|
982
|
+
subtract(c)
|
|
983
|
+
{
|
|
984
|
+
ASSERT(isColor(c));
|
|
985
|
+
return new Color(this.r-c.r, this.g-c.g, this.b-c.b, this.a-c.a);
|
|
986
|
+
}
|
|
894
987
|
|
|
895
988
|
/** Returns a copy of this color times the color passed in
|
|
896
989
|
* @param {Color} c - other color
|
|
897
990
|
* @return {Color} */
|
|
898
|
-
multiply(c)
|
|
991
|
+
multiply(c)
|
|
992
|
+
{
|
|
993
|
+
ASSERT(isColor(c));
|
|
994
|
+
return new Color(this.r*c.r, this.g*c.g, this.b*c.b, this.a*c.a);
|
|
995
|
+
}
|
|
899
996
|
|
|
900
997
|
/** Returns a copy of this color divided by the color passed in
|
|
901
998
|
* @param {Color} c - other color
|
|
902
999
|
* @return {Color} */
|
|
903
|
-
divide(c)
|
|
1000
|
+
divide(c)
|
|
1001
|
+
{
|
|
1002
|
+
ASSERT(isColor(c));
|
|
1003
|
+
return new Color(this.r/c.r, this.g/c.g, this.b/c.b, this.a/c.a);
|
|
1004
|
+
}
|
|
904
1005
|
|
|
905
1006
|
/** Returns a copy of this color scaled by the value passed in, alpha can be scaled separately
|
|
906
1007
|
* @param {Number} scale
|
|
@@ -917,7 +1018,11 @@ class Color
|
|
|
917
1018
|
* @param {Color} c - other color
|
|
918
1019
|
* @param {Number} percent
|
|
919
1020
|
* @return {Color} */
|
|
920
|
-
lerp(c, percent)
|
|
1021
|
+
lerp(c, percent)
|
|
1022
|
+
{
|
|
1023
|
+
ASSERT(isColor(c));
|
|
1024
|
+
return this.add(c.subtract(this).scale(clamp(percent)));
|
|
1025
|
+
}
|
|
921
1026
|
|
|
922
1027
|
/** Sets this color given a hue, saturation, lightness, and alpha
|
|
923
1028
|
* @param {Number} [h] - hue
|
|
@@ -1154,7 +1259,7 @@ let tileSizeDefault = vec2(16);
|
|
|
1154
1259
|
* @type {Number}
|
|
1155
1260
|
* @default
|
|
1156
1261
|
* @memberof Settings */
|
|
1157
|
-
let tileFixBleedScale = .
|
|
1262
|
+
let tileFixBleedScale = .1;
|
|
1158
1263
|
|
|
1159
1264
|
///////////////////////////////////////////////////////////////////////////////
|
|
1160
1265
|
// Object settings
|
|
@@ -1165,7 +1270,7 @@ let tileFixBleedScale = .3;
|
|
|
1165
1270
|
* @memberof Settings */
|
|
1166
1271
|
let enablePhysicsSolver = true;
|
|
1167
1272
|
|
|
1168
|
-
/** Default object mass for
|
|
1273
|
+
/** Default object mass for collision calcuations (how heavy objects are)
|
|
1169
1274
|
* @type {Number}
|
|
1170
1275
|
* @default
|
|
1171
1276
|
* @memberof Settings */
|
|
@@ -1248,7 +1353,7 @@ let touchGamepadEnable = false;
|
|
|
1248
1353
|
* @memberof Settings */
|
|
1249
1354
|
let touchGamepadAnalog = true;
|
|
1250
1355
|
|
|
1251
|
-
/** Size of
|
|
1356
|
+
/** Size of virtual gamepad for touch devices in pixels
|
|
1252
1357
|
* @type {Number}
|
|
1253
1358
|
* @default
|
|
1254
1359
|
* @memberof Settings */
|
|
@@ -1535,7 +1640,7 @@ function setDebugKey(key) { debugKey = key; }
|
|
|
1535
1640
|
* - Automatically adds self to object list
|
|
1536
1641
|
* - Will be updated and rendered each frame
|
|
1537
1642
|
* - Renders as a sprite from a tilesheet by default
|
|
1538
|
-
* - Can have color and
|
|
1643
|
+
* - Can have color and additive color applied
|
|
1539
1644
|
* - 2D Physics and collision system
|
|
1540
1645
|
* - Sorted by renderOrder
|
|
1541
1646
|
* - Objects can have children attached
|
|
@@ -1814,7 +1919,7 @@ class EngineObject
|
|
|
1814
1919
|
}
|
|
1815
1920
|
|
|
1816
1921
|
/** Destroy this object, destroy it's children, detach it's parent, and mark it for removal */
|
|
1817
|
-
destroy()
|
|
1922
|
+
destroy()
|
|
1818
1923
|
{
|
|
1819
1924
|
if (this.destroyed)
|
|
1820
1925
|
return;
|
|
@@ -2003,13 +2108,9 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
|
2003
2108
|
if (typeof pos === 'number')
|
|
2004
2109
|
{
|
|
2005
2110
|
const textureInfo = textureInfos[textureIndex];
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
2010
|
-
}
|
|
2011
|
-
else
|
|
2012
|
-
pos = vec2();
|
|
2111
|
+
ASSERT(textureInfo, 'Texture not loaded');
|
|
2112
|
+
const cols = textureInfo.size.x / size.x |0;
|
|
2113
|
+
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
2013
2114
|
}
|
|
2014
2115
|
|
|
2015
2116
|
// return a tile info object
|
|
@@ -2098,6 +2199,11 @@ function worldToScreen(worldPos)
|
|
|
2098
2199
|
);
|
|
2099
2200
|
}
|
|
2100
2201
|
|
|
2202
|
+
/** Get the camera's visible area in world space
|
|
2203
|
+
* @return {Vector2}
|
|
2204
|
+
* @memberof Draw */
|
|
2205
|
+
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
2206
|
+
|
|
2101
2207
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
2102
2208
|
* @param {Vector2} pos - Center of the tile in world space
|
|
2103
2209
|
* @param {Vector2} [size=(1,1)] - Size of the tile in world space
|
|
@@ -2732,9 +2838,9 @@ if (isTouchDevice)
|
|
|
2732
2838
|
// handle all touch events the same way
|
|
2733
2839
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2734
2840
|
{
|
|
2735
|
-
// fix stalled audio
|
|
2736
|
-
if (soundEnable)
|
|
2737
|
-
|
|
2841
|
+
// fix stalled audio requiring user interaction
|
|
2842
|
+
if (soundEnable && audioContext && audioContext.state != 'running')
|
|
2843
|
+
zzfx(0);
|
|
2738
2844
|
|
|
2739
2845
|
// check if touching and pass to mouse events
|
|
2740
2846
|
const touching = e.touches.length;
|
|
@@ -2775,7 +2881,7 @@ function createTouchGamepad()
|
|
|
2775
2881
|
touchGamepadStick = vec2();
|
|
2776
2882
|
|
|
2777
2883
|
const touchHandler = ontouchstart;
|
|
2778
|
-
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2884
|
+
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2779
2885
|
{
|
|
2780
2886
|
// clear touch gamepad input
|
|
2781
2887
|
touchGamepadStick = vec2();
|
|
@@ -2880,7 +2986,7 @@ function touchGamepadRender()
|
|
|
2880
2986
|
const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
2881
2987
|
for (let i=4; i--;)
|
|
2882
2988
|
{
|
|
2883
|
-
const pos = rightCenter.add(vec2().
|
|
2989
|
+
const pos = rightCenter.add(vec2().setDirection(i, touchGamepadSize/2));
|
|
2884
2990
|
overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
|
|
2885
2991
|
overlayContext.beginPath();
|
|
2886
2992
|
overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
|
|
@@ -2905,7 +3011,7 @@ function touchGamepadRender()
|
|
|
2905
3011
|
|
|
2906
3012
|
|
|
2907
3013
|
/**
|
|
2908
|
-
* Sound Object - Stores a
|
|
3014
|
+
* Sound Object - Stores a sound for later use and can be played positionally
|
|
2909
3015
|
*
|
|
2910
3016
|
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
2911
3017
|
* @example
|
|
@@ -2920,7 +3026,7 @@ class Sound
|
|
|
2920
3026
|
/** Create a sound object and cache the zzfx samples for later use
|
|
2921
3027
|
* @param {Array} zzfxSound - Array of zzfx parameters, ex. [.5,.5]
|
|
2922
3028
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
2923
|
-
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
3029
|
+
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
2924
3030
|
*/
|
|
2925
3031
|
constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
|
|
2926
3032
|
{
|
|
@@ -3039,22 +3145,19 @@ class SoundWave extends Sound
|
|
|
3039
3145
|
this.randomness = randomness;
|
|
3040
3146
|
|
|
3041
3147
|
if (!soundEnable) return;
|
|
3042
|
-
if (!soundDecoderContext)
|
|
3043
|
-
soundDecoderContext = new AudioContext;
|
|
3044
3148
|
|
|
3045
3149
|
fetch(filename)
|
|
3046
3150
|
.then(response => response.arrayBuffer())
|
|
3047
|
-
.then(arrayBuffer =>
|
|
3151
|
+
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
|
|
3048
3152
|
.then(audioBuffer =>
|
|
3049
3153
|
{
|
|
3050
3154
|
this.sampleChannels = [];
|
|
3051
3155
|
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
3052
|
-
this.sampleChannels[i] = audioBuffer.getChannelData(i);
|
|
3156
|
+
this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
|
|
3053
3157
|
this.sampleRate = audioBuffer.sampleRate;
|
|
3054
3158
|
});
|
|
3055
3159
|
}
|
|
3056
3160
|
}
|
|
3057
|
-
let soundDecoderContext; // audio context used only to decode audio files
|
|
3058
3161
|
|
|
3059
3162
|
/**
|
|
3060
3163
|
* Music Object - Stores a zzfx music track for later use
|
|
@@ -3103,24 +3206,24 @@ class Music extends Sound
|
|
|
3103
3206
|
|
|
3104
3207
|
/** Play the music
|
|
3105
3208
|
* @param {Number} [volume=1] - How much to scale volume by
|
|
3106
|
-
* @param {Boolean} [loop
|
|
3209
|
+
* @param {Boolean} [loop] - True if the music should loop
|
|
3107
3210
|
* @return {AudioBufferSourceNode} - The audio source node
|
|
3108
3211
|
*/
|
|
3109
|
-
playMusic(volume, loop
|
|
3212
|
+
playMusic(volume, loop=false)
|
|
3110
3213
|
{ return super.play(undefined, volume, 1, 1, loop); }
|
|
3111
3214
|
}
|
|
3112
3215
|
|
|
3113
3216
|
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
3114
|
-
* @param {String}
|
|
3217
|
+
* @param {String} filename - Location of sound file to play
|
|
3115
3218
|
* @param {Number} [volume] - How much to scale volume by
|
|
3116
3219
|
* @param {Boolean} [loop] - True if the music should loop
|
|
3117
3220
|
* @return {HTMLAudioElement} - The audio element for this sound
|
|
3118
3221
|
* @memberof Audio */
|
|
3119
|
-
function playAudioFile(
|
|
3222
|
+
function playAudioFile(filename, volume=1, loop=false)
|
|
3120
3223
|
{
|
|
3121
3224
|
if (!soundEnable) return;
|
|
3122
3225
|
|
|
3123
|
-
const audio = new Audio(
|
|
3226
|
+
const audio = new Audio(filename);
|
|
3124
3227
|
audio.volume = soundVolume * volume;
|
|
3125
3228
|
audio.loop = loop;
|
|
3126
3229
|
audio.play();
|
|
@@ -3168,8 +3271,14 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
3168
3271
|
///////////////////////////////////////////////////////////////////////////////
|
|
3169
3272
|
|
|
3170
3273
|
/** Audio context used by the engine
|
|
3274
|
+
* @type {AudioContext}
|
|
3275
|
+
* @memberof Audio */
|
|
3276
|
+
let audioContext = new AudioContext;
|
|
3277
|
+
|
|
3278
|
+
/** Keep track if audio was suspended when last sound was played
|
|
3279
|
+
* @type {Boolean}
|
|
3171
3280
|
* @memberof Audio */
|
|
3172
|
-
let
|
|
3281
|
+
let audioSuspended = false;
|
|
3173
3282
|
|
|
3174
3283
|
/** Play cached audio samples with given settings
|
|
3175
3284
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
@@ -3184,16 +3293,16 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3184
3293
|
{
|
|
3185
3294
|
if (!soundEnable) return;
|
|
3186
3295
|
|
|
3187
|
-
// create audio context if needed
|
|
3188
|
-
if (!audioContext)
|
|
3189
|
-
audioContext = new AudioContext;
|
|
3190
|
-
|
|
3191
3296
|
// prevent sounds from building up if they can't be played
|
|
3192
|
-
|
|
3297
|
+
const audioWasSuspended = audioSuspended;
|
|
3298
|
+
if (audioSuspended = audioContext.state != 'running')
|
|
3193
3299
|
{
|
|
3194
3300
|
// fix stalled audio
|
|
3195
3301
|
audioContext.resume();
|
|
3196
|
-
|
|
3302
|
+
|
|
3303
|
+
// prevent suspended sounds from building up
|
|
3304
|
+
if (audioWasSuspended)
|
|
3305
|
+
return;
|
|
3197
3306
|
}
|
|
3198
3307
|
|
|
3199
3308
|
// create buffer and source
|
|
@@ -3461,7 +3570,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
3461
3570
|
/**
|
|
3462
3571
|
* LittleJS Tile Layer System
|
|
3463
3572
|
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
3464
|
-
* -
|
|
3573
|
+
* - Unlimited numbers of layers, allocates canvases as needed
|
|
3465
3574
|
* - Interfaces with EngineObject for collision
|
|
3466
3575
|
* - Collision layer is separate from visible layers
|
|
3467
3576
|
* - It is recommended to have a visible layer that matches the collision
|
|
@@ -3513,7 +3622,7 @@ function getTileCollisionData(pos)
|
|
|
3513
3622
|
|
|
3514
3623
|
/** Check if collision with another object should occur
|
|
3515
3624
|
* @param {Vector2} pos
|
|
3516
|
-
* @param {Vector2} [size=(
|
|
3625
|
+
* @param {Vector2} [size=(0,0)]
|
|
3517
3626
|
* @param {EngineObject} [object]
|
|
3518
3627
|
* @return {Boolean}
|
|
3519
3628
|
* @memberof TileCollision */
|
|
@@ -3598,7 +3707,7 @@ class TileLayerData
|
|
|
3598
3707
|
* @param {Number} [direction] - Integer direction of tile, in 90 degree increments
|
|
3599
3708
|
* @param {Boolean} [mirror] - If the tile should be mirrored along the x axis
|
|
3600
3709
|
* @param {Color} [color] - Color of the tile */
|
|
3601
|
-
constructor(tile, direction=0, mirror=false, color=new Color
|
|
3710
|
+
constructor(tile, direction=0, mirror=false, color=new Color)
|
|
3602
3711
|
{
|
|
3603
3712
|
/** @property {Number} - The tile to use, untextured if undefined */
|
|
3604
3713
|
this.tile = tile;
|
|
@@ -3838,12 +3947,12 @@ class TileLayer extends EngineObject
|
|
|
3838
3947
|
* @example
|
|
3839
3948
|
* // create a particle emitter
|
|
3840
3949
|
* let pos = vec2(2,3);
|
|
3841
|
-
* let
|
|
3950
|
+
* let particleEmitter = new ParticleEmitter
|
|
3842
3951
|
* (
|
|
3843
|
-
* pos, 0, 1, 0, 500, PI,
|
|
3844
|
-
* tile(0, 16),
|
|
3845
|
-
*
|
|
3846
|
-
*
|
|
3952
|
+
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
3953
|
+
* tile(0, 16), // tileInfo
|
|
3954
|
+
* rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
|
|
3955
|
+
* rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
|
|
3847
3956
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
3848
3957
|
* .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
3849
3958
|
* .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
|
|
@@ -4030,16 +4139,17 @@ class ParticleEmitter extends EngineObject
|
|
|
4030
4139
|
|
|
4031
4140
|
// build particle
|
|
4032
4141
|
const particle = new Particle(pos, this.tileInfo, angle, colorStart, colorEnd, particleTime, sizeStart, sizeEnd, this.fadeRate, this.additive, this.trailScale, this.localSpace && this, this.particleDestroyCallback);
|
|
4033
|
-
particle.velocity
|
|
4034
|
-
particle.
|
|
4035
|
-
particle.
|
|
4036
|
-
particle.
|
|
4037
|
-
particle.
|
|
4038
|
-
particle.
|
|
4039
|
-
particle.
|
|
4040
|
-
particle.
|
|
4041
|
-
particle.
|
|
4042
|
-
particle.
|
|
4142
|
+
particle.velocity = vec2().setAngle(velocityAngle, speed);
|
|
4143
|
+
particle.angleVelocity = angleSpeed;
|
|
4144
|
+
particle.fadeRate = this.fadeRate;
|
|
4145
|
+
particle.damping = this.damping;
|
|
4146
|
+
particle.angleDamping = this.angleDamping;
|
|
4147
|
+
particle.elasticity = this.elasticity;
|
|
4148
|
+
particle.friction = this.friction;
|
|
4149
|
+
particle.gravityScale = this.gravityScale;
|
|
4150
|
+
particle.collideTiles = this.collideTiles;
|
|
4151
|
+
particle.renderOrder = this.renderOrder;
|
|
4152
|
+
particle.mirror = !!randInt(2);
|
|
4043
4153
|
|
|
4044
4154
|
// call particle create callaback
|
|
4045
4155
|
this.particleCreateCallback && this.particleCreateCallback(particle);
|
|
@@ -4250,8 +4360,8 @@ class Medal
|
|
|
4250
4360
|
// draw containing rect and clip to that region
|
|
4251
4361
|
context.save();
|
|
4252
4362
|
context.beginPath();
|
|
4253
|
-
context.fillStyle =
|
|
4254
|
-
context.strokeStyle =
|
|
4363
|
+
context.fillStyle = new Color(.9,.9,.9).toString();
|
|
4364
|
+
context.strokeStyle = new Color(0,0,0).toString();
|
|
4255
4365
|
context.lineWidth = 3;
|
|
4256
4366
|
context.rect(x, y, width, medalDisplaySize.y);
|
|
4257
4367
|
context.fill();
|
|
@@ -4430,7 +4540,7 @@ class Newgrounds
|
|
|
4430
4540
|
}
|
|
4431
4541
|
|
|
4432
4542
|
// build the input object
|
|
4433
|
-
const input =
|
|
4543
|
+
const input =
|
|
4434
4544
|
{
|
|
4435
4545
|
'app_id': this.app_id,
|
|
4436
4546
|
'session_id': this.session_id,
|
|
@@ -4645,8 +4755,6 @@ function glCreateTexture(image)
|
|
|
4645
4755
|
const filter = canvasPixelated ? gl_NEAREST : gl_LINEAR;
|
|
4646
4756
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
|
|
4647
4757
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
|
|
4648
|
-
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE);
|
|
4649
|
-
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE);
|
|
4650
4758
|
|
|
4651
4759
|
return texture;
|
|
4652
4760
|
}
|
|
@@ -4703,7 +4811,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4703
4811
|
ASSERT(typeof rgba == 'number' && typeof rgbaAdditive == 'number', 'invalid color');
|
|
4704
4812
|
|
|
4705
4813
|
// flush if there is not enough room or if different blend mode
|
|
4706
|
-
if (glInstanceCount >= gl_MAX_INSTANCES
|
|
4814
|
+
if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
|
|
4707
4815
|
glFlush();
|
|
4708
4816
|
|
|
4709
4817
|
let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
|
|
@@ -4724,7 +4832,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4724
4832
|
///////////////////////////////////////////////////////////////////////////////
|
|
4725
4833
|
// post processing - can be enabled to pass other canvases through a final shader
|
|
4726
4834
|
|
|
4727
|
-
let glPostShader,
|
|
4835
|
+
let glPostShader, glPostTexture, glPostIncludeOverlay;
|
|
4728
4836
|
|
|
4729
4837
|
/** Set up a post processing shader
|
|
4730
4838
|
* @param {String} shaderCode
|
|
@@ -4760,7 +4868,6 @@ function glInitPostProcess(shaderCode, includeOverlay=false)
|
|
|
4760
4868
|
);
|
|
4761
4869
|
|
|
4762
4870
|
// create buffer and texture
|
|
4763
|
-
glPostArrayBuffer = glContext.createBuffer();
|
|
4764
4871
|
glPostTexture = glCreateTexture(undefined);
|
|
4765
4872
|
glPostIncludeOverlay = includeOverlay;
|
|
4766
4873
|
|
|
@@ -4832,10 +4939,7 @@ gl_NEAREST = 9728,
|
|
|
4832
4939
|
gl_LINEAR = 9729,
|
|
4833
4940
|
gl_TEXTURE_MAG_FILTER = 10240,
|
|
4834
4941
|
gl_TEXTURE_MIN_FILTER = 10241,
|
|
4835
|
-
gl_TEXTURE_WRAP_S = 10242,
|
|
4836
|
-
gl_TEXTURE_WRAP_T = 10243,
|
|
4837
4942
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4838
|
-
gl_CLAMP_TO_EDGE = 33071,
|
|
4839
4943
|
gl_TEXTURE0 = 33984,
|
|
4840
4944
|
gl_ARRAY_BUFFER = 34962,
|
|
4841
4945
|
gl_STATIC_DRAW = 35044,
|
|
@@ -4852,7 +4956,7 @@ gl_MAX_INSTANCES = 1e4,
|
|
|
4852
4956
|
gl_INSTANCE_BYTE_STRIDE = gl_INDICIES_PER_INSTANCE * 4, // 11 * 4
|
|
4853
4957
|
gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
|
|
4854
4958
|
/**
|
|
4855
|
-
* LittleJS - The Tiny JavaScript Game Engine
|
|
4959
|
+
* LittleJS - The Tiny Fast JavaScript Game Engine
|
|
4856
4960
|
* MIT License - Copyright 2021 Frank Force
|
|
4857
4961
|
*
|
|
4858
4962
|
* Engine Features
|
|
@@ -4883,9 +4987,9 @@ const engineName = 'LittleJS';
|
|
|
4883
4987
|
* @type {String}
|
|
4884
4988
|
* @default
|
|
4885
4989
|
* @memberof Engine */
|
|
4886
|
-
const engineVersion = '1.9.
|
|
4990
|
+
const engineVersion = '1.9.3';
|
|
4887
4991
|
|
|
4888
|
-
/** Frames per second to update
|
|
4992
|
+
/** Frames per second to update
|
|
4889
4993
|
* @type {Number}
|
|
4890
4994
|
* @default
|
|
4891
4995
|
* @memberof Engine */
|
|
@@ -4902,7 +5006,7 @@ const timeDelta = 1/frameRate;
|
|
|
4902
5006
|
* @memberof Engine */
|
|
4903
5007
|
let engineObjects = [];
|
|
4904
5008
|
|
|
4905
|
-
/** Array
|
|
5009
|
+
/** Array with only objects set to collide with other objects this frame (for optimization)
|
|
4906
5010
|
* @type {Array}
|
|
4907
5011
|
* @memberof Engine */
|
|
4908
5012
|
let engineObjectsCollide = [];
|
|
@@ -4912,7 +5016,7 @@ let engineObjectsCollide = [];
|
|
|
4912
5016
|
* @memberof Engine */
|
|
4913
5017
|
let frame = 0;
|
|
4914
5018
|
|
|
4915
|
-
/** Current engine time since start in seconds
|
|
5019
|
+
/** Current engine time since start in seconds
|
|
4916
5020
|
* @type {Number}
|
|
4917
5021
|
* @memberof Engine */
|
|
4918
5022
|
let time = 0;
|
|
@@ -4938,12 +5042,12 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
4938
5042
|
|
|
4939
5043
|
///////////////////////////////////////////////////////////////////////////////
|
|
4940
5044
|
|
|
4941
|
-
/**
|
|
4942
|
-
* @param {Function} gameInit
|
|
4943
|
-
* @param {Function} gameUpdate
|
|
4944
|
-
* @param {Function} gameUpdatePost
|
|
4945
|
-
* @param {Function} gameRender
|
|
4946
|
-
* @param {Function} gameRenderPost
|
|
5045
|
+
/** Startup LittleJS engine with your callback functions
|
|
5046
|
+
* @param {Function} gameInit - Called once after the engine starts up, setup the game
|
|
5047
|
+
* @param {Function} gameUpdate - Called every frame at 60 frames per second, handle input and update the game state
|
|
5048
|
+
* @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
|
|
5049
|
+
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
5050
|
+
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
4947
5051
|
* @param {Array} [imageSources=['tiles.png']] - Image to load
|
|
4948
5052
|
* @memberof Engine */
|
|
4949
5053
|
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
|
|
@@ -4966,32 +5070,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4966
5070
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
4967
5071
|
if (!debugSpeedUp)
|
|
4968
5072
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
|
|
4969
|
-
|
|
4970
|
-
if (canvasFixedSize.x)
|
|
4971
|
-
{
|
|
4972
|
-
// clear canvas and set fixed size
|
|
4973
|
-
mainCanvas.width = canvasFixedSize.x;
|
|
4974
|
-
mainCanvas.height = canvasFixedSize.y;
|
|
4975
|
-
|
|
4976
|
-
// fit to window by adding space on top or bottom if necessary
|
|
4977
|
-
const aspect = innerWidth / innerHeight;
|
|
4978
|
-
const fixedAspect = mainCanvas.width / mainCanvas.height;
|
|
4979
|
-
(glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
|
|
4980
|
-
(glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
|
|
4981
|
-
}
|
|
4982
|
-
else
|
|
4983
|
-
{
|
|
4984
|
-
// clear canvas and set size to same as window
|
|
4985
|
-
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
4986
|
-
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
4987
|
-
}
|
|
4988
|
-
|
|
4989
|
-
// clear overlay canvas and set size
|
|
4990
|
-
overlayCanvas.width = mainCanvas.width;
|
|
4991
|
-
overlayCanvas.height = mainCanvas.height;
|
|
4992
|
-
|
|
4993
|
-
// save canvas size
|
|
4994
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
5073
|
+
updateCanvas();
|
|
4995
5074
|
|
|
4996
5075
|
if (paused)
|
|
4997
5076
|
{
|
|
@@ -5065,6 +5144,35 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5065
5144
|
requestAnimationFrame(engineUpdate);
|
|
5066
5145
|
}
|
|
5067
5146
|
|
|
5147
|
+
function updateCanvas()
|
|
5148
|
+
{
|
|
5149
|
+
if (canvasFixedSize.x)
|
|
5150
|
+
{
|
|
5151
|
+
// clear canvas and set fixed size
|
|
5152
|
+
mainCanvas.width = canvasFixedSize.x;
|
|
5153
|
+
mainCanvas.height = canvasFixedSize.y;
|
|
5154
|
+
|
|
5155
|
+
// fit to window by adding space on top or bottom if necessary
|
|
5156
|
+
const aspect = innerWidth / innerHeight;
|
|
5157
|
+
const fixedAspect = mainCanvas.width / mainCanvas.height;
|
|
5158
|
+
(glCanvas||mainCanvas).style.width = mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
|
|
5159
|
+
(glCanvas||mainCanvas).style.height = mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
|
|
5160
|
+
}
|
|
5161
|
+
else
|
|
5162
|
+
{
|
|
5163
|
+
// clear canvas and set size to same as window
|
|
5164
|
+
mainCanvas.width = min(innerWidth, canvasMaxSize.x);
|
|
5165
|
+
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
5166
|
+
}
|
|
5167
|
+
|
|
5168
|
+
// clear overlay canvas and set size
|
|
5169
|
+
overlayCanvas.width = mainCanvas.width;
|
|
5170
|
+
overlayCanvas.height = mainCanvas.height;
|
|
5171
|
+
|
|
5172
|
+
// save canvas size
|
|
5173
|
+
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
5174
|
+
}
|
|
5175
|
+
|
|
5068
5176
|
// setup html
|
|
5069
5177
|
const styleBody =
|
|
5070
5178
|
'margin:0;overflow:hidden;' + // fill the window
|
|
@@ -5089,6 +5197,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5089
5197
|
const styleCanvas = 'position:absolute;' + // position
|
|
5090
5198
|
'top:50%;left:50%;transform:translate(-50%,-50%)'; // center
|
|
5091
5199
|
(glCanvas||mainCanvas).style.cssText = mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
5200
|
+
updateCanvas();
|
|
5092
5201
|
|
|
5093
5202
|
// create promises for loading images
|
|
5094
5203
|
const promises = imageSources.map((src, textureIndex)=>
|
|
@@ -5285,9 +5394,9 @@ function drawEngineSplashScreen(t)
|
|
|
5285
5394
|
|
|
5286
5395
|
// big stack
|
|
5287
5396
|
rect(50,20,10,-10,color(0,1));
|
|
5288
|
-
rect(50,20,6,-10,color(0,2));
|
|
5289
|
-
rect(50,20,3,-10,color(0,3));
|
|
5290
|
-
rect(50,
|
|
5397
|
+
rect(50,20,6.5,-10,color(0,2));
|
|
5398
|
+
rect(50,20,3.5,-10,color(0,3));
|
|
5399
|
+
rect(50,20,10,-10);
|
|
5291
5400
|
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
5292
5401
|
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
5293
5402
|
circle(55,2,11.4,.5,PI-.5);
|
|
@@ -5306,7 +5415,7 @@ function drawEngineSplashScreen(t)
|
|
|
5306
5415
|
|
|
5307
5416
|
// engine outline
|
|
5308
5417
|
circle(36,30,10,PI/2,PI*3/2);
|
|
5309
|
-
circle(
|
|
5418
|
+
circle(48,30,10,PI/2,PI*3/2);
|
|
5310
5419
|
circle(60,30,10);
|
|
5311
5420
|
line(36,20,60,20);
|
|
5312
5421
|
|