littlejsengine 1.16.2 → 1.17.5

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 (57) hide show
  1. package/dist/littlejs.d.ts +291 -246
  2. package/dist/littlejs.esm.js +1520 -1271
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +1178 -920
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +1170 -912
  7. package/examples/box2d/gameObjects.js +4 -4
  8. package/examples/breakout/game.js +5 -6
  9. package/examples/electron/index.html +2 -2
  10. package/examples/electron/tiles.png +0 -0
  11. package/examples/htmlMenu/tiles.png +0 -0
  12. package/examples/index.html +9 -8
  13. package/examples/logo.png +0 -0
  14. package/examples/module/build.bat +7 -0
  15. package/examples/module/build.js +121 -0
  16. package/examples/module/tiles.png +0 -0
  17. package/examples/platformer/game.js +1 -1
  18. package/examples/platformer/gameEffects.js +25 -29
  19. package/examples/platformer/gameLevel.js +27 -28
  20. package/examples/puzzle/game.js +2 -2
  21. package/examples/shorts/base.html +4 -1
  22. package/examples/shorts/box2dPool.js +2 -2
  23. package/examples/shorts/box2dTileLayer.js +48 -0
  24. package/examples/shorts/clock.js +3 -3
  25. package/examples/shorts/fontImage.js +4 -3
  26. package/examples/shorts/music.js +2 -2
  27. package/examples/shorts/musicPlayer.js +2 -2
  28. package/examples/shorts/parallax.js +1 -1
  29. package/examples/shorts/sequencer.js +1 -1
  30. package/examples/shorts/shapes.js +1 -1
  31. package/examples/shorts/texture.js +10 -6
  32. package/examples/shorts/tiles.png +0 -0
  33. package/examples/shorts/tiltedView.js +2 -0
  34. package/examples/starter/index.html +2 -2
  35. package/examples/starter/tiles.png +0 -0
  36. package/examples/typescript/tiles.png +0 -0
  37. package/examples/uiSystem/game.js +1 -1
  38. package/examples/uiSystem/tiles.png +0 -0
  39. package/package.json +5 -5
  40. package/plugins/box2d.js +167 -63
  41. package/plugins/postProcess.js +47 -28
  42. package/plugins/uiSystem.js +18 -18
  43. package/plugins/zzfxm.js +2 -2
  44. package/reference.md +4 -3
  45. package/src/engine.js +182 -181
  46. package/src/engineAudio.js +47 -63
  47. package/src/engineDebug.js +8 -8
  48. package/src/engineDraw.js +184 -124
  49. package/src/engineExport.js +325 -334
  50. package/src/engineFont.png +0 -0
  51. package/src/engineInput.js +18 -24
  52. package/src/engineMath.js +24 -113
  53. package/src/engineObject.js +27 -26
  54. package/src/engineParticles.js +2 -2
  55. package/src/engineTileLayer.js +229 -192
  56. package/src/engineUtilities.js +100 -4
  57. package/src/engineWebGL.js +124 -73
@@ -44,29 +44,46 @@ function audioInit()
44
44
  ///////////////////////////////////////////////////////////////////////////////
45
45
 
46
46
  /**
47
- * Sound Object - Stores a sound for later use and can be played positionally
47
+ * Sound Object - Stores a sound for later
48
+ * - this can be used to load and play wave, mp3, and ogg files
49
+ * - it can also create sounds using the ZzFX sound generator
50
+ * - can attenuate and apply stereo panning to sounds
51
+ * - sound instance control with pause/resume capability
48
52
  *
49
53
  * <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
50
54
  * @memberof Audio
51
55
  * @example
52
- * // create a sound
56
+ * // load an audio asset file
57
+ * const sound_example = new Sound('sound.mp3');
58
+ *
59
+ * // create a zzfx sound
53
60
  * const sound_example = new Sound([.5,.5]);
54
61
  *
55
- * // play the sound
62
+ * // play a sound
56
63
  * sound_example.play();
57
64
  */
58
65
  class Sound
59
66
  {
60
- /** Create a sound object and cache the zzfx samples for later use
61
- * @param {Array} zzfxSound - Array of zzfx parameters, ex. [.5,.5]
67
+ /**
68
+ * @callback SoundLoadCallback - Function called when sound is loaded
69
+ * @param {Sound} sound
70
+ * @memberof Audio
71
+ */
72
+
73
+ /** Create a sound object and cache the audio for later use
74
+ * @param {string|Array} [asset] - Filename of audio file or zzfx array
75
+ * @param {number} [randomness] - How much to randomize frequency each time sound plays, for zzfx sounds the zzfx default is used if undefined
62
76
  * @param {number} [range=soundDefaultRange] - World space max range of sound
63
77
  * @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
78
+ * @param {SoundLoadCallback} [onloadCallback] - callback function to call when sound is loaded
64
79
  */
65
- constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
80
+ constructor(asset, randomness, range=soundDefaultRange, taper=soundDefaultTaper, onloadCallback)
66
81
  {
67
82
  if (!soundEnable || headlessMode) return;
68
83
 
69
- ASSERT(!zzfxSound || isArray(zzfxSound), 'zzfxSound is invalid');
84
+ ASSERT(!asset || isArray(asset) || isString(asset), 'asset must be a file name or zzfx array');
85
+ ASSERT(randomness === undefined || isNumber(randomness), 'randomness must be a number');
86
+ ASSERT(randomness === undefined || randomness >= 0 && randomness <=1, 'randomness must be between 0 and 1');
70
87
  ASSERT(isNumber(range), 'range must be a number');
71
88
  ASSERT(isNumber(taper), 'taper must be a number');
72
89
 
@@ -75,24 +92,35 @@ class Sound
75
92
  /** @property {number} - At what percentage of range should it start tapering */
76
93
  this.taper = taper;
77
94
  /** @property {number} - How much to randomize frequency each time sound plays */
78
- this.randomness = 0;
95
+ this.randomness = randomness ?? 0;
79
96
  /** @property {number} - Sample rate for this sound */
80
97
  this.sampleRate = audioDefaultSampleRate;
81
98
  /** @property {number} - Percentage of this sound currently loaded */
82
99
  this.loadedPercent = 0;
100
+ /** @property {SoundLoadCallback} - function to call when sound is loaded */
101
+ this.onloadCallback = onloadCallback;
83
102
 
84
- // generate zzfx sound now for fast playback
85
- if (zzfxSound)
103
+ if (Array.isArray(asset))
86
104
  {
105
+ // generate zzfx sound
106
+ const zzfxSound = asset;
107
+
87
108
  // remove randomness so it can be applied on playback
88
- const randomnessIndex = 1, defaultRandomness = .05;
89
- this.randomness = zzfxSound[randomnessIndex] !== undefined ?
90
- zzfxSound[randomnessIndex] : defaultRandomness;
109
+ const defaultRandomness = randomness ?? .05;
110
+ const randomnessIndex = 1;
111
+ this.randomness = zzfxSound[randomnessIndex] ?? defaultRandomness;
91
112
  zzfxSound[randomnessIndex] = 0;
92
113
 
93
114
  // generate the zzfx samples
94
115
  this.sampleChannels = [zzfxG(...zzfxSound)];
95
116
  this.loadedPercent = 1;
117
+ onloadCallback?.(this);
118
+ }
119
+ else if (typeof asset === 'string')
120
+ {
121
+ // load the audio file
122
+ const filename = asset;
123
+ this.loadSound(filename);
96
124
  }
97
125
  }
98
126
 
@@ -144,7 +172,7 @@ class Sound
144
172
  * @param {number} [volume] - Volume to play the music at
145
173
  * @param {boolean} [loop] - Should the music loop?
146
174
  * @param {boolean} [paused] - Should the music start paused
147
- * @return {SoundInstance} - The audio source node
175
+ * @return {SoundInstance} - The sound instance
148
176
  */
149
177
  playMusic(volume=1, loop=true, paused=false)
150
178
  { return this.play(undefined, volume, 1, 0, loop, paused); }
@@ -154,7 +182,7 @@ class Sound
154
182
  * @param {number} [semitoneOffset=0] - How many semitones to offset pitch
155
183
  * @param {Vector2} [pos] - World space position to play the sound if any
156
184
  * @param {number} [volume=1] - How much to scale volume by
157
- * @return {SoundInstance} - The audio source node
185
+ * @return {SoundInstance} - The sound instance
158
186
  */
159
187
  playNote(semitoneOffset=0, pos, volume)
160
188
  {
@@ -167,57 +195,14 @@ class Sound
167
195
  * @return {number} - How long the sound is in seconds (undefined if loading)
168
196
  */
169
197
  getDuration()
170
- { return this.sampleChannels && this.sampleRate ? this.sampleChannels[0].length / this.sampleRate : 0; }
198
+ { return this.sampleChannels?.[0]?.length / this.sampleRate || 0; }
171
199
 
172
200
  /** Check if sound is loaded, for sounds fetched from a url
173
201
  * @return {boolean} - True if sound is loaded and ready to play
174
202
  */
175
203
  isLoaded() { return this.loadedPercent === 1; }
176
- }
177
-
178
- ///////////////////////////////////////////////////////////////////////////////
179
-
180
- /**
181
- * Sound Wave Object - Loads and stores an audio file for later use
182
- * - this can be used to load and play wave, mp3, and ogg files
183
- * @extends Sound
184
- * @memberof Audio
185
- * @example
186
- * // load an audio asset file
187
- * const sound_example = new SoundWave('sound.mp3');
188
- *
189
- * // play the sound
190
- * sound_example.play();
191
- */
192
- class SoundWave extends Sound
193
- {
194
- /**
195
- * @callback SoundLoadCallback - Function called when sound is loaded
196
- * @param {SoundWave} sound
197
- * @memberof Audio
198
- */
199
204
 
200
- /** Create a sound object and cache the wave file for later use
201
- * @param {string} filename - Filename of audio file to load
202
- * @param {number} [randomness] - How much to randomize frequency each time sound plays
203
- * @param {number} [range=soundDefaultRange] - World space max range of sound
204
- * @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
205
- * @param {SoundLoadCallback} [onloadCallback] - callback function to call when sound is loaded
206
- */
207
- constructor(filename, randomness=0, range, taper, onloadCallback)
208
- {
209
- super(undefined, range, taper);
210
- if (!soundEnable || headlessMode) return;
211
- ASSERT(!filename || isString(filename), 'filename must be a string');
212
- ASSERT(isNumber(randomness), 'randomness must be a number');
213
-
214
- /** @property {SoundLoadCallback} - callback function to call when sound is loaded */
215
- this.onloadCallback = onloadCallback;
216
- this.randomness = randomness;
217
- filename && this.loadSound(filename);
218
- }
219
-
220
- /** Loads a sound from a URL and decodes it into sample data. Must be used with await!
205
+ /** Loads a sound from a URL and decodes it into sample data.
221
206
  * @param {string} filename
222
207
  * @return {Promise<void>} */
223
208
  async loadSound(filename)
@@ -259,8 +244,7 @@ class SoundWave extends Sound
259
244
  this.sampleRate = audioBuffer.sampleRate;
260
245
  this.sampleChannels = sampleChannels;
261
246
  this.loadedPercent = 1;
262
- if (this.onloadCallback)
263
- this.onloadCallback(this);
247
+ this.onloadCallback?.(this);
264
248
  }
265
249
  }
266
250
 
@@ -463,7 +447,7 @@ function speak(text, language='', volume=1, rate=1, pitch=1)
463
447
 
464
448
  /** Stop all queued speech
465
449
  * @memberof Audio */
466
- function speakStop() {speechSynthesis && speechSynthesis.cancel();}
450
+ function speakStop() {speechSynthesis?.cancel();}
467
451
 
468
452
  /** Get frequency of a note on a musical scale
469
453
  * @param {number} semitoneOffset - How many semitones away from the root note
@@ -49,7 +49,7 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
49
49
  /** Asserts if the expression is false, does nothing in release builds
50
50
  * Halts execution if the assert fails and throws an error
51
51
  * @param {boolean} assert
52
- * @param {...Object} [output] - error message output
52
+ * @param {...Object} output - error message output
53
53
  * @memberof Debug */
54
54
  function ASSERT(assert, ...output)
55
55
  {
@@ -59,13 +59,13 @@ function ASSERT(assert, ...output)
59
59
  }
60
60
 
61
61
  /** Log to console if debug is enabled, does nothing in release builds
62
- * @param {...Object} [output] - message output
62
+ * @param {...Object} output - message output
63
63
  * @memberof Debug */
64
64
  function LOG(...output) { console.log(...output); }
65
65
 
66
66
  /** Draw a debug rectangle in world space
67
67
  * @param {Vector2} pos
68
- * @param {Vector2} [size=Vector2()]
68
+ * @param {Vector2} [size=vec2(0)]
69
69
  * @param {Color|string} [color]
70
70
  * @param {number} [time]
71
71
  * @param {number} [angle]
@@ -389,7 +389,7 @@ function debugRender()
389
389
  if (tileCollisionTest(mousePos))
390
390
  {
391
391
  // show floored tile pick for tile collision
392
- drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5));
392
+ drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5), 0, false);
393
393
  }
394
394
  }
395
395
 
@@ -468,8 +468,8 @@ function debugRender()
468
468
  if (debugObject)
469
469
  {
470
470
  const raycastHitPos = tileCollisionRaycast(debugObject.pos, mousePos);
471
- raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3));
472
- drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5));
471
+ raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3), 0, false);
472
+ drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5), undefined, undefined, false);
473
473
 
474
474
  let debugText = 'mouse pos = ' + mousePos;
475
475
  if (tileCollisionLayers.length)
@@ -706,8 +706,8 @@ function debugProtectConstant(obj)
706
706
  props.forEach(prop =>
707
707
  {
708
708
  Object.defineProperty(obj, prop, {
709
- get: () => values[prop],
710
- set: (value) =>
709
+ get: ()=> values[prop],
710
+ set: (value)=>
711
711
  {
712
712
  ASSERT(false, `Cannot modify engine constant. Attempted to set constant (${obj}) property '${prop}' to '${value}'.`);
713
713
  },