littlejsengine 1.6.0 → 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.
Files changed (56) hide show
  1. package/README.md +138 -34
  2. package/build/littlejs.d.ts +104 -92
  3. package/build/littlejs.esm.js +414 -342
  4. package/build/littlejs.esm.min.js +1 -1
  5. package/build/littlejs.js +365 -296
  6. package/build/littlejs.min.js +1 -1
  7. package/build/littlejs.release.js +359 -291
  8. package/examples/breakout/game.js +5 -0
  9. package/examples/breakout/gameObjects.js +41 -48
  10. package/examples/breakout/index.html +3 -3
  11. package/examples/breakoutTutorial/README.md +514 -0
  12. package/examples/breakoutTutorial/game.js +181 -0
  13. package/examples/breakoutTutorial/images/1.png +0 -0
  14. package/examples/breakoutTutorial/images/10.png +0 -0
  15. package/examples/breakoutTutorial/images/11.png +0 -0
  16. package/examples/breakoutTutorial/images/2.png +0 -0
  17. package/examples/breakoutTutorial/images/3.png +0 -0
  18. package/examples/breakoutTutorial/images/4.png +0 -0
  19. package/examples/breakoutTutorial/images/5.png +0 -0
  20. package/examples/breakoutTutorial/images/6.png +0 -0
  21. package/examples/breakoutTutorial/images/7.png +0 -0
  22. package/examples/breakoutTutorial/images/8.png +0 -0
  23. package/examples/breakoutTutorial/images/9.png +0 -0
  24. package/examples/breakoutTutorial/index.html +10 -0
  25. package/examples/empty/game.js +10 -0
  26. package/examples/favicon.png +0 -0
  27. package/examples/module/index.html +1 -1
  28. package/examples/particles/index.html +1 -1
  29. package/examples/platformer/gameLevel.js +1 -1
  30. package/examples/platformer/gamePlayer.js +1 -1
  31. package/examples/platformer/index.html +6 -6
  32. package/examples/puzzle/game.js +1 -1
  33. package/examples/puzzle/index.html +2 -2
  34. package/examples/starter/build.bat +3 -2
  35. package/examples/starter/game.js +9 -9
  36. package/examples/starter/index.html +13 -13
  37. package/examples/stress/index.html +1 -1
  38. package/examples/typescript/game.js +89 -89
  39. package/examples/typescript/game.ts +10 -10
  40. package/examples/typescript/index.html +1 -1
  41. package/package.json +4 -4
  42. package/src/engine.js +29 -31
  43. package/src/engineAudio.js +53 -29
  44. package/src/engineBuild.bat +3 -1
  45. package/src/engineDebug.js +25 -24
  46. package/src/engineDraw.js +43 -39
  47. package/src/engineExport.js +49 -46
  48. package/src/engineInput.js +83 -74
  49. package/src/engineMedals.js +31 -8
  50. package/src/engineObject.js +25 -25
  51. package/src/engineParticles.js +3 -6
  52. package/src/engineRelease.js +19 -19
  53. package/src/engineSettings.js +4 -4
  54. package/src/engineTileLayer.js +18 -14
  55. package/src/engineUtilities.js +43 -34
  56. package/src/engineWebGL.js +8 -8
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * LittleJS Input System
3
- * <br> - Tracks key down, pressed, and released
4
- * <br> - Also tracks mouse buttons, position, and wheel
5
- * <br> - Supports multiple gamepads
6
- * <br> - Virtual gamepad for touch devices with touchGamepadSize
3
+ * - Tracks key down, pressed, and released
4
+ * - Also tracks mouse buttons, position, and wheel
5
+ * - Supports multiple gamepads
6
+ * - Virtual gamepad for touch devices with touchGamepadSize
7
7
  * @namespace Input
8
8
  */
9
9
 
@@ -14,25 +14,28 @@
14
14
  * @param {Number} [device=0]
15
15
  * @return {Boolean}
16
16
  * @memberof Input */
17
- const keyIsDown = (key, device=0)=> inputData[device] && inputData[device][key] & 1;
17
+ function keyIsDown(key, device=0)
18
+ { return inputData[device] && inputData[device][key] & 1; }
18
19
 
19
20
  /** Returns true if device key was pressed this frame
20
21
  * @param {Number} key
21
22
  * @param {Number} [device=0]
22
23
  * @return {Boolean}
23
24
  * @memberof Input */
24
- const keyWasPressed = (key, device=0)=> inputData[device] && inputData[device][key] & 2 ? 1 : 0;
25
+ function keyWasPressed(key, device=0)
26
+ { return inputData[device] && inputData[device][key] & 2 ? 1 : 0; }
25
27
 
26
28
  /** Returns true if device key was released this frame
27
29
  * @param {Number} key
28
30
  * @param {Number} [device=0]
29
31
  * @return {Boolean}
30
32
  * @memberof Input */
31
- const keyWasReleased = (key, device=0)=> inputData[device] && inputData[device][key] & 4 ? 1 : 0;
33
+ function keyWasReleased(key, device=0)
34
+ { return inputData[device] && inputData[device][key] & 4 ? 1 : 0; }
32
35
 
33
36
  /** Clears all input
34
37
  * @memberof Input */
35
- const clearInput = ()=> inputData = [[]];
38
+ function clearInput() { inputData = [[]]; }
36
39
 
37
40
  /** Returns true if mouse button is down
38
41
  * @function
@@ -85,28 +88,32 @@ let preventDefaultInput = 0;
85
88
  * @param {Number} [gamepad=0]
86
89
  * @return {Boolean}
87
90
  * @memberof Input */
88
- const gamepadIsDown = (button, gamepad=0)=> keyIsDown(button, gamepad+1);
91
+ function gamepadIsDown(button, gamepad=0)
92
+ { return keyIsDown(button, gamepad+1); }
89
93
 
90
94
  /** Returns true if gamepad button was pressed
91
95
  * @param {Number} button
92
96
  * @param {Number} [gamepad=0]
93
97
  * @return {Boolean}
94
98
  * @memberof Input */
95
- const gamepadWasPressed = (button, gamepad=0)=> keyWasPressed(button, gamepad+1);
99
+ function gamepadWasPressed(button, gamepad=0)
100
+ { return keyWasPressed(button, gamepad+1); }
96
101
 
97
102
  /** Returns true if gamepad button was released
98
103
  * @param {Number} button
99
104
  * @param {Number} [gamepad=0]
100
105
  * @return {Boolean}
101
106
  * @memberof Input */
102
- const gamepadWasReleased = (button, gamepad=0)=> keyWasReleased(button, gamepad+1);
107
+ function gamepadWasReleased(button, gamepad=0)
108
+ { return keyWasReleased(button, gamepad+1); }
103
109
 
104
110
  /** Returns gamepad stick value
105
111
  * @param {Number} stick
106
112
  * @param {Number} [gamepad=0]
107
113
  * @return {Vector2}
108
114
  * @memberof Input */
109
- const gamepadStick = (stick, gamepad=0)=> stickData[gamepad] ? stickData[gamepad][stick] || vec2() : vec2();
115
+ function gamepadStick(stick, gamepad=0)
116
+ { return stickData[gamepad] ? stickData[gamepad][stick] || vec2() : vec2(); }
110
117
 
111
118
  ///////////////////////////////////////////////////////////////////////////////
112
119
  // Input update called by engine
@@ -145,12 +152,18 @@ onkeydown = (e)=>
145
152
  e.repeat || (inputData[isUsingGamepad = 0][remapKey(e.which)] = 3);
146
153
  preventDefaultInput && e.preventDefault();
147
154
  }
155
+
148
156
  onkeyup = (e)=>
149
157
  {
150
158
  if (debug && e.target != document.body) return;
151
159
  inputData[0][remapKey(e.which)] = 4;
152
160
  }
153
- const remapKey = (c)=> inputWASDEmulateDirection ? c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
161
+
162
+ function remapKey(c)
163
+ {
164
+ return inputWASDEmulateDirection ?
165
+ c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
166
+ }
154
167
 
155
168
  ///////////////////////////////////////////////////////////////////////////////
156
169
  // Mouse event handlers
@@ -159,10 +172,10 @@ onmousedown = (e)=> {inputData[isUsingGamepad = 0][e.button] = 3; onmousemove(e)
159
172
  onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
160
173
  onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
161
174
  onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
162
- oncontextmenu = (e)=> !1; // prevent right click menu
175
+ oncontextmenu = (e)=> false; // prevent right click menu
163
176
 
164
177
  // convert a mouse or touch event position to screen space
165
- const mouseToScreen = (mousePos)=>
178
+ function mouseToScreen(mousePos)
166
179
  {
167
180
  if (!mainCanvas)
168
181
  return vec2(); // fix bug that can occur if user clicks before page loads
@@ -208,8 +221,7 @@ function gamepadsUpdate()
208
221
  if (gamepad)
209
222
  {
210
223
  // read clamp dead zone of analog sticks
211
- const deadZone = .3, deadZoneMax = .8;
212
- const applyDeadZone = (v)=>
224
+ const deadZone = .3, deadZoneMax = .8, applyDeadZone = (v)=>
213
225
  v > deadZone ? percent( v, deadZone, deadZoneMax) :
214
226
  v < -deadZone ? -percent(-v, deadZone, deadZoneMax) : 0;
215
227
 
@@ -242,11 +254,12 @@ function gamepadsUpdate()
242
254
  /** Pulse the vibration hardware if it exists
243
255
  * @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
244
256
  * @memberof Input */
245
- const vibrate = (pattern)=> vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern);
257
+ function vibrate(pattern)
258
+ { vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern); }
246
259
 
247
260
  /** Cancel any ongoing vibration
248
261
  * @memberof Input */
249
- const vibrateStop = ()=> vibrate(0);
262
+ function vibrateStop() { vibrate(0); }
250
263
 
251
264
  ///////////////////////////////////////////////////////////////////////////////
252
265
  // Touch input
@@ -292,6 +305,9 @@ if (isTouchDevice)
292
305
  return true;
293
306
  }
294
307
 
308
+ // try to create touch game pad
309
+ touchGamepadEnable && touchGamepadCreate();
310
+
295
311
  return ontouchstart(e);
296
312
  }
297
313
  }
@@ -305,76 +321,69 @@ let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
305
321
  // create the touch gamepad, called automatically by the engine
306
322
  function touchGamepadCreate()
307
323
  {
308
- if (!touchGamepadEnable || !isTouchDevice)
309
- return;
310
-
311
324
  // touch input internal variables
312
325
  touchGamepadButtons = [];
313
326
  touchGamepadStick = vec2();
314
327
 
315
- // setup touch input
316
- ontouchstart = (e)=>
328
+ let touchHandler = ontouchstart;
329
+ ontouchstart = ontouchmove = ontouchend = (e)=>
317
330
  {
318
- // fix mobile audio, force it to play a sound on first touch
319
- zzfx(0);
320
-
321
- ontouchstart = ontouchmove = ontouchend = (e)=>
331
+ // clear touch gamepad input
332
+ touchGamepadStick = vec2();
333
+ touchGamepadButtons = [];
334
+
335
+ const touching = e.touches.length;
336
+ if (touching)
322
337
  {
323
- // clear touch gamepad input
324
- touchGamepadStick = vec2();
325
- touchGamepadButtons = [];
326
-
327
- const touching = e.touches.length;
328
- if (touching)
338
+ touchGamepadTimer.set();
339
+ if (paused)
329
340
  {
330
- // set that gamepad is active
331
- isUsingGamepad = 1;
332
- touchGamepadTimer.set();
333
-
334
- if (paused)
335
- {
336
- // touch anywhere to press start when paused
337
- touchGamepadButtons[9] = 1;
338
- return;
339
- }
341
+ // touch anywhere to press start when paused
342
+ touchGamepadButtons[9] = 1;
343
+ return;
340
344
  }
345
+ }
341
346
 
342
- // get center of left and right sides
343
- const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
344
- const buttonCenter = mainCanvasSize.subtract(vec2(touchGamepadSize, touchGamepadSize));
345
- const startCenter = mainCanvasSize.scale(.5);
347
+ // get center of left and right sides
348
+ const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
349
+ const buttonCenter = mainCanvasSize.subtract(vec2(touchGamepadSize, touchGamepadSize));
350
+ const startCenter = mainCanvasSize.scale(.5);
346
351
 
347
- // check each touch point
348
- for (const touch of e.touches)
352
+ // check each touch point
353
+ for (const touch of e.touches)
354
+ {
355
+ const touchPos = mouseToScreen(vec2(touch.clientX, touch.clientY));
356
+ if (touchPos.distance(stickCenter) < touchGamepadSize)
349
357
  {
350
- const touchPos = mouseToScreen(vec2(touch.clientX, touch.clientY));
351
- if (touchPos.distance(stickCenter) < touchGamepadSize)
352
- {
353
- // virtual analog stick
354
- if (touchGamepadAnalog)
355
- touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
356
- else
357
- {
358
- // 8 way dpad
359
- const angle = touchPos.subtract(stickCenter).angle();
360
- touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
361
- }
362
- }
363
- else if (touchPos.distance(buttonCenter) < touchGamepadSize)
358
+ // virtual analog stick
359
+ if (touchGamepadAnalog)
360
+ touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
361
+ else
364
362
  {
365
- // virtual face buttons
366
- const button = touchPos.subtract(buttonCenter).direction();
367
- touchGamepadButtons[button] = 1;
368
- }
369
- else if (touchPos.distance(startCenter) < touchGamepadSize)
370
- {
371
- // virtual start button in center
372
- touchGamepadButtons[9] = 1;
363
+ // 8 way dpad
364
+ const angle = touchPos.subtract(stickCenter).angle();
365
+ touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
373
366
  }
374
367
  }
368
+ else if (touchPos.distance(buttonCenter) < touchGamepadSize)
369
+ {
370
+ // virtual face buttons
371
+ const button = touchPos.subtract(buttonCenter).direction();
372
+ touchGamepadButtons[button] = 1;
373
+ }
374
+ else if (touchPos.distance(startCenter) < touchGamepadSize)
375
+ {
376
+ // virtual start button in center
377
+ touchGamepadButtons[9] = 1;
378
+ }
375
379
  }
376
380
 
377
- return ontouchstart(e);
381
+ // call default touch handler and set to using gamepad
382
+ touchHandler(e);
383
+ isUsingGamepad = 1;
384
+
385
+ // must return true so the document will get focus
386
+ return true;
378
387
  }
379
388
  }
380
389
 
@@ -400,7 +409,7 @@ function touchGamepadRender()
400
409
  overlayContext.beginPath();
401
410
 
402
411
  const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
403
- if (touchGamepadAnalog)
412
+ if (touchGamepadAnalog) // draw circle shaped gamepad
404
413
  {
405
414
  overlayContext.arc(leftCenter.x, leftCenter.y, touchGamepadSize/2, 0, 9);
406
415
  overlayContext.fill();
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * LittleJS Medal System
3
- * <br> - Tracks and displays medals
4
- * <br> - Saves medals to local storage
5
- * <br> - Newgrounds integration
3
+ * - Tracks and displays medals
4
+ * - Saves medals to local storage
5
+ * - Newgrounds integration
6
6
  * @namespace Medals
7
7
  */
8
8
 
@@ -19,8 +19,8 @@ let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
19
19
  ///////////////////////////////////////////////////////////////////////////////
20
20
 
21
21
  /** Initialize medals with a save name used for storage
22
- * <br> - Call this after creating all medals
23
- * <br> - Checks if medals are unlocked
22
+ * - Call this after creating all medals
23
+ * - Checks if medals are unlocked
24
24
  * @param {String} saveName
25
25
  * @memberof Medals */
26
26
  function medalsInit(saveName)
@@ -290,9 +290,32 @@ class Newgrounds
290
290
  CryptoJS()
291
291
  {
292
292
  ///////////////////////////////////////////////////////////////////////////////
293
- // Crypto-JS - https://github.com/brix/crypto-js [The MIT License (MIT)]
294
- // Copyright (c) 2009-2013 Jeff Mott Copyright (c) 2013-2016 Evan Vosberg
295
-
293
+ // Crypto-JS - https://github.com/brix/crypto-js - MIT License
294
+ //
295
+ // [The MIT License (MIT)](http://opensource.org/licenses/MIT)
296
+ //
297
+ // Copyright (c) 2009-2013 Jeff Mott
298
+ // Copyright (c) 2013-2016 Evan Vosberg
299
+ //
300
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
301
+ // of this software and associated documentation files (the "Software"), to deal
302
+ // in the Software without restriction, including without limitation the rights
303
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
304
+ // copies of the Software, and to permit persons to whom the Software is
305
+ // furnished to do so, subject to the following conditions:
306
+ //
307
+ // The above copyright notice and this permission notice shall be included in
308
+ // all copies or substantial portions of the Software.
309
+ //
310
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
311
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
312
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
313
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
314
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
315
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
316
+ // THE SOFTWARE.
296
317
  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));
318
+ // end of Crypto-JS
319
+ ///////////////////////////////////////////////////////////////////////////////
297
320
  }
298
321
  }
@@ -1,29 +1,29 @@
1
- /*
2
- LittleJS Object System
3
- */
1
+ /**
2
+ * LittleJS Object System
3
+ */
4
4
 
5
5
  'use strict';
6
6
 
7
7
  /**
8
8
  * LittleJS Object Base Object Class
9
- * <br> - Base object class used by the engine
10
- * <br> - Automatically adds self to object list
11
- * <br> - Will be updated and rendered each frame
12
- * <br> - Renders as a sprite from a tilesheet by default
13
- * <br> - Can have color and addtive color applied
14
- * <br> - 2d Physics and collision system
15
- * <br> - Sorted by renderOrder
16
- * <br> - Objects can have children attached
17
- * <br> - Parents are updated before children, and set child transform
18
- * <br> - Call destroy() to get rid of objects
19
- * <br>
20
- * <br>The physics system used by objects is simple and fast with some caveats...
21
- * <br> - Collision uses the axis aligned size, the object's rotation angle is only for rendering
22
- * <br> - Objects are guaranteed to not intersect tile collision from physics
23
- * <br> - If an object starts or is moved inside tile collision, it will not collide with that tile
24
- * <br> - Collision for objects can be set to be solid to block other objects
25
- * <br> - Objects may get pushed into overlapping other solid objects, if so they will push away
26
- * <br> - Solid objects are more performance intensive and should be used sparingly
9
+ * - Base object class used by the engine
10
+ * - Automatically adds self to object list
11
+ * - Will be updated and rendered each frame
12
+ * - Renders as a sprite from a tilesheet by default
13
+ * - Can have color and addtive color applied
14
+ * - 2d Physics and collision system
15
+ * - Sorted by renderOrder
16
+ * - Objects can have children attached
17
+ * - Parents are updated before children, and set child transform
18
+ * - Call destroy() to get rid of objects
19
+ *
20
+ * The physics system used by objects is simple and fast with some caveats...
21
+ * - Collision uses the axis aligned size, the object's rotation angle is only for rendering
22
+ * - Objects are guaranteed to not intersect tile collision from physics
23
+ * - If an object starts or is moved inside tile collision, it will not collide with that tile
24
+ * - Collision for objects can be set to be solid to block other objects
25
+ * - Objects may get pushed into overlapping other solid objects, if so they will push away
26
+ * - Solid objects are more performance intensive and should be used sparingly
27
27
  * @example
28
28
  * // create an engine object, normally you would first extend the class with your own
29
29
  * const pos = vec2(2,3);
@@ -112,6 +112,7 @@ class EngineObject
112
112
  this.velocity.y += gravity * this.gravityScale;
113
113
  this.pos.x += this.velocity.x *= this.damping;
114
114
  this.pos.y += this.velocity.y *= this.damping;
115
+ this.angle += this.angleVelocity *= this.angleDamping;
115
116
 
116
117
  // physics sanity checks
117
118
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
@@ -168,6 +169,7 @@ class EngineObject
168
169
  const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity; // prefer to push up if small delta
169
170
  const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
170
171
  const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
172
+ const elasticity = max(this.elasticity, o.elasticity);
171
173
 
172
174
  if (smallStepUp | isBlockedY | !isBlockedX) // resolve y collision
173
175
  {
@@ -180,7 +182,7 @@ class EngineObject
180
182
  this.groundObject = o;
181
183
 
182
184
  // bounce if other object is fixed or grounded
183
- this.velocity.y *= -this.elasticity;
185
+ this.velocity.y *= -elasticity;
184
186
  }
185
187
  else if (o.mass)
186
188
  {
@@ -194,7 +196,6 @@ class EngineObject
194
196
  + this.velocity.y * 2 * this.mass / (this.mass + o.mass);
195
197
 
196
198
  // lerp betwen elastic or inelastic based on elasticity
197
- const elasticity = max(this.elasticity, o.elasticity);
198
199
  this.velocity.y = lerp(elasticity, inelastic, elastic0);
199
200
  o.velocity.y = lerp(elasticity, inelastic, elastic1);
200
201
  }
@@ -215,12 +216,11 @@ class EngineObject
215
216
  + this.velocity.x * 2 * this.mass / (this.mass + o.mass);
216
217
 
217
218
  // lerp betwen elastic or inelastic based on elasticity
218
- const elasticity = max(this.elasticity, o.elasticity);
219
219
  this.velocity.x = lerp(elasticity, inelastic, elastic0);
220
220
  o.velocity.x = lerp(elasticity, inelastic, elastic1);
221
221
  }
222
222
  else // bounce if other object is fixed
223
- this.velocity.x *= -this.elasticity;
223
+ this.velocity.x *= -elasticity;
224
224
  }
225
225
  debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
226
226
  }
@@ -1,9 +1,6 @@
1
- /*
2
- LittleJS Particle System
3
- - Spawns particles with randomness from parameters
4
- - Updates particle physics
5
- - Fast particle rendering
6
- */
1
+ /**
2
+ * LittleJS Particle System
3
+ */
7
4
 
8
5
  'use strict';
9
6
 
@@ -1,15 +1,15 @@
1
- /*
2
- LittleJS - Release Build
3
- MIT License - Copyright 2021 Frank Force
4
-
5
- - This file is used for release builds in place of engineDebug.js
6
- - Debug functionality will be disabled to lower size and increase performance
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
 
11
10
  let showWatermark = 0;
12
11
  let godMode = 0;
12
+ let debugKeyCode = 0;
13
13
  const debug = 0;
14
14
  const debugOverlay = 0;
15
15
  const debugPhysics = 0;
@@ -19,15 +19,15 @@ const debugGamepads = 0;
19
19
  const debugMedals = 0;
20
20
 
21
21
  // debug commands are automatically removed from the final build
22
- const ASSERT = ()=> {}
23
- const debugInit = ()=> {}
24
- const debugUpdate = ()=> {}
25
- const debugRender = ()=> {}
26
- const debugRect = ()=> {}
27
- const debugCircle = ()=> {}
28
- const debugPoint = ()=> {}
29
- const debugLine = ()=> {}
30
- const debugAABB = ()=> {}
31
- const debugText = ()=> {}
32
- const debugClear = ()=> {}
33
- const debugSaveCanvas = ()=> {}
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 (){}
@@ -36,11 +36,11 @@ let canvasMaxSize = vec2(1920, 1200);
36
36
  * @memberof Settings */
37
37
  let canvasFixedSize = vec2();
38
38
 
39
- /** Disables anti aliasing for pixel art if true
39
+ /** Disables filtering for crisper pixel art if true
40
40
  * @type {Boolean}
41
41
  * @default
42
42
  * @memberof Settings */
43
- let cavasPixelated = 1;
43
+ let canvasPixelated = 1;
44
44
 
45
45
  /** Default font used for text rendering
46
46
  * @type {String}
@@ -157,8 +157,8 @@ let gamepadDirectionEmulateStick = 1;
157
157
  let inputWASDEmulateDirection = 1;
158
158
 
159
159
  /** True if touch gamepad should appear on mobile devices
160
- * <br> - Supports left analog stick, 4 face buttons and start button (button 9)
161
- * <br> - Must be set by end of gameInit to be activated
160
+ * - Supports left analog stick, 4 face buttons and start button (button 9)
161
+ * - Must be set by end of gameInit to be activated
162
162
  * @type {Boolean}
163
163
  * @default 0
164
164
  * @memberof Settings */
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * LittleJS Tile Layer System
3
- * <br> - Caches arrays of tiles to off screen canvas for fast rendering
4
- * <br> - Unlimted numbers of layers, allocates canvases as needed
5
- * <br> - Interfaces with EngineObject for collision
6
- * <br> - Collision layer is separate from visible layers
7
- * <br> - It is recommended to have a visible layer that matches the collision
8
- * <br> - Tile layers can be drawn to using their context with canvas2d
9
- * <br> - Drawn directly to the main canvas without using WebGL
3
+ * - Caches arrays of tiles to off screen canvas for fast rendering
4
+ * - Unlimted numbers of layers, allocates canvases as needed
5
+ * - Interfaces with EngineObject for collision
6
+ * - Collision layer is separate from visible layers
7
+ * - It is recommended to have a visible layer that matches the collision
8
+ * - Tile layers can be drawn to using their context with canvas2d
9
+ * - Drawn directly to the main canvas without using WebGL
10
10
  * @namespace TileCollision
11
11
  */
12
12
 
@@ -37,15 +37,19 @@ function initTileCollision(size)
37
37
  * @param {Vector2} pos
38
38
  * @param {Number} [data=0]
39
39
  * @memberof TileCollision */
40
- const setTileCollisionData = (pos, data=0)=>
40
+ function setTileCollisionData(pos, data=0)
41
+ {
41
42
  pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
43
+ }
42
44
 
43
45
  /** Get tile collision data
44
46
  * @param {Vector2} pos
45
47
  * @return {Number}
46
48
  * @memberof TileCollision */
47
- const getTileCollisionData = (pos)=>
48
- pos.arrayCheck(tileCollisionSize) ? tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] : 0;
49
+ function getTileCollisionData(pos)
50
+ {
51
+ return pos.arrayCheck(tileCollisionSize) ? tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] : 0;
52
+ }
49
53
 
50
54
  /** Check if collision with another object should occur
51
55
  * @param {Vector2} pos
@@ -139,10 +143,10 @@ class TileLayerData
139
143
 
140
144
  /**
141
145
  * Tile layer object - cached rendering system for tile layers
142
- * <br> - Each Tile layer is rendered to an off screen canvas
143
- * <br> - To allow dynamic modifications, layers are rendered using canvas 2d
144
- * <br> - Some devices like mobile phones are limited to 4k texture resolution
145
- * <br> - So with 16x16 tiles this limits layers to 256x256 on mobile devices
146
+ * - Each Tile layer is rendered to an off screen canvas
147
+ * - To allow dynamic modifications, layers are rendered using canvas 2d
148
+ * - Some devices like mobile phones are limited to 4k texture resolution
149
+ * - So with 16x16 tiles this limits layers to 256x256 on mobile devices
146
150
  * @extends EngineObject
147
151
  * @example
148
152
  * // create tile collision and visible tile layer