littlejsengine 1.6.4 → 1.6.6
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 +13 -9
- package/build/littlejs.d.ts +92 -88
- package/build/littlejs.esm.js +312 -251
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +270 -206
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +271 -203
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/favicon.png +0 -0
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/game.js +1 -1
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +1 -1
- package/examples/typescript/index.html +1 -1
- package/package.json +2 -2
- package/src/engine.js +29 -30
- package/src/engineAudio.js +42 -18
- package/src/engineDebug.js +17 -22
- package/src/engineDraw.js +24 -24
- package/src/engineExport.js +42 -45
- package/src/engineInput.js +32 -19
- package/src/engineMedals.js +31 -8
- package/src/engineObject.js +21 -21
- package/src/engineParticles.js +3 -6
- package/src/engineRelease.js +18 -19
- package/src/engineSettings.js +4 -4
- package/src/engineTileLayer.js +18 -14
- package/src/engineUtilities.js +41 -32
- package/src/engineWebGL.js +8 -8
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS - Release Build
|
|
3
|
+
* MIT License - Copyright 2021 Frank Force
|
|
4
|
+
* - This file is used for release builds in place of engineDebug.js
|
|
5
|
+
* - Debug functionality is disabled to reduce size and increase performance
|
|
6
|
+
*/
|
|
8
7
|
|
|
9
8
|
'use strict';
|
|
10
9
|
|
|
@@ -20,24 +19,24 @@ const debugGamepads = 0;
|
|
|
20
19
|
const debugMedals = 0;
|
|
21
20
|
|
|
22
21
|
// debug commands are automatically removed from the final build
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
function ASSERT (){}
|
|
23
|
+
function debugInit (){}
|
|
24
|
+
function debugUpdate (){}
|
|
25
|
+
function debugRender (){}
|
|
26
|
+
function debugRect (){}
|
|
27
|
+
function debugCircle (){}
|
|
28
|
+
function debugPoint (){}
|
|
29
|
+
function debugLine (){}
|
|
30
|
+
function debugAABB (){}
|
|
31
|
+
function debugText (){}
|
|
32
|
+
function debugClear (){}
|
|
33
|
+
function debugSaveCanvas (){}
|
|
35
34
|
/**
|
|
36
35
|
* LittleJS Utility Classes and Functions
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* - General purpose math library
|
|
37
|
+
* - Vector2 - fast, simple, easy 2D vector class
|
|
38
|
+
* - Color - holds a rgba color with some math functions
|
|
39
|
+
* - Timer - tracks time automatically
|
|
41
40
|
* @namespace Utilities
|
|
42
41
|
*/
|
|
43
42
|
|
|
@@ -53,34 +52,34 @@ const PI = Math.PI;
|
|
|
53
52
|
* @param {Number} value
|
|
54
53
|
* @return {Number}
|
|
55
54
|
* @memberof Utilities */
|
|
56
|
-
|
|
55
|
+
function abs(a) { return a < 0 ? -a : a; }
|
|
57
56
|
|
|
58
57
|
/** Returns lowest of two values passed in
|
|
59
58
|
* @param {Number} valueA
|
|
60
59
|
* @param {Number} valueB
|
|
61
60
|
* @return {Number}
|
|
62
61
|
* @memberof Utilities */
|
|
63
|
-
|
|
62
|
+
function min(a, b) { return a < b ? a : b; }
|
|
64
63
|
|
|
65
64
|
/** Returns highest of two values passed in
|
|
66
65
|
* @param {Number} valueA
|
|
67
66
|
* @param {Number} valueB
|
|
68
67
|
* @return {Number}
|
|
69
68
|
* @memberof Utilities */
|
|
70
|
-
|
|
69
|
+
function max(a, b) { return a > b ? a : b; }
|
|
71
70
|
|
|
72
71
|
/** Returns the sign of value passed in (also returns 1 if 0)
|
|
73
72
|
* @param {Number} value
|
|
74
73
|
* @return {Number}
|
|
75
74
|
* @memberof Utilities */
|
|
76
|
-
|
|
75
|
+
function sign(a) { return a < 0 ? -1 : 1; }
|
|
77
76
|
|
|
78
77
|
/** Returns first parm modulo the second param, but adjusted so negative numbers work as expected
|
|
79
78
|
* @param {Number} dividend
|
|
80
79
|
* @param {Number} [divisor=1]
|
|
81
80
|
* @return {Number}
|
|
82
81
|
* @memberof Utilities */
|
|
83
|
-
|
|
82
|
+
function mod(a, b=1) { return ((a % b) + b) % b; }
|
|
84
83
|
|
|
85
84
|
/** Clamps the value beween max and min
|
|
86
85
|
* @param {Number} value
|
|
@@ -88,7 +87,8 @@ const mod = (a, b=1)=> ((a % b) + b) % b;
|
|
|
88
87
|
* @param {Number} [max=1]
|
|
89
88
|
* @return {Number}
|
|
90
89
|
* @memberof Utilities */
|
|
91
|
-
|
|
90
|
+
function clamp(v, min=0, max=1)
|
|
91
|
+
{ return v < min ? min : v > max ? max : v; }
|
|
92
92
|
|
|
93
93
|
/** Returns what percentage the value is between max and min
|
|
94
94
|
* @param {Number} value
|
|
@@ -96,7 +96,8 @@ const clamp = (v, min=0, max=1)=> v < min ? min : v > max ? max : v;
|
|
|
96
96
|
* @param {Number} [max=1]
|
|
97
97
|
* @return {Number}
|
|
98
98
|
* @memberof Utilities */
|
|
99
|
-
|
|
99
|
+
function percent(v, min=0, max=1)
|
|
100
|
+
{ return max-min ? clamp((v-min) / (max-min)) : 0; }
|
|
100
101
|
|
|
101
102
|
/** Linearly interpolates the percent value between max and min
|
|
102
103
|
* @param {Number} percent
|
|
@@ -104,19 +105,19 @@ const percent = (v, min=0, max=1)=> max-min ? clamp((v-min) / (max-min)) : 0;
|
|
|
104
105
|
* @param {Number} [max=1]
|
|
105
106
|
* @return {Number}
|
|
106
107
|
* @memberof Utilities */
|
|
107
|
-
|
|
108
|
+
function lerp(p, min=0, max=1){ return min + clamp(p) * (max-min); }
|
|
108
109
|
|
|
109
110
|
/** Applies smoothstep function to the percentage value
|
|
110
111
|
* @param {Number} value
|
|
111
112
|
* @return {Number}
|
|
112
113
|
* @memberof Utilities */
|
|
113
|
-
|
|
114
|
+
function smoothStep(p) { return p * p * (3 - 2 * p); }
|
|
114
115
|
|
|
115
116
|
/** Returns the nearest power of two not less then the value
|
|
116
117
|
* @param {Number} value
|
|
117
118
|
* @return {Number}
|
|
118
119
|
* @memberof Utilities */
|
|
119
|
-
|
|
120
|
+
function nearestPowerOfTwo(v) { return 2**Math.ceil(Math.log2(v)); }
|
|
120
121
|
|
|
121
122
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
122
123
|
* @param {Vector2} pointA - Center of box A
|
|
@@ -125,7 +126,8 @@ const nearestPowerOfTwo = (v)=> 2**Math.ceil(Math.log2(v));
|
|
|
125
126
|
* @param {Vector2} [sizeB] - Size of box B
|
|
126
127
|
* @return {Boolean} - True if overlapping
|
|
127
128
|
* @memberof Utilities */
|
|
128
|
-
|
|
129
|
+
function isOverlapping(pA, sA, pB, sB)
|
|
130
|
+
{ return abs(pA.x - pB.x)*2 < sA.x + sB.x && abs(pA.y - pB.y)*2 < sA.y + sB.y; }
|
|
129
131
|
|
|
130
132
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
131
133
|
* @param {Number} [frequency=1] - Frequency of the wave in Hz
|
|
@@ -133,13 +135,14 @@ const isOverlapping = (pA, sA, pB, sB)=> abs(pA.x - pB.x)*2 < sA.x + sB.x && abs
|
|
|
133
135
|
* @param {Number} [t=time] - Value to use for time of the wave
|
|
134
136
|
* @return {Number} - Value waving between 0 and amplitude
|
|
135
137
|
* @memberof Utilities */
|
|
136
|
-
|
|
138
|
+
function wave(frequency=1, amplitude=1, t=time)
|
|
139
|
+
{ return amplitude/2 * (1 - Math.cos(t*frequency*2*PI)); }
|
|
137
140
|
|
|
138
141
|
/** Formats seconds to mm:ss style for display purposes
|
|
139
142
|
* @param {Number} t - time in seconds
|
|
140
143
|
* @return {String}
|
|
141
144
|
* @memberof Utilities */
|
|
142
|
-
|
|
145
|
+
function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
|
|
143
146
|
|
|
144
147
|
///////////////////////////////////////////////////////////////////////////////
|
|
145
148
|
|
|
@@ -151,32 +154,33 @@ const formatTime = (t)=> (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0);
|
|
|
151
154
|
* @param {Number} [valueB=0]
|
|
152
155
|
* @return {Number}
|
|
153
156
|
* @memberof Random */
|
|
154
|
-
|
|
157
|
+
function rand(a=1, b=0) { return b + (a-b)*Math.random(); }
|
|
155
158
|
|
|
156
159
|
/** Returns a floored random value the two values passed in
|
|
157
160
|
* @param {Number} [valueA=1]
|
|
158
161
|
* @param {Number} [valueB=0]
|
|
159
162
|
* @return {Number}
|
|
160
163
|
* @memberof Random */
|
|
161
|
-
|
|
164
|
+
function randInt(a=1, b=0) { return rand(a,b)|0; }
|
|
162
165
|
|
|
163
166
|
/** Randomly returns either -1 or 1
|
|
164
167
|
* @return {Number}
|
|
165
168
|
* @memberof Random */
|
|
166
|
-
|
|
169
|
+
function randSign() { return randInt(2) * 2 - 1; }
|
|
167
170
|
|
|
168
171
|
/** Returns a random Vector2 within a circular shape
|
|
169
172
|
* @param {Number} [radius=1]
|
|
170
173
|
* @param {Number} [minRadius=0]
|
|
171
174
|
* @return {Vector2}
|
|
172
175
|
* @memberof Random */
|
|
173
|
-
|
|
176
|
+
function randInCircle(radius=1, minRadius=0)
|
|
177
|
+
{ return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
|
|
174
178
|
|
|
175
179
|
/** Returns a random Vector2 with the passed in length
|
|
176
180
|
* @param {Number} [length=1]
|
|
177
181
|
* @return {Vector2}
|
|
178
182
|
* @memberof Random */
|
|
179
|
-
|
|
183
|
+
function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length); }
|
|
180
184
|
|
|
181
185
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
182
186
|
* @param {Color} [colorA=Color()]
|
|
@@ -184,8 +188,8 @@ const randVector = (length=1)=> new Vector2().setAngle(rand(2*PI), length);
|
|
|
184
188
|
* @param {Boolean} [linear]
|
|
185
189
|
* @return {Color}
|
|
186
190
|
* @memberof Random */
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
function randColor(cA = new Color, cB = new Color(0,0,0,1), linear)
|
|
192
|
+
{ return linear ? cA.lerp(cB, rand()) : new Color(rand(cA.r,cB.r),rand(cA.g,cB.g),rand(cA.b,cB.b),rand(cA.a,cB.a)); }
|
|
189
193
|
|
|
190
194
|
/** Seed used by the randSeeded function
|
|
191
195
|
* @type {Number}
|
|
@@ -196,16 +200,19 @@ let randSeed = 1;
|
|
|
196
200
|
/** Set seed used by the randSeeded function, should not be 0
|
|
197
201
|
* @param {Number} seed
|
|
198
202
|
* @memberof Random */
|
|
199
|
-
|
|
203
|
+
function setRandSeed(seed) { randSeed = seed; }
|
|
200
204
|
|
|
201
205
|
/** Returns a seeded random value between the two values passed in using randSeed
|
|
202
206
|
* @param {Number} [valueA=1]
|
|
203
207
|
* @param {Number} [valueB=0]
|
|
204
208
|
* @return {Number}
|
|
205
209
|
* @memberof Random */
|
|
206
|
-
|
|
210
|
+
function randSeeded(a=1, b=0)
|
|
207
211
|
{
|
|
208
|
-
|
|
212
|
+
// xorshift algorithm
|
|
213
|
+
randSeed ^= randSeed << 13;
|
|
214
|
+
randSeed ^= randSeed >>> 17;
|
|
215
|
+
randSeed ^= randSeed << 5;
|
|
209
216
|
return b + (a-b) * abs(randSeed % 1e9) / 1e9;
|
|
210
217
|
}
|
|
211
218
|
|
|
@@ -223,7 +230,8 @@ const randSeeded = (a=1, b=0)=>
|
|
|
223
230
|
* b = vec2(); // set b to (0, 0)
|
|
224
231
|
* @memberof Utilities
|
|
225
232
|
*/
|
|
226
|
-
|
|
233
|
+
function vec2(x=0, y)
|
|
234
|
+
{ return x.x == undefined ? new Vector2(x, y == undefined? x : y) : new Vector2(x.x, x.y); }
|
|
227
235
|
|
|
228
236
|
/**
|
|
229
237
|
* Check if object is a valid Vector2
|
|
@@ -231,11 +239,11 @@ const vec2 = (x=0, y)=> x.x == undefined ? new Vector2(x, y == undefined? x : y)
|
|
|
231
239
|
* @return {Boolean}
|
|
232
240
|
* @memberof Utilities
|
|
233
241
|
*/
|
|
234
|
-
|
|
242
|
+
function isVector2(v) { return !isNaN(v.x) && !isNaN(v.y); }
|
|
235
243
|
|
|
236
244
|
/**
|
|
237
245
|
* 2D Vector object with vector math library
|
|
238
|
-
*
|
|
246
|
+
* - Functions do not change this so they can be chained together
|
|
239
247
|
* @example
|
|
240
248
|
* let a = new Vector2(2, 3); // vector with coordinates (2, 3)
|
|
241
249
|
* let b = new Vector2; // vector with coordinates (0, 0)
|
|
@@ -382,7 +390,7 @@ class Vector2
|
|
|
382
390
|
* @return {Color}
|
|
383
391
|
* @memberof Utilities
|
|
384
392
|
*/
|
|
385
|
-
|
|
393
|
+
function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
386
394
|
|
|
387
395
|
/**
|
|
388
396
|
* Create a color object with HSLA values
|
|
@@ -393,7 +401,7 @@ const rgb = (r, g, b, a)=> new Color(r, g, b, a);
|
|
|
393
401
|
* @return {Color}
|
|
394
402
|
* @memberof Utilities
|
|
395
403
|
*/
|
|
396
|
-
|
|
404
|
+
function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
397
405
|
|
|
398
406
|
/**
|
|
399
407
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
@@ -652,11 +660,11 @@ let canvasMaxSize = vec2(1920, 1200);
|
|
|
652
660
|
* @memberof Settings */
|
|
653
661
|
let canvasFixedSize = vec2();
|
|
654
662
|
|
|
655
|
-
/** Disables
|
|
663
|
+
/** Disables filtering for crisper pixel art if true
|
|
656
664
|
* @type {Boolean}
|
|
657
665
|
* @default
|
|
658
666
|
* @memberof Settings */
|
|
659
|
-
let
|
|
667
|
+
let canvasPixelated = 1;
|
|
660
668
|
|
|
661
669
|
/** Default font used for text rendering
|
|
662
670
|
* @type {String}
|
|
@@ -773,8 +781,8 @@ let gamepadDirectionEmulateStick = 1;
|
|
|
773
781
|
let inputWASDEmulateDirection = 1;
|
|
774
782
|
|
|
775
783
|
/** True if touch gamepad should appear on mobile devices
|
|
776
|
-
*
|
|
777
|
-
*
|
|
784
|
+
* - Supports left analog stick, 4 face buttons and start button (button 9)
|
|
785
|
+
* - Must be set by end of gameInit to be activated
|
|
778
786
|
* @type {Boolean}
|
|
779
787
|
* @default 0
|
|
780
788
|
* @memberof Settings */
|
|
@@ -863,27 +871,23 @@ let medalDisplayIconSize = 50;
|
|
|
863
871
|
* @default 0
|
|
864
872
|
* @memberof Settings */
|
|
865
873
|
let medalsPreventUnlock;
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
*/
|
|
884
|
-
|
|
885
|
-
/**
|
|
886
|
-
* LittleJS Engine Globals
|
|
874
|
+
/**
|
|
875
|
+
* LittleJS - The Tiny JavaScript Game Engine That Can!
|
|
876
|
+
* MIT License - Copyright 2021 Frank Force
|
|
877
|
+
*
|
|
878
|
+
* Engine Features
|
|
879
|
+
* - Object oriented system with base class engine object
|
|
880
|
+
* - Base class object handles update, physics, collision, rendering, etc
|
|
881
|
+
* - Engine helper classes and functions like Vector2, Color, and Timer
|
|
882
|
+
* - Super fast rendering system for tile sheets
|
|
883
|
+
* - Sound effects audio with zzfx and music with zzfxm
|
|
884
|
+
* - Input processing system with gamepad and touchscreen support
|
|
885
|
+
* - Tile layer rendering and collision system
|
|
886
|
+
* - Particle effect system
|
|
887
|
+
* - Medal system tracks and displays achievements
|
|
888
|
+
* - Debug tools and debug rendering system
|
|
889
|
+
* - Post processing effects
|
|
890
|
+
* - Call engineInit() to start it up!
|
|
887
891
|
* @namespace Engine
|
|
888
892
|
*/
|
|
889
893
|
|
|
@@ -899,7 +903,7 @@ const engineName = 'LittleJS';
|
|
|
899
903
|
* @type {String}
|
|
900
904
|
* @default
|
|
901
905
|
* @memberof Engine */
|
|
902
|
-
const engineVersion = '1.6.
|
|
906
|
+
const engineVersion = '1.6.6';
|
|
903
907
|
|
|
904
908
|
/** Frames per second to update objects
|
|
905
909
|
* @type {Number}
|
|
@@ -969,10 +973,11 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
969
973
|
debug && (tileImage.onload=()=>ASSERT(1)); // tile sheet can not reloaded
|
|
970
974
|
|
|
971
975
|
// setup html
|
|
972
|
-
const styleBody = 'margin:0;overflow:hidden;
|
|
973
|
-
';
|
|
974
|
-
'
|
|
975
|
-
'
|
|
976
|
+
const styleBody = 'margin:0;overflow:hidden;' + // fill the window
|
|
977
|
+
'background:#000;' + // set background color
|
|
978
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
979
|
+
'user-select:none;' + // prevent mobile hold to select
|
|
980
|
+
'-webkit-user-select:none'; // compatibility for ios
|
|
976
981
|
document.body.style = styleBody;
|
|
977
982
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
978
983
|
mainContext = mainCanvas.getContext('2d');
|
|
@@ -985,8 +990,10 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
985
990
|
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
986
991
|
overlayContext = overlayCanvas.getContext('2d');
|
|
987
992
|
|
|
988
|
-
// set canvas style
|
|
989
|
-
const styleCanvas = 'position:absolute;
|
|
993
|
+
// set canvas style
|
|
994
|
+
const styleCanvas = 'position:absolute;' +
|
|
995
|
+
'top:50%;left:50%;transform:translate(-50%,-50%);' + // center the canvas
|
|
996
|
+
(canvasPixelated?'image-rendering:pixelated':''); // set pixelated rendering
|
|
990
997
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
991
998
|
|
|
992
999
|
gameInit();
|
|
@@ -1119,7 +1126,7 @@ function enginePreRender()
|
|
|
1119
1126
|
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
1120
1127
|
|
|
1121
1128
|
// disable smoothing for pixel art
|
|
1122
|
-
mainContext.imageSmoothingEnabled = !
|
|
1129
|
+
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
1123
1130
|
|
|
1124
1131
|
// setup gl rendering if enabled
|
|
1125
1132
|
glEnable && glPreRender();
|
|
@@ -1133,7 +1140,7 @@ function engineObjectsUpdate()
|
|
|
1133
1140
|
engineObjectsCollide = engineObjects.filter(o=>o.collideSolidObjects);
|
|
1134
1141
|
|
|
1135
1142
|
// recursive object update
|
|
1136
|
-
|
|
1143
|
+
function updateObject(o)
|
|
1137
1144
|
{
|
|
1138
1145
|
if (!o.destroyed)
|
|
1139
1146
|
{
|
|
@@ -1186,32 +1193,32 @@ function engineObjectsCallback(pos, size, callbackFunction, objects=engineObject
|
|
|
1186
1193
|
pos.distanceSquared(o.pos) < sizeSquared && callbackFunction(o);
|
|
1187
1194
|
}
|
|
1188
1195
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
*/
|
|
1196
|
+
/**
|
|
1197
|
+
* LittleJS Object System
|
|
1198
|
+
*/
|
|
1192
1199
|
|
|
1193
1200
|
'use strict';
|
|
1194
1201
|
|
|
1195
1202
|
/**
|
|
1196
1203
|
* LittleJS Object Base Object Class
|
|
1197
|
-
*
|
|
1198
|
-
*
|
|
1199
|
-
*
|
|
1200
|
-
*
|
|
1201
|
-
*
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1205
|
-
*
|
|
1206
|
-
*
|
|
1207
|
-
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
*
|
|
1214
|
-
*
|
|
1204
|
+
* - Base object class used by the engine
|
|
1205
|
+
* - Automatically adds self to object list
|
|
1206
|
+
* - Will be updated and rendered each frame
|
|
1207
|
+
* - Renders as a sprite from a tilesheet by default
|
|
1208
|
+
* - Can have color and addtive color applied
|
|
1209
|
+
* - 2d Physics and collision system
|
|
1210
|
+
* - Sorted by renderOrder
|
|
1211
|
+
* - Objects can have children attached
|
|
1212
|
+
* - Parents are updated before children, and set child transform
|
|
1213
|
+
* - Call destroy() to get rid of objects
|
|
1214
|
+
*
|
|
1215
|
+
* The physics system used by objects is simple and fast with some caveats...
|
|
1216
|
+
* - Collision uses the axis aligned size, the object's rotation angle is only for rendering
|
|
1217
|
+
* - Objects are guaranteed to not intersect tile collision from physics
|
|
1218
|
+
* - If an object starts or is moved inside tile collision, it will not collide with that tile
|
|
1219
|
+
* - Collision for objects can be set to be solid to block other objects
|
|
1220
|
+
* - Objects may get pushed into overlapping other solid objects, if so they will push away
|
|
1221
|
+
* - Solid objects are more performance intensive and should be used sparingly
|
|
1215
1222
|
* @example
|
|
1216
1223
|
* // create an engine object, normally you would first extend the class with your own
|
|
1217
1224
|
* const pos = vec2(2,3);
|
|
@@ -1564,23 +1571,23 @@ class EngineObject
|
|
|
1564
1571
|
}
|
|
1565
1572
|
/**
|
|
1566
1573
|
* LittleJS Drawing System
|
|
1567
|
-
*
|
|
1568
|
-
*
|
|
1569
|
-
*
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1573
|
-
*
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1577
|
-
*
|
|
1578
|
-
*
|
|
1579
|
-
*
|
|
1580
|
-
*
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
*
|
|
1574
|
+
* - Hybrid with both Canvas2D and WebGL available
|
|
1575
|
+
* - Super fast tile sheet rendering with WebGL
|
|
1576
|
+
* - Can apply rotation, mirror, color and additive color
|
|
1577
|
+
* - Many useful utility functions
|
|
1578
|
+
*
|
|
1579
|
+
* LittleJS uses a hybrid rendering solution with the best of both Canvas2D and WebGL.
|
|
1580
|
+
* There are 3 canvas/contexts available to draw to...
|
|
1581
|
+
* mainCanvas - 2D background canvas, non WebGL stuff like tile layers are drawn here.
|
|
1582
|
+
* glCanvas - Used by the accelerated WebGL batch rendering system.
|
|
1583
|
+
* overlayCanvas - Another 2D canvas that appears on top of the other 2 canvases.
|
|
1584
|
+
*
|
|
1585
|
+
* The WebGL rendering system is very fast with some caveats...
|
|
1586
|
+
* - The default setup supports only 1 tile sheet, to support more call glCreateTexture and glSetTexture
|
|
1587
|
+
* - Switching blend modes (additive) or textures causes another draw call which is expensive in excess
|
|
1588
|
+
* - Group additive rendering together using renderOrder to mitigate this issue
|
|
1589
|
+
*
|
|
1590
|
+
* The LittleJS rendering solution is intentionally simple, feel free to adjust it for your needs!
|
|
1584
1591
|
* @namespace Draw
|
|
1585
1592
|
*/
|
|
1586
1593
|
|
|
@@ -1624,7 +1631,7 @@ let tileImageSize, tileImageFixBleed, drawCount;
|
|
|
1624
1631
|
* @param {Vector2} screenPos
|
|
1625
1632
|
* @return {Vector2}
|
|
1626
1633
|
* @memberof Draw */
|
|
1627
|
-
|
|
1634
|
+
function screenToWorld(screenPos)
|
|
1628
1635
|
{
|
|
1629
1636
|
ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
|
|
1630
1637
|
return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
|
|
@@ -1635,7 +1642,7 @@ const screenToWorld = (screenPos)=>
|
|
|
1635
1642
|
* @param {Vector2} worldPos
|
|
1636
1643
|
* @return {Vector2}
|
|
1637
1644
|
* @memberof Draw */
|
|
1638
|
-
|
|
1645
|
+
function worldToScreen(worldPos)
|
|
1639
1646
|
{
|
|
1640
1647
|
ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
|
|
1641
1648
|
return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
|
|
@@ -1844,9 +1851,9 @@ let engineFontImage;
|
|
|
1844
1851
|
|
|
1845
1852
|
/**
|
|
1846
1853
|
* Font Image Object - Draw text on a 2D canvas by using characters in an image
|
|
1847
|
-
*
|
|
1848
|
-
*
|
|
1849
|
-
*
|
|
1854
|
+
* - 96 characters (from space to tilde) are stored in an image
|
|
1855
|
+
* - Uses a default 8x8 font if none is supplied
|
|
1856
|
+
* - You can also use fonts from the main tile sheet
|
|
1850
1857
|
* @example
|
|
1851
1858
|
* // use built in font
|
|
1852
1859
|
* const font = new ImageFont;
|
|
@@ -1886,7 +1893,7 @@ class FontImage
|
|
|
1886
1893
|
{
|
|
1887
1894
|
const context = this.context;
|
|
1888
1895
|
context.save();
|
|
1889
|
-
context.imageSmoothingEnabled = !
|
|
1896
|
+
context.imageSmoothingEnabled = !canvasPixelated;
|
|
1890
1897
|
|
|
1891
1898
|
const size = this.tileSize;
|
|
1892
1899
|
const drawSize = size.add(this.paddingSize).scale(scale);
|
|
@@ -1932,7 +1939,7 @@ class FontImage
|
|
|
1932
1939
|
/** Returns true if fullscreen mode is active
|
|
1933
1940
|
* @return {Boolean}
|
|
1934
1941
|
* @memberof Draw */
|
|
1935
|
-
|
|
1942
|
+
function isFullscreen() { return document.fullscreenElement; }
|
|
1936
1943
|
|
|
1937
1944
|
/** Toggle fullsceen mode
|
|
1938
1945
|
* @memberof Draw */
|
|
@@ -1949,10 +1956,10 @@ function toggleFullscreen()
|
|
|
1949
1956
|
|
|
1950
1957
|
/**
|
|
1951
1958
|
* LittleJS Input System
|
|
1952
|
-
*
|
|
1953
|
-
*
|
|
1954
|
-
*
|
|
1955
|
-
*
|
|
1959
|
+
* - Tracks key down, pressed, and released
|
|
1960
|
+
* - Also tracks mouse buttons, position, and wheel
|
|
1961
|
+
* - Supports multiple gamepads
|
|
1962
|
+
* - Virtual gamepad for touch devices with touchGamepadSize
|
|
1956
1963
|
* @namespace Input
|
|
1957
1964
|
*/
|
|
1958
1965
|
|
|
@@ -1963,25 +1970,28 @@ function toggleFullscreen()
|
|
|
1963
1970
|
* @param {Number} [device=0]
|
|
1964
1971
|
* @return {Boolean}
|
|
1965
1972
|
* @memberof Input */
|
|
1966
|
-
|
|
1973
|
+
function keyIsDown(key, device=0)
|
|
1974
|
+
{ return inputData[device] && inputData[device][key] & 1; }
|
|
1967
1975
|
|
|
1968
1976
|
/** Returns true if device key was pressed this frame
|
|
1969
1977
|
* @param {Number} key
|
|
1970
1978
|
* @param {Number} [device=0]
|
|
1971
1979
|
* @return {Boolean}
|
|
1972
1980
|
* @memberof Input */
|
|
1973
|
-
|
|
1981
|
+
function keyWasPressed(key, device=0)
|
|
1982
|
+
{ return inputData[device] && inputData[device][key] & 2 ? 1 : 0; }
|
|
1974
1983
|
|
|
1975
1984
|
/** Returns true if device key was released this frame
|
|
1976
1985
|
* @param {Number} key
|
|
1977
1986
|
* @param {Number} [device=0]
|
|
1978
1987
|
* @return {Boolean}
|
|
1979
1988
|
* @memberof Input */
|
|
1980
|
-
|
|
1989
|
+
function keyWasReleased(key, device=0)
|
|
1990
|
+
{ return inputData[device] && inputData[device][key] & 4 ? 1 : 0; }
|
|
1981
1991
|
|
|
1982
1992
|
/** Clears all input
|
|
1983
1993
|
* @memberof Input */
|
|
1984
|
-
|
|
1994
|
+
function clearInput() { inputData = [[]]; }
|
|
1985
1995
|
|
|
1986
1996
|
/** Returns true if mouse button is down
|
|
1987
1997
|
* @function
|
|
@@ -2034,28 +2044,32 @@ let preventDefaultInput = 0;
|
|
|
2034
2044
|
* @param {Number} [gamepad=0]
|
|
2035
2045
|
* @return {Boolean}
|
|
2036
2046
|
* @memberof Input */
|
|
2037
|
-
|
|
2047
|
+
function gamepadIsDown(button, gamepad=0)
|
|
2048
|
+
{ return keyIsDown(button, gamepad+1); }
|
|
2038
2049
|
|
|
2039
2050
|
/** Returns true if gamepad button was pressed
|
|
2040
2051
|
* @param {Number} button
|
|
2041
2052
|
* @param {Number} [gamepad=0]
|
|
2042
2053
|
* @return {Boolean}
|
|
2043
2054
|
* @memberof Input */
|
|
2044
|
-
|
|
2055
|
+
function gamepadWasPressed(button, gamepad=0)
|
|
2056
|
+
{ return keyWasPressed(button, gamepad+1); }
|
|
2045
2057
|
|
|
2046
2058
|
/** Returns true if gamepad button was released
|
|
2047
2059
|
* @param {Number} button
|
|
2048
2060
|
* @param {Number} [gamepad=0]
|
|
2049
2061
|
* @return {Boolean}
|
|
2050
2062
|
* @memberof Input */
|
|
2051
|
-
|
|
2063
|
+
function gamepadWasReleased(button, gamepad=0)
|
|
2064
|
+
{ return keyWasReleased(button, gamepad+1); }
|
|
2052
2065
|
|
|
2053
2066
|
/** Returns gamepad stick value
|
|
2054
2067
|
* @param {Number} stick
|
|
2055
2068
|
* @param {Number} [gamepad=0]
|
|
2056
2069
|
* @return {Vector2}
|
|
2057
2070
|
* @memberof Input */
|
|
2058
|
-
|
|
2071
|
+
function gamepadStick(stick, gamepad=0)
|
|
2072
|
+
{ return stickData[gamepad] ? stickData[gamepad][stick] || vec2() : vec2(); }
|
|
2059
2073
|
|
|
2060
2074
|
///////////////////////////////////////////////////////////////////////////////
|
|
2061
2075
|
// Input update called by engine
|
|
@@ -2094,12 +2108,18 @@ onkeydown = (e)=>
|
|
|
2094
2108
|
e.repeat || (inputData[isUsingGamepad = 0][remapKey(e.which)] = 3);
|
|
2095
2109
|
preventDefaultInput && e.preventDefault();
|
|
2096
2110
|
}
|
|
2111
|
+
|
|
2097
2112
|
onkeyup = (e)=>
|
|
2098
2113
|
{
|
|
2099
2114
|
if (debug && e.target != document.body) return;
|
|
2100
2115
|
inputData[0][remapKey(e.which)] = 4;
|
|
2101
2116
|
}
|
|
2102
|
-
|
|
2117
|
+
|
|
2118
|
+
function remapKey(c)
|
|
2119
|
+
{
|
|
2120
|
+
return inputWASDEmulateDirection ?
|
|
2121
|
+
c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
|
|
2122
|
+
}
|
|
2103
2123
|
|
|
2104
2124
|
///////////////////////////////////////////////////////////////////////////////
|
|
2105
2125
|
// Mouse event handlers
|
|
@@ -2108,10 +2128,10 @@ onmousedown = (e)=> {inputData[isUsingGamepad = 0][e.button] = 3; onmousemove(e)
|
|
|
2108
2128
|
onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
|
|
2109
2129
|
onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
|
|
2110
2130
|
onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
|
|
2111
|
-
oncontextmenu = (e)=>
|
|
2131
|
+
oncontextmenu = (e)=> false; // prevent right click menu
|
|
2112
2132
|
|
|
2113
2133
|
// convert a mouse or touch event position to screen space
|
|
2114
|
-
|
|
2134
|
+
function mouseToScreen(mousePos)
|
|
2115
2135
|
{
|
|
2116
2136
|
if (!mainCanvas)
|
|
2117
2137
|
return vec2(); // fix bug that can occur if user clicks before page loads
|
|
@@ -2157,8 +2177,7 @@ function gamepadsUpdate()
|
|
|
2157
2177
|
if (gamepad)
|
|
2158
2178
|
{
|
|
2159
2179
|
// read clamp dead zone of analog sticks
|
|
2160
|
-
const deadZone = .3, deadZoneMax = .8
|
|
2161
|
-
const applyDeadZone = (v)=>
|
|
2180
|
+
const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
|
|
2162
2181
|
v > deadZone ? percent( v, deadZone, deadZoneMax) :
|
|
2163
2182
|
v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
|
|
2164
2183
|
|
|
@@ -2191,11 +2210,12 @@ function gamepadsUpdate()
|
|
|
2191
2210
|
/** Pulse the vibration hardware if it exists
|
|
2192
2211
|
* @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
|
|
2193
2212
|
* @memberof Input */
|
|
2194
|
-
|
|
2213
|
+
function vibrate(pattern)
|
|
2214
|
+
{ vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern); }
|
|
2195
2215
|
|
|
2196
2216
|
/** Cancel any ongoing vibration
|
|
2197
2217
|
* @memberof Input */
|
|
2198
|
-
|
|
2218
|
+
function vibrateStop() { vibrate(0); }
|
|
2199
2219
|
|
|
2200
2220
|
///////////////////////////////////////////////////////////////////////////////
|
|
2201
2221
|
// Touch input
|
|
@@ -2380,20 +2400,21 @@ function touchGamepadRender()
|
|
|
2380
2400
|
}
|
|
2381
2401
|
/**
|
|
2382
2402
|
* LittleJS Audio System
|
|
2383
|
-
*
|
|
2384
|
-
*
|
|
2385
|
-
*
|
|
2386
|
-
*
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2403
|
+
* - <a href=https://killedbyapixel.github.io/ZzFX/>ZzFX Sound Effects</a> - Sound Effect Generator
|
|
2404
|
+
* - <a href=https://keithclark.github.io/ZzFXM/>ZzFXM Music</a> - Music System
|
|
2405
|
+
* - Caches sounds and music for fast playback
|
|
2406
|
+
* - Can attenuate and apply stereo panning to sounds
|
|
2407
|
+
* - Ability to play mp3, ogg, and wave files
|
|
2408
|
+
* - Speech synthesis wrapper functions
|
|
2409
|
+
* @namespace Audio
|
|
2389
2410
|
*/
|
|
2390
2411
|
|
|
2391
2412
|
'use strict';
|
|
2392
2413
|
|
|
2393
2414
|
/**
|
|
2394
2415
|
* Sound Object - Stores a zzfx sound for later use and can be played positionally
|
|
2395
|
-
*
|
|
2396
|
-
* <
|
|
2416
|
+
*
|
|
2417
|
+
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
2397
2418
|
* @example
|
|
2398
2419
|
* // create a sound
|
|
2399
2420
|
* const sound_example = new Sound([.5,.5]);
|
|
@@ -2477,8 +2498,8 @@ class Sound
|
|
|
2477
2498
|
|
|
2478
2499
|
/**
|
|
2479
2500
|
* Music Object - Stores a zzfx music track for later use
|
|
2480
|
-
*
|
|
2481
|
-
* <
|
|
2501
|
+
*
|
|
2502
|
+
* <a href=https://keithclark.github.io/ZzFXM/>Create music with the ZzFXM tracker.</a>
|
|
2482
2503
|
* @example
|
|
2483
2504
|
* // create some music
|
|
2484
2505
|
* const music_example = new Music(
|
|
@@ -2588,14 +2609,15 @@ function speak(text, language='', volume=1, rate=1, pitch=1)
|
|
|
2588
2609
|
|
|
2589
2610
|
/** Stop all queued speech
|
|
2590
2611
|
* @memberof Audio */
|
|
2591
|
-
|
|
2612
|
+
function speakStop() {speechSynthesis && speechSynthesis.cancel();}
|
|
2592
2613
|
|
|
2593
2614
|
/** Get frequency of a note on a musical scale
|
|
2594
2615
|
* @param {Number} semitoneOffset - How many semitones away from the root note
|
|
2595
2616
|
* @param {Number} [rootNoteFrequency=220] - Frequency at semitone offset 0
|
|
2596
2617
|
* @return {Number} - The frequency of the note
|
|
2597
2618
|
* @memberof Audio */
|
|
2598
|
-
|
|
2619
|
+
function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
2620
|
+
{ return rootFrequency * 2**(semitoneOffset/12); }
|
|
2599
2621
|
|
|
2600
2622
|
///////////////////////////////////////////////////////////////////////////////
|
|
2601
2623
|
|
|
@@ -2653,12 +2675,12 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
2653
2675
|
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force
|
|
2654
2676
|
|
|
2655
2677
|
/** Generate and play a ZzFX sound
|
|
2656
|
-
*
|
|
2657
|
-
* <
|
|
2678
|
+
*
|
|
2679
|
+
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
2658
2680
|
* @param {Array} zzfxSound - Array of ZzFX parameters, ex. [.5,.5]
|
|
2659
|
-
* @return {
|
|
2681
|
+
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
2660
2682
|
* @memberof Audio */
|
|
2661
|
-
|
|
2683
|
+
function zzfx(...zzfxSound) { return playSamples([zzfxG(...zzfxSound)]); }
|
|
2662
2684
|
|
|
2663
2685
|
/** Sample rate used for all ZzFX sounds
|
|
2664
2686
|
* @default 44100
|
|
@@ -2666,7 +2688,29 @@ const zzfx = (...zzfxSound) => playSamples([zzfxG(...zzfxSound)]);
|
|
|
2666
2688
|
const zzfxR = 44100;
|
|
2667
2689
|
|
|
2668
2690
|
/** Generate samples for a ZzFX sound
|
|
2669
|
-
* @
|
|
2691
|
+
* @param {Number} [volume=1] - Volume scale (percent)
|
|
2692
|
+
* @param {Number} [randomness=.05] - How much to randomize frequency (percent Hz)
|
|
2693
|
+
* @param {Number} [frequency=220] - Frequency of sound (Hz)
|
|
2694
|
+
* @param {Number} [attack=0] - Attack time, how fast sound starts (seconds)
|
|
2695
|
+
* @param {Number} [sustain=0] - Sustain time, how long sound holds (seconds)
|
|
2696
|
+
* @param {Number} [release=.1] - Release time, how fast sound fades out (seconds)
|
|
2697
|
+
* @param {Number} [shape=0] - Shape of the sound wave
|
|
2698
|
+
* @param {Number} [shapeCurve=1] - Squarenes of wave (0=square, 1=normal, 2=pointy)
|
|
2699
|
+
* @param {Number} [slide=0] - How much to slide frequency (kHz/s)
|
|
2700
|
+
* @param {Number} [deltaSlide=0] - How much to change slide (kHz/s/s)
|
|
2701
|
+
* @param {Number} [pitchJump=0] - Frequency of pitch jump (Hz)
|
|
2702
|
+
* @param {Number} [pitchJumpTime=0] - Time of pitch jump (seconds)
|
|
2703
|
+
* @param {Number} [repeatTime=0] - Resets some parameters periodically (seconds)
|
|
2704
|
+
* @param {Number} [noise=0] - How much random noise to add (percent)
|
|
2705
|
+
* @param {Number} [modulation=0] - Frequency of modulation wave, negative flips phase (Hz)
|
|
2706
|
+
* @param {Number} [bitCrush=0] - Resamples at a lower frequency in (samples*100)
|
|
2707
|
+
* @param {Number} [delay=0] - Overlap sound with itself for reverb and flanger effects (seconds)
|
|
2708
|
+
* @param {Number} [sustainVolume=1] - Volume level for sustain (percent)
|
|
2709
|
+
* @param {Number} [decay=0] - Decay time, how long to reach sustain after attack (seconds)
|
|
2710
|
+
* @param {Number} [tremolo=0] - Trembling effect, rate controlled by repeat time (precent)
|
|
2711
|
+
* @return {Array} - Array of audio samples
|
|
2712
|
+
* @memberof Audio
|
|
2713
|
+
*/
|
|
2670
2714
|
function zzfxG
|
|
2671
2715
|
(
|
|
2672
2716
|
// parameters
|
|
@@ -2756,7 +2800,7 @@ function zzfxG
|
|
|
2756
2800
|
* @param {Array} patterns - Array of pattern data
|
|
2757
2801
|
* @param {Array} sequence - Array of pattern indexes
|
|
2758
2802
|
* @param {Number} [BPM=125] - Playback speed of the song in BPM
|
|
2759
|
-
* @
|
|
2803
|
+
* @return {Array} - Left and right channel sample data
|
|
2760
2804
|
* @memberof Audio */
|
|
2761
2805
|
function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
2762
2806
|
{
|
|
@@ -2854,13 +2898,13 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
2854
2898
|
}
|
|
2855
2899
|
/**
|
|
2856
2900
|
* LittleJS Tile Layer System
|
|
2857
|
-
*
|
|
2858
|
-
*
|
|
2859
|
-
*
|
|
2860
|
-
*
|
|
2861
|
-
*
|
|
2862
|
-
*
|
|
2863
|
-
*
|
|
2901
|
+
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
2902
|
+
* - Unlimted numbers of layers, allocates canvases as needed
|
|
2903
|
+
* - Interfaces with EngineObject for collision
|
|
2904
|
+
* - Collision layer is separate from visible layers
|
|
2905
|
+
* - It is recommended to have a visible layer that matches the collision
|
|
2906
|
+
* - Tile layers can be drawn to using their context with canvas2d
|
|
2907
|
+
* - Drawn directly to the main canvas without using WebGL
|
|
2864
2908
|
* @namespace TileCollision
|
|
2865
2909
|
*/
|
|
2866
2910
|
|
|
@@ -2891,15 +2935,19 @@ function initTileCollision(size)
|
|
|
2891
2935
|
* @param {Vector2} pos
|
|
2892
2936
|
* @param {Number} [data=0]
|
|
2893
2937
|
* @memberof TileCollision */
|
|
2894
|
-
|
|
2938
|
+
function setTileCollisionData(pos, data=0)
|
|
2939
|
+
{
|
|
2895
2940
|
pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
|
|
2941
|
+
}
|
|
2896
2942
|
|
|
2897
2943
|
/** Get tile collision data
|
|
2898
2944
|
* @param {Vector2} pos
|
|
2899
2945
|
* @return {Number}
|
|
2900
2946
|
* @memberof TileCollision */
|
|
2901
|
-
|
|
2902
|
-
|
|
2947
|
+
function getTileCollisionData(pos)
|
|
2948
|
+
{
|
|
2949
|
+
return pos.arrayCheck(tileCollisionSize) ? tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] : 0;
|
|
2950
|
+
}
|
|
2903
2951
|
|
|
2904
2952
|
/** Check if collision with another object should occur
|
|
2905
2953
|
* @param {Vector2} pos
|
|
@@ -2993,10 +3041,10 @@ class TileLayerData
|
|
|
2993
3041
|
|
|
2994
3042
|
/**
|
|
2995
3043
|
* Tile layer object - cached rendering system for tile layers
|
|
2996
|
-
*
|
|
2997
|
-
*
|
|
2998
|
-
*
|
|
2999
|
-
*
|
|
3044
|
+
* - Each Tile layer is rendered to an off screen canvas
|
|
3045
|
+
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
3046
|
+
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
3047
|
+
* - So with 16x16 tiles this limits layers to 256x256 on mobile devices
|
|
3000
3048
|
* @extends EngineObject
|
|
3001
3049
|
* @example
|
|
3002
3050
|
* // create tile collision and visible tile layer
|
|
@@ -3196,12 +3244,9 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3196
3244
|
drawRect(pos, size, color, angle)
|
|
3197
3245
|
{ this.drawTile(pos, size, -1, 0, color, angle); }
|
|
3198
3246
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
- Updates particle physics
|
|
3203
|
-
- Fast particle rendering
|
|
3204
|
-
*/
|
|
3247
|
+
/**
|
|
3248
|
+
* LittleJS Particle System
|
|
3249
|
+
*/
|
|
3205
3250
|
|
|
3206
3251
|
'use strict';
|
|
3207
3252
|
|
|
@@ -3507,9 +3552,9 @@ class Particle extends EngineObject
|
|
|
3507
3552
|
}
|
|
3508
3553
|
/**
|
|
3509
3554
|
* LittleJS Medal System
|
|
3510
|
-
*
|
|
3511
|
-
*
|
|
3512
|
-
*
|
|
3555
|
+
* - Tracks and displays medals
|
|
3556
|
+
* - Saves medals to local storage
|
|
3557
|
+
* - Newgrounds integration
|
|
3513
3558
|
* @namespace Medals
|
|
3514
3559
|
*/
|
|
3515
3560
|
|
|
@@ -3526,8 +3571,8 @@ let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
|
3526
3571
|
///////////////////////////////////////////////////////////////////////////////
|
|
3527
3572
|
|
|
3528
3573
|
/** Initialize medals with a save name used for storage
|
|
3529
|
-
*
|
|
3530
|
-
*
|
|
3574
|
+
* - Call this after creating all medals
|
|
3575
|
+
* - Checks if medals are unlocked
|
|
3531
3576
|
* @param {String} saveName
|
|
3532
3577
|
* @memberof Medals */
|
|
3533
3578
|
function medalsInit(saveName)
|
|
@@ -3797,20 +3842,43 @@ class Newgrounds
|
|
|
3797
3842
|
CryptoJS()
|
|
3798
3843
|
{
|
|
3799
3844
|
///////////////////////////////////////////////////////////////////////////////
|
|
3800
|
-
// Crypto-JS - https://github.com/brix/crypto-js
|
|
3801
|
-
//
|
|
3802
|
-
|
|
3845
|
+
// Crypto-JS - https://github.com/brix/crypto-js - MIT License
|
|
3846
|
+
//
|
|
3847
|
+
// [The MIT License (MIT)](http://opensource.org/licenses/MIT)
|
|
3848
|
+
//
|
|
3849
|
+
// Copyright (c) 2009-2013 Jeff Mott
|
|
3850
|
+
// Copyright (c) 2013-2016 Evan Vosberg
|
|
3851
|
+
//
|
|
3852
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
3853
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
3854
|
+
// in the Software without restriction, including without limitation the rights
|
|
3855
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
3856
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
3857
|
+
// furnished to do so, subject to the following conditions:
|
|
3858
|
+
//
|
|
3859
|
+
// The above copyright notice and this permission notice shall be included in
|
|
3860
|
+
// all copies or substantial portions of the Software.
|
|
3861
|
+
//
|
|
3862
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
3863
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
3864
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
3865
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
3866
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
3867
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
3868
|
+
// THE SOFTWARE.
|
|
3803
3869
|
return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",...']charCodeAtUinyxpf',"for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],1<<17,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(1<<15),new Uint8Array(51e6),0,0,0,0));
|
|
3870
|
+
// end of Crypto-JS
|
|
3871
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
3804
3872
|
}
|
|
3805
3873
|
}
|
|
3806
3874
|
/**
|
|
3807
3875
|
* LittleJS WebGL Interface
|
|
3808
|
-
*
|
|
3809
|
-
*
|
|
3810
|
-
*
|
|
3811
|
-
*
|
|
3812
|
-
*
|
|
3813
|
-
*
|
|
3876
|
+
* - All webgl used by the engine is wrapped up here
|
|
3877
|
+
* - For normal stuff you won't need to see or call anything in this file
|
|
3878
|
+
* - For advanced stuff there are helper functions to create shaders, textures, etc
|
|
3879
|
+
* - Can be disabled with glEnable to revert to 2D canvas rendering
|
|
3880
|
+
* - Batches sprite rendering on GPU for incredibly fast performance
|
|
3881
|
+
* - Sprite transform math is done in the shader where possible
|
|
3814
3882
|
* @namespace WebGL
|
|
3815
3883
|
*/
|
|
3816
3884
|
|
|
@@ -3885,7 +3953,7 @@ function glSetBlendMode(additive)
|
|
|
3885
3953
|
}
|
|
3886
3954
|
|
|
3887
3955
|
/** Set the WebGl texture, not normally necessary unless multiple tile sheets are used
|
|
3888
|
-
*
|
|
3956
|
+
* - This may also flush the gl buffer resulting in more draw calls and worse performance
|
|
3889
3957
|
* @param {WebGLTexture} [texture=glTileTexture]
|
|
3890
3958
|
* @memberof WebGL */
|
|
3891
3959
|
function glSetTexture(texture=glTileTexture)
|
|
@@ -3946,7 +4014,7 @@ function glCreateTexture(image)
|
|
|
3946
4014
|
image && image.width && glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
3947
4015
|
|
|
3948
4016
|
// use point filtering for pixelated rendering
|
|
3949
|
-
const filter =
|
|
4017
|
+
const filter = canvasPixelated ? gl_NEAREST : gl_LINEAR;
|
|
3950
4018
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
|
|
3951
4019
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
|
|
3952
4020
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE);
|