littlejsengine 1.9.1 → 1.9.2
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 +7 -7
- package/{build → dist}/littlejs.d.ts +25 -20
- package/{build → dist}/littlejs.esm.js +160 -61
- package/dist/littlejs.esm.min.js +1 -0
- package/{build → dist}/littlejs.js +160 -61
- package/dist/littlejs.min.js +1 -0
- package/{build → dist}/littlejs.release.js +154 -59
- 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/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/gameTileData.tmx +143 -0
- package/examples/platformer/data/gameTileData.tsx +4 -0
- package/examples/platformer/game.js +0 -1
- package/examples/platformer/gameCharacter.js +1 -1
- package/examples/platformer/gameEffects.js +42 -110
- package/examples/platformer/gameLevel.js +149 -183
- package/examples/platformer/gameObjects.js +61 -16
- package/examples/platformer/gamePlayer.js +3 -2
- package/examples/platformer/gameTileData.js +181 -0
- 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/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 +1 -1
- 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/src/engine.js +1 -1
- package/src/engineAudio.js +4 -10
- package/src/engineBuild.js +9 -2
- package/src/engineDebug.js +6 -2
- package/src/engineInput.js +4 -4
- package/src/engineMedals.js +2 -2
- package/src/engineParticles.js +5 -5
- package/src/engineTileLayer.js +1 -1
- package/src/engineUtilities.js +136 -35
- package/src/engineWebGL.js +1 -1
- package/build/littlejs.esm.min.js +0 -1
- package/build/littlejs.min.js +0 -1
- package/index.d.ts +0 -2094
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ LittleJS is a small but powerful game engine with many features and no dependenc
|
|
|
54
54
|
|
|
55
55
|
### 💥 Physics
|
|
56
56
|
|
|
57
|
-
- Robust
|
|
57
|
+
- Robust arcade physics system with collision handling
|
|
58
58
|
- Very fast collision and raycasting for tile maps
|
|
59
59
|
|
|
60
60
|
### 🚀 Flexibility
|
|
@@ -91,7 +91,7 @@ These examples are for both learning and using as starter projects to create you
|
|
|
91
91
|
- [Starter Project](https://killedbyapixel.github.io/LittleJS/examples/starter/) - Clean example with only a few things to get you started
|
|
92
92
|
- [Breakout](https://killedbyapixel.github.io/LittleJS/examples/breakout/) - Block breaking game with post-processing effects
|
|
93
93
|
- [Puzzle Game](https://killedbyapixel.github.io/LittleJS/examples/puzzle/) - Match 3 puzzle game with HD rendering and high score tracking
|
|
94
|
-
- [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter with
|
|
94
|
+
- [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter with level data from [Tiled Editor](https://github.com/mapeditor/tiled)
|
|
95
95
|
- [Stress Test](https://killedbyapixel.github.io/LittleJS/examples/stress/) - Max sprite/object test and music system demo
|
|
96
96
|
- [Particle System Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Particle system editor and visualizer
|
|
97
97
|
|
|
@@ -99,11 +99,11 @@ These examples are for both learning and using as starter projects to create you
|
|
|
99
99
|
|
|
100
100
|
To easily include LittleJS in your game, you can use one of the pre-built js files.
|
|
101
101
|
|
|
102
|
-
- [littlejs.js](https://github.com/KilledByAPixel/LittleJS/blob/main/
|
|
103
|
-
- [littlejs.release.js](https://github.com/KilledByAPixel/LittleJS/blob/main/
|
|
104
|
-
- [littlejs.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/
|
|
105
|
-
- [littlejs.esm.js](https://github.com/KilledByAPixel/LittleJS/blob/main/
|
|
106
|
-
- [littlejs.esm.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/
|
|
102
|
+
- [littlejs.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.js) - The full game engine with debug mode available
|
|
103
|
+
- [littlejs.release.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.release.js) - The engine optimized for release builds
|
|
104
|
+
- [littlejs.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.min.js) - The engine in release mode and minified
|
|
105
|
+
- [littlejs.esm.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.js) - The engine exported as a module with debug mode available
|
|
106
|
+
- [littlejs.esm.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.min.js) - The engine exported as a minified module in release mode
|
|
107
107
|
|
|
108
108
|
To rebuild the engine you must first run ```npm install``` to setup the necessary npm dependencies. Then call ```npm run build``` to build the engine.
|
|
109
109
|
|
|
@@ -111,9 +111,9 @@ declare module "littlejs.esm" {
|
|
|
111
111
|
export let showWatermark: boolean;
|
|
112
112
|
/** Asserts if the experssion is false, does not do anything in release builds
|
|
113
113
|
* @param {Boolean} assert
|
|
114
|
-
* @param {Object} output
|
|
114
|
+
* @param {Object} [output]
|
|
115
115
|
* @memberof Debug */
|
|
116
|
-
export function ASSERT(assert: boolean, output
|
|
116
|
+
export function ASSERT(assert: boolean, output?: any): void;
|
|
117
117
|
/** Draw a debug rectangle in world space
|
|
118
118
|
* @param {Vector2} pos
|
|
119
119
|
* @param {Vector2} [size=Vector2()]
|
|
@@ -619,13 +619,13 @@ declare module "littlejs.esm" {
|
|
|
619
619
|
* @memberof Utilities */
|
|
620
620
|
export function nearestPowerOfTwo(value: number): number;
|
|
621
621
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
622
|
-
* @param {Vector2} pointA
|
|
623
|
-
* @param {Vector2} sizeA
|
|
624
|
-
* @param {Vector2} pointB
|
|
625
|
-
* @param {Vector2} sizeB - Size of box B
|
|
626
|
-
* @return {Boolean}
|
|
622
|
+
* @param {Vector2} pointA - Center of box A
|
|
623
|
+
* @param {Vector2} sizeA - Size of box A
|
|
624
|
+
* @param {Vector2} pointB - Center of box B
|
|
625
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
626
|
+
* @return {Boolean} - True if overlapping
|
|
627
627
|
* @memberof Utilities */
|
|
628
|
-
export function isOverlapping(pointA: Vector2, sizeA: Vector2, pointB: Vector2, sizeB
|
|
628
|
+
export function isOverlapping(pointA: Vector2, sizeA: Vector2, pointB: Vector2, sizeB?: Vector2): boolean;
|
|
629
629
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
630
630
|
* @param {Number} [frequency] - Frequency of the wave in Hz
|
|
631
631
|
* @param {Number} [amplitude] - Amplitude (max height) of the wave
|
|
@@ -668,8 +668,8 @@ declare module "littlejs.esm" {
|
|
|
668
668
|
* @memberof Random */
|
|
669
669
|
export function randVector(length?: number): Vector2;
|
|
670
670
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
671
|
-
* @param {Color} [colorA=
|
|
672
|
-
* @param {Color} [colorB=
|
|
671
|
+
* @param {Color} [colorA=(1,1,1,1)]
|
|
672
|
+
* @param {Color} [colorB=(0,0,0,1)]
|
|
673
673
|
* @param {Boolean} [linear]
|
|
674
674
|
* @return {Color}
|
|
675
675
|
* @memberof Random */
|
|
@@ -787,6 +787,10 @@ declare module "littlejs.esm" {
|
|
|
787
787
|
* @param {Number} angle
|
|
788
788
|
* @return {Vector2} */
|
|
789
789
|
rotate(angle: number): Vector2;
|
|
790
|
+
/** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
791
|
+
* @param {Number} [direction]
|
|
792
|
+
* @param {Number} [length] */
|
|
793
|
+
setDirection(direction?: number, length?: number): Vector2;
|
|
790
794
|
/** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
|
|
791
795
|
* @return {Number} */
|
|
792
796
|
direction(): number;
|
|
@@ -819,8 +823,8 @@ declare module "littlejs.esm" {
|
|
|
819
823
|
* let a = new Color; // white
|
|
820
824
|
* let b = new Color(1, 0, 0); // red
|
|
821
825
|
* let c = new Color(0, 0, 0, 0); // transparent black
|
|
822
|
-
* let d =
|
|
823
|
-
* let e =
|
|
826
|
+
* let d = rgb(0, 0, 1); // blue using rgb color
|
|
827
|
+
* let e = hsl(.3, 1, .5); // green using hsl color
|
|
824
828
|
*/
|
|
825
829
|
export class Color {
|
|
826
830
|
/** Create a color with the rgba components passed in, white by default
|
|
@@ -952,7 +956,7 @@ declare module "littlejs.esm" {
|
|
|
952
956
|
*/
|
|
953
957
|
export function vec2(x?: (number | Vector2), y?: number): Vector2;
|
|
954
958
|
/**
|
|
955
|
-
* Create a color object with RGBA values
|
|
959
|
+
* Create a color object with RGBA values, white by default
|
|
956
960
|
* @param {Number} [r=1] - red
|
|
957
961
|
* @param {Number} [g=1] - green
|
|
958
962
|
* @param {Number} [b=1] - blue
|
|
@@ -962,7 +966,7 @@ declare module "littlejs.esm" {
|
|
|
962
966
|
*/
|
|
963
967
|
export function rgb(r?: number, g?: number, b?: number, a?: number): Color;
|
|
964
968
|
/**
|
|
965
|
-
* Create a color object with HSLA values
|
|
969
|
+
* Create a color object with HSLA values, white by default
|
|
966
970
|
* @param {Number} [h=0] - hue
|
|
967
971
|
* @param {Number} [s=0] - saturation
|
|
968
972
|
* @param {Number} [l=1] - lightness
|
|
@@ -1520,8 +1524,9 @@ declare module "littlejs.esm" {
|
|
|
1520
1524
|
* @memberof Audio */
|
|
1521
1525
|
export function getNoteFrequency(semitoneOffset: number, rootFrequency?: number): number;
|
|
1522
1526
|
/** Audio context used by the engine
|
|
1527
|
+
* @type {AudioContext}
|
|
1523
1528
|
* @memberof Audio */
|
|
1524
|
-
export let audioContext:
|
|
1529
|
+
export let audioContext: AudioContext;
|
|
1525
1530
|
/** Play cached audio samples with given settings
|
|
1526
1531
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
1527
1532
|
* @param {Number} [volume] - How much to scale volume by
|
|
@@ -1842,12 +1847,12 @@ declare module "littlejs.esm" {
|
|
|
1842
1847
|
* @example
|
|
1843
1848
|
* // create a particle emitter
|
|
1844
1849
|
* let pos = vec2(2,3);
|
|
1845
|
-
* let
|
|
1850
|
+
* let particleEmitter = new ParticleEmitter
|
|
1846
1851
|
* (
|
|
1847
|
-
* pos, 0, 1, 0, 500, PI,
|
|
1848
|
-
* tile(0, 16),
|
|
1849
|
-
*
|
|
1850
|
-
*
|
|
1852
|
+
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
1853
|
+
* tile(0, 16), // tileInfo
|
|
1854
|
+
* rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
|
|
1855
|
+
* rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
|
|
1851
1856
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
1852
1857
|
* .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
1853
1858
|
* .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
|
|
@@ -58,9 +58,13 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
58
58
|
|
|
59
59
|
/** Asserts if the experssion 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
|
|
@@ -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
|
|
@@ -2732,9 +2837,9 @@ if (isTouchDevice)
|
|
|
2732
2837
|
// handle all touch events the same way
|
|
2733
2838
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2734
2839
|
{
|
|
2735
|
-
// fix stalled audio
|
|
2736
|
-
if (soundEnable)
|
|
2737
|
-
|
|
2840
|
+
// fix stalled audio requiring user interaction
|
|
2841
|
+
if (soundEnable && audioContext && audioContext.state != 'running')
|
|
2842
|
+
zzfx(0);
|
|
2738
2843
|
|
|
2739
2844
|
// check if touching and pass to mouse events
|
|
2740
2845
|
const touching = e.touches.length;
|
|
@@ -2880,7 +2985,7 @@ function touchGamepadRender()
|
|
|
2880
2985
|
const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
2881
2986
|
for (let i=4; i--;)
|
|
2882
2987
|
{
|
|
2883
|
-
const pos = rightCenter.add(vec2().
|
|
2988
|
+
const pos = rightCenter.add(vec2().setDirection(i, touchGamepadSize/2));
|
|
2884
2989
|
overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
|
|
2885
2990
|
overlayContext.beginPath();
|
|
2886
2991
|
overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);
|
|
@@ -3039,22 +3144,19 @@ class SoundWave extends Sound
|
|
|
3039
3144
|
this.randomness = randomness;
|
|
3040
3145
|
|
|
3041
3146
|
if (!soundEnable) return;
|
|
3042
|
-
if (!soundDecoderContext)
|
|
3043
|
-
soundDecoderContext = new AudioContext;
|
|
3044
3147
|
|
|
3045
3148
|
fetch(filename)
|
|
3046
3149
|
.then(response => response.arrayBuffer())
|
|
3047
|
-
.then(arrayBuffer =>
|
|
3150
|
+
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
|
|
3048
3151
|
.then(audioBuffer =>
|
|
3049
3152
|
{
|
|
3050
3153
|
this.sampleChannels = [];
|
|
3051
3154
|
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
3052
|
-
this.sampleChannels[i] = audioBuffer.getChannelData(i);
|
|
3155
|
+
this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
|
|
3053
3156
|
this.sampleRate = audioBuffer.sampleRate;
|
|
3054
3157
|
});
|
|
3055
3158
|
}
|
|
3056
3159
|
}
|
|
3057
|
-
let soundDecoderContext; // audio context used only to decode audio files
|
|
3058
3160
|
|
|
3059
3161
|
/**
|
|
3060
3162
|
* Music Object - Stores a zzfx music track for later use
|
|
@@ -3168,8 +3270,9 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
3168
3270
|
///////////////////////////////////////////////////////////////////////////////
|
|
3169
3271
|
|
|
3170
3272
|
/** Audio context used by the engine
|
|
3273
|
+
* @type {AudioContext}
|
|
3171
3274
|
* @memberof Audio */
|
|
3172
|
-
let audioContext;
|
|
3275
|
+
let audioContext = new AudioContext;
|
|
3173
3276
|
|
|
3174
3277
|
/** Play cached audio samples with given settings
|
|
3175
3278
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
@@ -3184,10 +3287,6 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3184
3287
|
{
|
|
3185
3288
|
if (!soundEnable) return;
|
|
3186
3289
|
|
|
3187
|
-
// create audio context if needed
|
|
3188
|
-
if (!audioContext)
|
|
3189
|
-
audioContext = new AudioContext;
|
|
3190
|
-
|
|
3191
3290
|
// prevent sounds from building up if they can't be played
|
|
3192
3291
|
if (audioContext.state != 'running')
|
|
3193
3292
|
{
|
|
@@ -3598,7 +3697,7 @@ class TileLayerData
|
|
|
3598
3697
|
* @param {Number} [direction] - Integer direction of tile, in 90 degree increments
|
|
3599
3698
|
* @param {Boolean} [mirror] - If the tile should be mirrored along the x axis
|
|
3600
3699
|
* @param {Color} [color] - Color of the tile */
|
|
3601
|
-
constructor(tile, direction=0, mirror=false, color=new Color
|
|
3700
|
+
constructor(tile, direction=0, mirror=false, color=new Color)
|
|
3602
3701
|
{
|
|
3603
3702
|
/** @property {Number} - The tile to use, untextured if undefined */
|
|
3604
3703
|
this.tile = tile;
|
|
@@ -3838,12 +3937,12 @@ class TileLayer extends EngineObject
|
|
|
3838
3937
|
* @example
|
|
3839
3938
|
* // create a particle emitter
|
|
3840
3939
|
* let pos = vec2(2,3);
|
|
3841
|
-
* let
|
|
3940
|
+
* let particleEmitter = new ParticleEmitter
|
|
3842
3941
|
* (
|
|
3843
|
-
* pos, 0, 1, 0, 500, PI,
|
|
3844
|
-
* tile(0, 16),
|
|
3845
|
-
*
|
|
3846
|
-
*
|
|
3942
|
+
* pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
|
|
3943
|
+
* tile(0, 16), // tileInfo
|
|
3944
|
+
* rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
|
|
3945
|
+
* rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
|
|
3847
3946
|
* 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
|
|
3848
3947
|
* .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
|
|
3849
3948
|
* .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
|
|
@@ -4250,8 +4349,8 @@ class Medal
|
|
|
4250
4349
|
// draw containing rect and clip to that region
|
|
4251
4350
|
context.save();
|
|
4252
4351
|
context.beginPath();
|
|
4253
|
-
context.fillStyle =
|
|
4254
|
-
context.strokeStyle =
|
|
4352
|
+
context.fillStyle = new Color(.9,.9,.9).toString();
|
|
4353
|
+
context.strokeStyle = new Color(0,0,0).toString();
|
|
4255
4354
|
context.lineWidth = 3;
|
|
4256
4355
|
context.rect(x, y, width, medalDisplaySize.y);
|
|
4257
4356
|
context.fill();
|
|
@@ -4703,7 +4802,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
|
|
|
4703
4802
|
ASSERT(typeof rgba == 'number' && typeof rgbaAdditive == 'number', 'invalid color');
|
|
4704
4803
|
|
|
4705
4804
|
// flush if there is not enough room or if different blend mode
|
|
4706
|
-
if (glInstanceCount >= gl_MAX_INSTANCES
|
|
4805
|
+
if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
|
|
4707
4806
|
glFlush();
|
|
4708
4807
|
|
|
4709
4808
|
let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
|
|
@@ -4883,7 +4982,7 @@ const engineName = 'LittleJS';
|
|
|
4883
4982
|
* @type {String}
|
|
4884
4983
|
* @default
|
|
4885
4984
|
* @memberof Engine */
|
|
4886
|
-
const engineVersion = '1.9.
|
|
4985
|
+
const engineVersion = '1.9.2';
|
|
4887
4986
|
|
|
4888
4987
|
/** Frames per second to update objects
|
|
4889
4988
|
* @type {Number}
|