littlejsengine 1.14.11 → 1.14.19
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/dist/littlejs.d.ts +303 -137
- package/dist/littlejs.esm.js +936 -463
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +934 -462
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +859 -417
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakoutTutorial/README.md +32 -32
- package/examples/breakoutTutorial/game.js +1 -1
- package/examples/electron/game.js +4 -4
- package/examples/electron/index.html +2 -2
- package/examples/electron/package.json +1 -8
- package/examples/index.html +67 -56
- package/examples/module/game.js +4 -4
- package/examples/platformer/gameEffects.js +5 -5
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +4 -4
- package/examples/puzzle/game.js +1 -1
- package/examples/shorts/animation.js +1 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/blending.js +8 -14
- package/examples/shorts/box2d.js +7 -3
- package/examples/shorts/box2dCar.js +2 -1
- package/examples/shorts/empty.js +30 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +10 -4
- package/examples/shorts/landerGame.js +11 -8
- package/examples/shorts/medals.js +4 -4
- package/examples/shorts/music.js +29 -56
- package/examples/shorts/musicPlayer.js +135 -0
- package/examples/shorts/nineSlice.js +34 -15
- package/examples/shorts/parallax.js +5 -4
- package/examples/shorts/particles.js +15 -15
- package/examples/shorts/piano.js +15 -21
- package/examples/shorts/pongGame.js +6 -4
- package/examples/shorts/raycasting.js +9 -4
- package/examples/shorts/sequencer.js +122 -0
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/shapes.js +7 -4
- package/examples/shorts/slidingPuzzle.js +4 -2
- package/examples/shorts/sound.js +18 -9
- package/examples/shorts/spaceGame.js +12 -8
- package/examples/shorts/spriteAtlas.js +7 -7
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/systemFont.js +2 -2
- package/examples/shorts/texture.js +2 -2
- package/examples/shorts/tileLayer.js +10 -10
- package/examples/shorts/tiltedView.js +24 -5
- package/examples/shorts/timers.js +10 -0
- package/examples/shorts/topDown.js +4 -1
- package/examples/shorts/uiSystem.js +8 -5
- package/examples/starter/game.js +4 -4
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +4 -4
- package/examples/typescript/game.ts +4 -4
- package/examples/uiSystem/game.js +4 -3
- package/package.json +4 -2
- package/plugins/box2d.js +17 -2
- package/plugins/newgrounds.js +7 -5
- package/plugins/postProcess.js +76 -53
- package/plugins/uiSystem.js +192 -53
- package/plugins/zzfxm.js +5 -1
- package/reference.md +1 -1
- package/src/engine.js +60 -23
- package/src/engineAudio.js +44 -17
- package/src/engineDebug.js +75 -45
- package/src/engineDraw.js +94 -59
- package/src/engineExport.js +2 -1
- package/src/engineMedals.js +10 -2
- package/src/engineObject.js +14 -10
- package/src/engineParticles.js +60 -47
- package/src/engineSettings.js +7 -7
- package/src/engineTileLayer.js +73 -56
- package/src/engineUtilities.js +67 -20
- package/src/engineWebGL.js +134 -63
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {string}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.14.
|
|
33
|
+
const engineVersion = '1.14.19';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -91,29 +91,60 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
91
91
|
///////////////////////////////////////////////////////////////////////////////
|
|
92
92
|
// plugin hooks
|
|
93
93
|
|
|
94
|
-
const
|
|
94
|
+
const pluginList = [];
|
|
95
|
+
class EnginePlugin
|
|
96
|
+
{
|
|
97
|
+
constructor(update, render, glContextLost, glContextRestored)
|
|
98
|
+
{
|
|
99
|
+
this.update = update;
|
|
100
|
+
this.render = render;
|
|
101
|
+
this.glContextLost = glContextLost;
|
|
102
|
+
this.glContextRestored = glContextRestored;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @callback PluginCallback - Update or render function for a plugin
|
|
108
|
+
* @memberof Engine
|
|
109
|
+
*/
|
|
95
110
|
|
|
96
111
|
/** Add a new update function for a plugin
|
|
97
|
-
* @param {
|
|
98
|
-
* @param {
|
|
112
|
+
* @param {PluginCallback} [update]
|
|
113
|
+
* @param {PluginCallback} [render]
|
|
114
|
+
* @param {PluginCallback} [glContextLost]
|
|
115
|
+
* @param {PluginCallback} [glContextRestored]
|
|
99
116
|
* @memberof Engine */
|
|
100
|
-
function engineAddPlugin(
|
|
117
|
+
function engineAddPlugin(update, render, glContextLost, glContextRestored)
|
|
101
118
|
{
|
|
102
|
-
|
|
103
|
-
ASSERT(!
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
// make sure plugin functions are unique
|
|
120
|
+
ASSERT(!pluginList.find(p=>
|
|
121
|
+
p.update === update && p.render === render &&
|
|
122
|
+
p.glContextLost === glContextLost &&
|
|
123
|
+
p.glContextRestored === glContextRestored));
|
|
124
|
+
|
|
125
|
+
const plugin = new EnginePlugin(update, render, glContextLost, glContextRestored);
|
|
126
|
+
pluginList.push(plugin);
|
|
106
127
|
}
|
|
107
128
|
|
|
108
129
|
///////////////////////////////////////////////////////////////////////////////
|
|
109
130
|
// Main Engine Functions
|
|
110
131
|
|
|
132
|
+
/**
|
|
133
|
+
* @callback GameInitCallback - Called after the engine starts, can be async
|
|
134
|
+
* @returns {void|Promise<void>}
|
|
135
|
+
* @memberof Engine
|
|
136
|
+
*/
|
|
137
|
+
/**
|
|
138
|
+
* @callback GameCallback - Update or render function for the game
|
|
139
|
+
* @memberof Engine
|
|
140
|
+
*/
|
|
141
|
+
|
|
111
142
|
/** Startup LittleJS engine with your callback functions
|
|
112
|
-
* @param {
|
|
113
|
-
* @param {
|
|
114
|
-
* @param {
|
|
115
|
-
* @param {
|
|
116
|
-
* @param {
|
|
143
|
+
* @param {GameInitCallback} gameInit - Called once after the engine starts up, can be async for loading
|
|
144
|
+
* @param {GameCallback} gameUpdate - Called every frame before objects are updated (60fps), use for game logic
|
|
145
|
+
* @param {GameCallback} gameUpdatePost - Called after physics and objects are updated, even when paused, use for UI updates
|
|
146
|
+
* @param {GameCallback} gameRender - Called before objects are rendered, use for drawing backgrounds/world elements
|
|
147
|
+
* @param {GameCallback} gameRenderPost - Called after objects are rendered, use for drawing UI/overlays
|
|
117
148
|
* @param {Array<string>} [imageSources=[]] - List of image file paths to preload (e.g., ['player.png', 'tiles.png'])
|
|
118
149
|
* @param {HTMLElement} [rootElement] - Root DOM element to attach canvas to, defaults to document.body
|
|
119
150
|
* @example
|
|
@@ -177,7 +208,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
177
208
|
wasUpdated = true;
|
|
178
209
|
updateCanvas();
|
|
179
210
|
inputUpdate();
|
|
180
|
-
|
|
211
|
+
pluginList.forEach(plugin=>plugin.update?.());
|
|
181
212
|
|
|
182
213
|
// update object transforms even when paused
|
|
183
214
|
for (const o of engineObjects)
|
|
@@ -210,7 +241,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
210
241
|
updateCanvas();
|
|
211
242
|
inputUpdate();
|
|
212
243
|
gameUpdate();
|
|
213
|
-
|
|
244
|
+
pluginList.forEach(plugin=>plugin.update?.());
|
|
214
245
|
engineObjectsUpdate();
|
|
215
246
|
|
|
216
247
|
// do post update
|
|
@@ -244,7 +275,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
244
275
|
for (const o of engineObjects)
|
|
245
276
|
o.destroyed || o.render();
|
|
246
277
|
gameRenderPost();
|
|
247
|
-
|
|
278
|
+
pluginList.forEach(plugin=>plugin.render?.());
|
|
248
279
|
touchGamepadRender();
|
|
249
280
|
debugRender();
|
|
250
281
|
glFlush();
|
|
@@ -365,11 +396,12 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
365
396
|
const promises = imageSources.map((src, textureIndex)=>
|
|
366
397
|
new Promise(resolve =>
|
|
367
398
|
{
|
|
399
|
+
ASSERT(isString(src), 'imageSources must be an array of strings');
|
|
400
|
+
|
|
368
401
|
const image = new Image;
|
|
369
402
|
image.onerror = image.onload = ()=>
|
|
370
403
|
{
|
|
371
404
|
const textureInfo = new TextureInfo(image);
|
|
372
|
-
textureInfo.createWebGLTexture();
|
|
373
405
|
textureInfos[textureIndex] = textureInfo;
|
|
374
406
|
resolve();
|
|
375
407
|
}
|
|
@@ -385,7 +417,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
385
417
|
{
|
|
386
418
|
const textureInfo = new TextureInfo(new Image);
|
|
387
419
|
textureInfos[0] = textureInfo;
|
|
388
|
-
textureInfo.createWebGLTexture();
|
|
389
420
|
resolve();
|
|
390
421
|
}));
|
|
391
422
|
}
|
|
@@ -396,7 +427,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
396
427
|
promises.push(new Promise(resolve =>
|
|
397
428
|
{
|
|
398
429
|
let t = 0;
|
|
399
|
-
|
|
430
|
+
console.log(`${engineName} Engine v${engineVersion}`);
|
|
400
431
|
updateSplash();
|
|
401
432
|
function updateSplash()
|
|
402
433
|
{
|
|
@@ -480,10 +511,16 @@ function engineObjectsCollect(pos, size, objects=engineObjects)
|
|
|
480
511
|
return collectedObjects;
|
|
481
512
|
}
|
|
482
513
|
|
|
514
|
+
/**
|
|
515
|
+
* @callback ObjectCallbackFunction - Function that processes an object
|
|
516
|
+
* @param {EngineObject} uiObjects
|
|
517
|
+
* @memberof Engine
|
|
518
|
+
*/
|
|
519
|
+
|
|
483
520
|
/** Triggers a callback for each object within a given area
|
|
484
|
-
* @param {Vector2} [pos]
|
|
485
|
-
* @param {Vector2|number} [size]
|
|
486
|
-
* @param {
|
|
521
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
522
|
+
* @param {Vector2|number} [size] - Radius of circle if float, rectangle size if Vector2
|
|
523
|
+
* @param {ObjectCallbackFunction} [callbackFunction] - Calls this function on every object that passes the test
|
|
487
524
|
* @param {Array<EngineObject>} [objects=engineObjects] - List of objects to check
|
|
488
525
|
* @memberof Engine */
|
|
489
526
|
function engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
package/src/engineAudio.js
CHANGED
|
@@ -47,6 +47,7 @@ function audioInit()
|
|
|
47
47
|
* Sound Object - Stores a sound for later use and can be played positionally
|
|
48
48
|
*
|
|
49
49
|
* <a href=https://killedbyapixel.github.io/ZzFX/>Create sounds using the ZzFX Sound Designer.</a>
|
|
50
|
+
* @memberof Audio
|
|
50
51
|
* @example
|
|
51
52
|
* // create a sound
|
|
52
53
|
* const sound_example = new Sound([.5,.5]);
|
|
@@ -141,12 +142,12 @@ class Sound
|
|
|
141
142
|
|
|
142
143
|
/** Play the sound as a musical note with a semitone offset
|
|
143
144
|
* This can be used to play music with chromatic scales
|
|
144
|
-
* @param {number} semitoneOffset - How many semitones to offset pitch
|
|
145
|
+
* @param {number} [semitoneOffset=0] - How many semitones to offset pitch
|
|
145
146
|
* @param {Vector2} [pos] - World space position to play the sound if any
|
|
146
147
|
* @param {number} [volume=1] - How much to scale volume by
|
|
147
148
|
* @return {SoundInstance} - The audio source node
|
|
148
149
|
*/
|
|
149
|
-
playNote(semitoneOffset, pos, volume)
|
|
150
|
+
playNote(semitoneOffset=0, pos, volume)
|
|
150
151
|
{
|
|
151
152
|
const pitch = getNoteFrequency(semitoneOffset, 1);
|
|
152
153
|
return this.play(pos, volume, pitch, 0);
|
|
@@ -169,6 +170,8 @@ class Sound
|
|
|
169
170
|
/**
|
|
170
171
|
* Sound Wave Object - Stores a wave sound for later use and can be played positionally
|
|
171
172
|
* - this can be used to play wave, mp3, and ogg files
|
|
173
|
+
* @extends Sound
|
|
174
|
+
* @memberof Audio
|
|
172
175
|
* @example
|
|
173
176
|
* // create a sound
|
|
174
177
|
* const sound_example = new SoundWave('sound.mp3');
|
|
@@ -178,22 +181,29 @@ class Sound
|
|
|
178
181
|
*/
|
|
179
182
|
class SoundWave extends Sound
|
|
180
183
|
{
|
|
184
|
+
/**
|
|
185
|
+
* @callback SoundLoadCallback - Function called when sound is loaded
|
|
186
|
+
* @param {SoundWave} sound
|
|
187
|
+
* @memberof Audio
|
|
188
|
+
*/
|
|
189
|
+
|
|
181
190
|
/** Create a sound object and cache the wave file for later use
|
|
182
191
|
* @param {string} filename - Filename of audio file to load
|
|
183
192
|
* @param {number} [randomness] - How much to randomize frequency each time sound plays
|
|
184
193
|
* @param {number} [range=soundDefaultRange] - World space max range of sound
|
|
185
194
|
* @param {number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering
|
|
186
|
-
* @param {
|
|
195
|
+
* @param {SoundLoadCallback} [onloadCallback] - callback function to call when sound is loaded
|
|
187
196
|
*/
|
|
188
197
|
constructor(filename, randomness=0, range, taper, onloadCallback)
|
|
189
198
|
{
|
|
190
199
|
super(undefined, range, taper);
|
|
191
200
|
if (!soundEnable || headlessMode) return;
|
|
201
|
+
ASSERT(!filename || isString(filename), 'filename must be a string');
|
|
192
202
|
|
|
193
|
-
/** @property {
|
|
203
|
+
/** @property {SoundLoadCallback} - callback function to call when sound is loaded */
|
|
194
204
|
this.onloadCallback = onloadCallback;
|
|
195
205
|
this.randomness = randomness;
|
|
196
|
-
this.loadSound(filename);
|
|
206
|
+
filename && this.loadSound(filename);
|
|
197
207
|
}
|
|
198
208
|
|
|
199
209
|
/** Loads a sound from a URL and decodes it into sample data. Must be used with await!
|
|
@@ -202,6 +212,8 @@ class SoundWave extends Sound
|
|
|
202
212
|
async loadSound(filename)
|
|
203
213
|
{
|
|
204
214
|
const response = await fetch(filename);
|
|
215
|
+
if (!response.ok)
|
|
216
|
+
throw new Error(`Failed to load sound from ${filename}: ${response.status} ${response.statusText}`);
|
|
205
217
|
const arrayBuffer = await response.arrayBuffer();
|
|
206
218
|
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
207
219
|
|
|
@@ -237,7 +249,7 @@ class SoundWave extends Sound
|
|
|
237
249
|
this.sampleChannels = sampleChannels;
|
|
238
250
|
this.loadedPercent = 1;
|
|
239
251
|
if (this.onloadCallback)
|
|
240
|
-
this.onloadCallback();
|
|
252
|
+
this.onloadCallback(this);
|
|
241
253
|
}
|
|
242
254
|
}
|
|
243
255
|
|
|
@@ -246,6 +258,7 @@ class SoundWave extends Sound
|
|
|
246
258
|
/**
|
|
247
259
|
* Sound Instance - Wraps an AudioBufferSourceNode for individual sound control
|
|
248
260
|
* Represents a single playing instance of a sound with pause/resume capabilities
|
|
261
|
+
* @memberof Audio
|
|
249
262
|
* @example
|
|
250
263
|
* // Play a sound and get an instance for control
|
|
251
264
|
* const jumpSound = new Sound([.5,.5,220]);
|
|
@@ -311,8 +324,16 @@ class SoundInstance
|
|
|
311
324
|
this.stop();
|
|
312
325
|
this.gainNode = audioContext.createGain();
|
|
313
326
|
this.source = playSamples(this.sound.sampleChannels, this.volume, this.rate, this.pan, this.loop, this.sound.sampleRate, this.gainNode, offset, this.onendedCallback);
|
|
314
|
-
this.
|
|
315
|
-
|
|
327
|
+
if (this.source)
|
|
328
|
+
{
|
|
329
|
+
this.startTime = audioContext.currentTime - offset;
|
|
330
|
+
this.pausedTime = undefined;
|
|
331
|
+
}
|
|
332
|
+
else
|
|
333
|
+
{
|
|
334
|
+
this.startTime = undefined;
|
|
335
|
+
this.pausedTime = 0;
|
|
336
|
+
}
|
|
316
337
|
}
|
|
317
338
|
|
|
318
339
|
/** Set the volume of this sound instance
|
|
@@ -445,6 +466,12 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
445
466
|
|
|
446
467
|
///////////////////////////////////////////////////////////////////////////////
|
|
447
468
|
|
|
469
|
+
/**
|
|
470
|
+
* @callback AudioEndedCallback - Function called when a sound ends
|
|
471
|
+
* @param {AudioBufferSourceNode} source
|
|
472
|
+
* @memberof Audio
|
|
473
|
+
*/
|
|
474
|
+
|
|
448
475
|
/** Play cached audio samples with given settings
|
|
449
476
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
450
477
|
* @param {number} [volume] - How much to scale volume by
|
|
@@ -454,13 +481,20 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
454
481
|
* @param {number} [sampleRate=44100] - Sample rate for the sound
|
|
455
482
|
* @param {GainNode} [gainNode] - Optional gain node for volume control while playing
|
|
456
483
|
* @param {number} [offset] - Offset in seconds to start playback from
|
|
457
|
-
* @param {
|
|
458
|
-
* @return {AudioBufferSourceNode} - The
|
|
484
|
+
* @param {AudioEndedCallback} [onended] - Callback for when the sound ends
|
|
485
|
+
* @return {AudioBufferSourceNode} - The source node of the sound played, may be undefined if play fails
|
|
459
486
|
* @memberof Audio */
|
|
460
487
|
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=audioDefaultSampleRate, gainNode, offset=0, onended)
|
|
461
488
|
{
|
|
462
489
|
if (!soundEnable || headlessMode) return;
|
|
463
490
|
|
|
491
|
+
if (!audioIsRunning())
|
|
492
|
+
{
|
|
493
|
+
// fix stalled audio, this sound won't be able to play
|
|
494
|
+
audioContext.resume();
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
464
498
|
// create buffer and source
|
|
465
499
|
const channelCount = sampleChannels.length;
|
|
466
500
|
const sampleLength = sampleChannels[0].length;
|
|
@@ -486,13 +520,6 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
486
520
|
if (onended)
|
|
487
521
|
source.addEventListener('ended', ()=> onended(source));
|
|
488
522
|
|
|
489
|
-
if (!audioIsRunning())
|
|
490
|
-
{
|
|
491
|
-
// fix stalled audio, this sound won't be able to play
|
|
492
|
-
audioContext.resume();
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
523
|
// play and return sound
|
|
497
524
|
const startOffset = offset * rate;
|
|
498
525
|
source.start(0, startOffset);
|
package/src/engineDebug.js
CHANGED
|
@@ -47,10 +47,16 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
47
47
|
// Debug helper functions
|
|
48
48
|
|
|
49
49
|
/** Asserts if the expression is false, does nothing in release builds
|
|
50
|
+
* Halts execution if the assert fails and throws an error
|
|
50
51
|
* @param {boolean} assert
|
|
51
52
|
* @param {...Object} [output] - error message output
|
|
52
53
|
* @memberof Debug */
|
|
53
|
-
function ASSERT(assert, ...output)
|
|
54
|
+
function ASSERT(assert, ...output)
|
|
55
|
+
{
|
|
56
|
+
if (assert) return;
|
|
57
|
+
console.assert(assert, ...output)
|
|
58
|
+
throw new Error('Assert failed!'); // halt execution
|
|
59
|
+
}
|
|
54
60
|
|
|
55
61
|
/** Log to console if debug is enabled, does nothing in release builds
|
|
56
62
|
* @param {...Object} [output] - message output
|
|
@@ -60,64 +66,72 @@ function LOG(...output) { console.log(...output); }
|
|
|
60
66
|
/** Draw a debug rectangle in world space
|
|
61
67
|
* @param {Vector2} pos
|
|
62
68
|
* @param {Vector2} [size=Vector2()]
|
|
63
|
-
* @param {string}
|
|
64
|
-
* @param {number}
|
|
65
|
-
* @param {number}
|
|
69
|
+
* @param {Color|string} [color]
|
|
70
|
+
* @param {number} [time]
|
|
71
|
+
* @param {number} [angle]
|
|
66
72
|
* @param {boolean} [fill]
|
|
67
73
|
* @memberof Debug */
|
|
68
|
-
function debugRect(pos, size=vec2(), color=
|
|
74
|
+
function debugRect(pos, size=vec2(), color=WHITE, time=0, angle=0, fill=false)
|
|
69
75
|
{
|
|
70
76
|
if (typeof size === 'number')
|
|
71
77
|
size = vec2(size); // allow passing in floats
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
if (isColor(color))
|
|
79
|
+
color = color.toString();
|
|
80
|
+
pos = pos.copy();
|
|
81
|
+
size = size.copy();
|
|
82
|
+
const timer = new Timer(time);
|
|
83
|
+
debugPrimitives.push({pos:pos.copy(), size:size.copy(), color, timer, angle, fill});
|
|
74
84
|
}
|
|
75
85
|
|
|
76
86
|
/** Draw a debug poly in world space
|
|
77
87
|
* @param {Vector2} pos
|
|
78
88
|
* @param {Array<Vector2>} points
|
|
79
|
-
* @param {string}
|
|
80
|
-
* @param {number}
|
|
81
|
-
* @param {number}
|
|
89
|
+
* @param {Color|string} [color]
|
|
90
|
+
* @param {number} [time]
|
|
91
|
+
* @param {number} [angle]
|
|
82
92
|
* @param {boolean} [fill]
|
|
83
93
|
* @memberof Debug */
|
|
84
|
-
function debugPoly(pos, points, color=
|
|
94
|
+
function debugPoly(pos, points, color=WHITE, time=0, angle=0, fill=false)
|
|
85
95
|
{
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
if (isColor(color))
|
|
97
|
+
color = color.toString();
|
|
98
|
+
pos = pos.copy();
|
|
99
|
+
points = points.map(p=>p.copy());
|
|
100
|
+
const timer = new Timer(time);
|
|
101
|
+
debugPrimitives.push({pos, points, color, timer, angle, fill});
|
|
88
102
|
}
|
|
89
103
|
|
|
90
104
|
/** Draw a debug circle in world space
|
|
91
105
|
* @param {Vector2} pos
|
|
92
|
-
* @param {number}
|
|
93
|
-
* @param {string}
|
|
94
|
-
* @param {number}
|
|
106
|
+
* @param {number} [size] - diameter
|
|
107
|
+
* @param {Color|string} [color]
|
|
108
|
+
* @param {number} [time]
|
|
95
109
|
* @param {boolean} [fill]
|
|
96
110
|
* @memberof Debug */
|
|
97
|
-
function debugCircle(pos, size=0, color=
|
|
111
|
+
function debugCircle(pos, size=0, color=WHITE, time=0, fill=false)
|
|
98
112
|
{
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
if (isColor(color))
|
|
114
|
+
color = color.toString();
|
|
115
|
+
pos = pos.copy();
|
|
116
|
+
const timer = new Timer(time);
|
|
117
|
+
debugPrimitives.push({pos, size, color, timer, angle:0, fill});
|
|
101
118
|
}
|
|
102
119
|
|
|
103
120
|
/** Draw a debug point in world space
|
|
104
121
|
* @param {Vector2} pos
|
|
105
|
-
* @param {string}
|
|
106
|
-
* @param {number}
|
|
107
|
-
* @param {number}
|
|
122
|
+
* @param {Color|string} [color]
|
|
123
|
+
* @param {number} [time]
|
|
124
|
+
* @param {number} [angle]
|
|
108
125
|
* @memberof Debug */
|
|
109
126
|
function debugPoint(pos, color, time, angle)
|
|
110
|
-
{
|
|
111
|
-
ASSERT(typeof color === 'string', 'pass in css color strings');
|
|
112
|
-
debugRect(pos, undefined, color, time, angle);
|
|
113
|
-
}
|
|
127
|
+
{ debugRect(pos, undefined, color, time, angle); }
|
|
114
128
|
|
|
115
129
|
/** Draw a debug line in world space
|
|
116
130
|
* @param {Vector2} posA
|
|
117
131
|
* @param {Vector2} posB
|
|
118
|
-
* @param {string}
|
|
119
|
-
* @param {number}
|
|
120
|
-
* @param {number}
|
|
132
|
+
* @param {Color|string} [color]
|
|
133
|
+
* @param {number} [width]
|
|
134
|
+
* @param {number} [time]
|
|
121
135
|
* @memberof Debug */
|
|
122
136
|
function debugLine(posA, posB, color, width=.1, time)
|
|
123
137
|
{
|
|
@@ -131,7 +145,7 @@ function debugLine(posA, posB, color, width=.1, time)
|
|
|
131
145
|
* @param {Vector2} sizeA
|
|
132
146
|
* @param {Vector2} posB
|
|
133
147
|
* @param {Vector2} sizeB
|
|
134
|
-
* @param {string}
|
|
148
|
+
* @param {Color|string} [color]
|
|
135
149
|
* @memberof Debug */
|
|
136
150
|
function debugOverlap(posA, sizeA, posB, sizeB, color)
|
|
137
151
|
{
|
|
@@ -147,18 +161,21 @@ function debugOverlap(posA, sizeA, posB, sizeB, color)
|
|
|
147
161
|
}
|
|
148
162
|
|
|
149
163
|
/** Draw a debug axis aligned bounding box in world space
|
|
150
|
-
* @param {string}
|
|
164
|
+
* @param {string} text
|
|
151
165
|
* @param {Vector2} pos
|
|
152
|
-
* @param {number}
|
|
153
|
-
* @param {string}
|
|
154
|
-
* @param {number}
|
|
155
|
-
* @param {number}
|
|
156
|
-
* @param {string}
|
|
166
|
+
* @param {number} [size]
|
|
167
|
+
* @param {Color|string} [color]
|
|
168
|
+
* @param {number} [time]
|
|
169
|
+
* @param {number} [angle]
|
|
170
|
+
* @param {string} [font]
|
|
157
171
|
* @memberof Debug */
|
|
158
|
-
function debugText(text, pos, size=1, color=
|
|
172
|
+
function debugText(text, pos, size=1, color=WHITE, time=0, angle=0, font='monospace')
|
|
159
173
|
{
|
|
160
|
-
|
|
161
|
-
|
|
174
|
+
if (isColor(color))
|
|
175
|
+
color = color.toString();
|
|
176
|
+
pos = pos.copy();
|
|
177
|
+
const timer = new Timer(time);
|
|
178
|
+
debugPrimitives.push({text, pos, size, color, timer, angle, font});
|
|
162
179
|
}
|
|
163
180
|
|
|
164
181
|
/** Clear all debug primitives in the list
|
|
@@ -209,17 +226,30 @@ function debugSaveDataURL(dataURL, filename)
|
|
|
209
226
|
downloadLink.click();
|
|
210
227
|
}
|
|
211
228
|
|
|
212
|
-
/**
|
|
229
|
+
/** Breaks on all asserts/errors, hides the canvas, and shows message in plain text
|
|
230
|
+
* This is a good function to call at the start of your game to catch all errors
|
|
231
|
+
* In release builds this function has no effect
|
|
213
232
|
* @memberof Debug */
|
|
214
233
|
function debugShowErrors()
|
|
215
234
|
{
|
|
216
235
|
const showError = (message)=>
|
|
217
236
|
{
|
|
218
237
|
// replace entire page with error message
|
|
219
|
-
document.body.style
|
|
220
|
-
document.body.
|
|
221
|
-
document.body.innerHTML = `<pre style=color:#f00;font-size:50px;white-space:pre-wrap>` + message;
|
|
238
|
+
document.body.style = 'background-color:#111;margin:8px';
|
|
239
|
+
document.body.innerHTML = `<pre style=color:#f00;font-size:28px;white-space:pre-wrap>` + message;
|
|
222
240
|
}
|
|
241
|
+
|
|
242
|
+
const originalAssert = console.assert;
|
|
243
|
+
console.assert = (assertion, ...output)=>
|
|
244
|
+
{
|
|
245
|
+
originalAssert(assertion, ...output);
|
|
246
|
+
if (!assertion)
|
|
247
|
+
{
|
|
248
|
+
const message = output.join(' ');
|
|
249
|
+
const stack = new Error().stack;
|
|
250
|
+
throw 'Assertion failed!\n' + message + '\n' + stack;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
223
253
|
onunhandledrejection = (event)=>
|
|
224
254
|
showError(event.reason.stack || event.reason);
|
|
225
255
|
onerror = (message, source, lineno, colno)=>
|
|
@@ -387,7 +417,7 @@ function debugRender()
|
|
|
387
417
|
p.fill && overlayContext.fill();
|
|
388
418
|
overlayContext.stroke();
|
|
389
419
|
}
|
|
390
|
-
else if (p.size === 0 || p.size.x === 0 && p.size.y === 0)
|
|
420
|
+
else if (p.size === 0 || (p.size.x === 0 && p.size.y === 0))
|
|
391
421
|
{
|
|
392
422
|
// point
|
|
393
423
|
overlayContext.fillRect(-pointSize/2, -1, pointSize, 3);
|
|
@@ -414,7 +444,7 @@ function debugRender()
|
|
|
414
444
|
});
|
|
415
445
|
|
|
416
446
|
// remove expired primitives
|
|
417
|
-
debugPrimitives = debugPrimitives.filter(r=>r.
|
|
447
|
+
debugPrimitives = debugPrimitives.filter(r=>r.timer<0);
|
|
418
448
|
}
|
|
419
449
|
|
|
420
450
|
if (debugObject)
|