littlejsengine 1.14.10 → 1.14.16
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 +264 -120
- package/dist/littlejs.esm.js +603 -288
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +600 -287
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +521 -232
- package/examples/box2d/gameObjects.js +2 -2
- 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 +3 -3
- package/examples/electron/index.html +2 -2
- package/examples/electron/package.json +1 -8
- package/examples/index.html +59 -51
- package/examples/module/game.js +3 -3
- package/examples/platformer/gameCharacter.js +6 -2
- package/examples/platformer/gameEffects.js +4 -4
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +11 -9
- 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 +30 -3
- package/examples/shorts/medals.js +4 -4
- package/examples/shorts/music.js +29 -55
- package/examples/shorts/musicPlayer.js +134 -0
- package/examples/shorts/nineSlice.js +34 -15
- package/examples/shorts/parallax.js +4 -3
- package/examples/shorts/particles.js +16 -16
- package/examples/shorts/piano.js +15 -21
- package/examples/shorts/pongGame.js +6 -4
- package/examples/shorts/raycasting.js +13 -5
- package/examples/shorts/sequencer.js +122 -0
- package/examples/shorts/shapes.js +7 -4
- package/examples/shorts/slidingPuzzle.js +16 -6
- 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 +14 -3
- 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 +3 -3
- package/examples/starter/index.html +2 -2
- package/examples/typescript/game.js +3 -3
- package/examples/typescript/game.ts +3 -3
- package/examples/uiSystem/game.js +6 -6
- package/package.json +4 -2
- package/plugins/box2d.js +18 -3
- package/plugins/newgrounds.js +11 -9
- package/plugins/postProcess.js +5 -2
- package/plugins/uiSystem.js +120 -34
- package/plugins/zzfxm.js +5 -1
- package/reference.md +1 -3
- package/src/engine.js +52 -21
- package/src/engineAudio.js +31 -14
- package/src/engineDebug.js +80 -55
- package/src/engineDraw.js +60 -31
- package/src/engineExport.js +3 -1
- package/src/engineMedals.js +10 -2
- package/src/engineObject.js +14 -10
- package/src/engineParticles.js +59 -46
- package/src/engineRelease.js +1 -0
- package/src/engineSettings.js +7 -7
- package/src/engineTileLayer.js +49 -18
- package/src/engineUtilities.js +79 -34
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]);
|
|
@@ -445,6 +458,12 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
445
458
|
|
|
446
459
|
///////////////////////////////////////////////////////////////////////////////
|
|
447
460
|
|
|
461
|
+
/**
|
|
462
|
+
* @callback AudioEndedCallback - Function called when a sound ends
|
|
463
|
+
* @param {AudioBufferSourceNode} source
|
|
464
|
+
* @memberof Audio
|
|
465
|
+
*/
|
|
466
|
+
|
|
448
467
|
/** Play cached audio samples with given settings
|
|
449
468
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
450
469
|
* @param {number} [volume] - How much to scale volume by
|
|
@@ -454,7 +473,7 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
454
473
|
* @param {number} [sampleRate=44100] - Sample rate for the sound
|
|
455
474
|
* @param {GainNode} [gainNode] - Optional gain node for volume control while playing
|
|
456
475
|
* @param {number} [offset] - Offset in seconds to start playback from
|
|
457
|
-
* @param {
|
|
476
|
+
* @param {AudioEndedCallback} [onended] - Callback for when the sound ends
|
|
458
477
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
459
478
|
* @memberof Audio */
|
|
460
479
|
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=audioDefaultSampleRate, gainNode, offset=0, onended)
|
|
@@ -486,16 +505,14 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
486
505
|
if (onended)
|
|
487
506
|
source.addEventListener('ended', ()=> onended(source));
|
|
488
507
|
|
|
508
|
+
const startOffset = offset * rate;
|
|
489
509
|
if (!audioIsRunning())
|
|
490
510
|
{
|
|
491
|
-
// fix stalled audio
|
|
492
|
-
audioContext.resume();
|
|
493
|
-
return;
|
|
511
|
+
// fix stalled audio and start
|
|
512
|
+
audioContext.resume().then(()=>source.start(0, startOffset));
|
|
494
513
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const startOffset = offset * rate;
|
|
498
|
-
source.start(0, startOffset);
|
|
514
|
+
else
|
|
515
|
+
source.start(0, startOffset);
|
|
499
516
|
return source;
|
|
500
517
|
}
|
|
501
518
|
|
package/src/engineDebug.js
CHANGED
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
* @memberof Debug */
|
|
17
17
|
const debug = true;
|
|
18
18
|
|
|
19
|
-
/** True if asserts are enabled
|
|
20
|
-
* @type {boolean}
|
|
21
|
-
* @default
|
|
22
|
-
* @memberof Debug */
|
|
23
|
-
const enableAsserts = true;
|
|
24
|
-
|
|
25
19
|
/** Size to render debug points by default
|
|
26
20
|
* @type {number}
|
|
27
21
|
* @default
|
|
@@ -52,77 +46,92 @@ let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParti
|
|
|
52
46
|
///////////////////////////////////////////////////////////////////////////////
|
|
53
47
|
// Debug helper functions
|
|
54
48
|
|
|
55
|
-
/** Asserts if the expression is false, does
|
|
49
|
+
/** Asserts if the expression is false, does nothing in release builds
|
|
50
|
+
* Halts execution if the assert fails and throws an error
|
|
56
51
|
* @param {boolean} assert
|
|
57
52
|
* @param {...Object} [output] - error message output
|
|
58
53
|
* @memberof Debug */
|
|
59
54
|
function ASSERT(assert, ...output)
|
|
60
55
|
{
|
|
61
|
-
if (
|
|
62
|
-
|
|
56
|
+
if (assert) return;
|
|
57
|
+
console.assert(assert, ...output)
|
|
58
|
+
throw new Error('Assert failed!'); // halt execution
|
|
63
59
|
}
|
|
64
60
|
|
|
61
|
+
/** Log to console if debug is enabled, does nothing in release builds
|
|
62
|
+
* @param {...Object} [output] - message output
|
|
63
|
+
* @memberof Debug */
|
|
64
|
+
function LOG(...output) { console.log(...output); }
|
|
65
|
+
|
|
65
66
|
/** Draw a debug rectangle in world space
|
|
66
67
|
* @param {Vector2} pos
|
|
67
68
|
* @param {Vector2} [size=Vector2()]
|
|
68
|
-
* @param {string}
|
|
69
|
-
* @param {number}
|
|
70
|
-
* @param {number}
|
|
69
|
+
* @param {Color|string} [color]
|
|
70
|
+
* @param {number} [time]
|
|
71
|
+
* @param {number} [angle]
|
|
71
72
|
* @param {boolean} [fill]
|
|
72
73
|
* @memberof Debug */
|
|
73
|
-
function debugRect(pos, size=vec2(), color=
|
|
74
|
+
function debugRect(pos, size=vec2(), color=WHITE, time=0, angle=0, fill=false)
|
|
74
75
|
{
|
|
75
76
|
if (typeof size === 'number')
|
|
76
77
|
size = vec2(size); // allow passing in floats
|
|
77
|
-
|
|
78
|
-
|
|
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});
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
/** Draw a debug poly in world space
|
|
82
87
|
* @param {Vector2} pos
|
|
83
88
|
* @param {Array<Vector2>} points
|
|
84
|
-
* @param {string}
|
|
85
|
-
* @param {number}
|
|
86
|
-
* @param {number}
|
|
89
|
+
* @param {Color|string} [color]
|
|
90
|
+
* @param {number} [time]
|
|
91
|
+
* @param {number} [angle]
|
|
87
92
|
* @param {boolean} [fill]
|
|
88
93
|
* @memberof Debug */
|
|
89
|
-
function debugPoly(pos, points, color=
|
|
94
|
+
function debugPoly(pos, points, color=WHITE, time=0, angle=0, fill=false)
|
|
90
95
|
{
|
|
91
|
-
|
|
92
|
-
|
|
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});
|
|
93
102
|
}
|
|
94
103
|
|
|
95
104
|
/** Draw a debug circle in world space
|
|
96
105
|
* @param {Vector2} pos
|
|
97
|
-
* @param {number}
|
|
98
|
-
* @param {string}
|
|
99
|
-
* @param {number}
|
|
106
|
+
* @param {number} [size] - diameter
|
|
107
|
+
* @param {Color|string} [color]
|
|
108
|
+
* @param {number} [time]
|
|
100
109
|
* @param {boolean} [fill]
|
|
101
110
|
* @memberof Debug */
|
|
102
|
-
function debugCircle(pos, size=0, color=
|
|
111
|
+
function debugCircle(pos, size=0, color=WHITE, time=0, fill=false)
|
|
103
112
|
{
|
|
104
|
-
|
|
105
|
-
|
|
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});
|
|
106
118
|
}
|
|
107
119
|
|
|
108
120
|
/** Draw a debug point in world space
|
|
109
121
|
* @param {Vector2} pos
|
|
110
|
-
* @param {string}
|
|
111
|
-
* @param {number}
|
|
112
|
-
* @param {number}
|
|
122
|
+
* @param {Color|string} [color]
|
|
123
|
+
* @param {number} [time]
|
|
124
|
+
* @param {number} [angle]
|
|
113
125
|
* @memberof Debug */
|
|
114
126
|
function debugPoint(pos, color, time, angle)
|
|
115
|
-
{
|
|
116
|
-
ASSERT(typeof color === 'string', 'pass in css color strings');
|
|
117
|
-
debugRect(pos, undefined, color, time, angle);
|
|
118
|
-
}
|
|
127
|
+
{ debugRect(pos, undefined, color, time, angle); }
|
|
119
128
|
|
|
120
129
|
/** Draw a debug line in world space
|
|
121
130
|
* @param {Vector2} posA
|
|
122
131
|
* @param {Vector2} posB
|
|
123
|
-
* @param {string}
|
|
124
|
-
* @param {number}
|
|
125
|
-
* @param {number}
|
|
132
|
+
* @param {Color|string} [color]
|
|
133
|
+
* @param {number} [width]
|
|
134
|
+
* @param {number} [time]
|
|
126
135
|
* @memberof Debug */
|
|
127
136
|
function debugLine(posA, posB, color, width=.1, time)
|
|
128
137
|
{
|
|
@@ -136,7 +145,7 @@ function debugLine(posA, posB, color, width=.1, time)
|
|
|
136
145
|
* @param {Vector2} sizeA
|
|
137
146
|
* @param {Vector2} posB
|
|
138
147
|
* @param {Vector2} sizeB
|
|
139
|
-
* @param {string}
|
|
148
|
+
* @param {Color|string} [color]
|
|
140
149
|
* @memberof Debug */
|
|
141
150
|
function debugOverlap(posA, sizeA, posB, sizeB, color)
|
|
142
151
|
{
|
|
@@ -152,18 +161,21 @@ function debugOverlap(posA, sizeA, posB, sizeB, color)
|
|
|
152
161
|
}
|
|
153
162
|
|
|
154
163
|
/** Draw a debug axis aligned bounding box in world space
|
|
155
|
-
* @param {string}
|
|
164
|
+
* @param {string} text
|
|
156
165
|
* @param {Vector2} pos
|
|
157
|
-
* @param {number}
|
|
158
|
-
* @param {string}
|
|
159
|
-
* @param {number}
|
|
160
|
-
* @param {number}
|
|
161
|
-
* @param {string}
|
|
166
|
+
* @param {number} [size]
|
|
167
|
+
* @param {Color|string} [color]
|
|
168
|
+
* @param {number} [time]
|
|
169
|
+
* @param {number} [angle]
|
|
170
|
+
* @param {string} [font]
|
|
162
171
|
* @memberof Debug */
|
|
163
|
-
function debugText(text, pos, size=1, color=
|
|
172
|
+
function debugText(text, pos, size=1, color=WHITE, time=0, angle=0, font='monospace')
|
|
164
173
|
{
|
|
165
|
-
|
|
166
|
-
|
|
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});
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
/** Clear all debug primitives in the list
|
|
@@ -214,17 +226,30 @@ function debugSaveDataURL(dataURL, filename)
|
|
|
214
226
|
downloadLink.click();
|
|
215
227
|
}
|
|
216
228
|
|
|
217
|
-
/**
|
|
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
|
|
218
232
|
* @memberof Debug */
|
|
219
233
|
function debugShowErrors()
|
|
220
234
|
{
|
|
221
235
|
const showError = (message)=>
|
|
222
236
|
{
|
|
223
237
|
// replace entire page with error message
|
|
224
|
-
document.body.style
|
|
225
|
-
document.body.
|
|
226
|
-
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;
|
|
227
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
|
+
};
|
|
228
253
|
onunhandledrejection = (event)=>
|
|
229
254
|
showError(event.reason.stack || event.reason);
|
|
230
255
|
onerror = (message, source, lineno, colno)=>
|
|
@@ -392,7 +417,7 @@ function debugRender()
|
|
|
392
417
|
p.fill && overlayContext.fill();
|
|
393
418
|
overlayContext.stroke();
|
|
394
419
|
}
|
|
395
|
-
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))
|
|
396
421
|
{
|
|
397
422
|
// point
|
|
398
423
|
overlayContext.fillRect(-pointSize/2, -1, pointSize, 3);
|
|
@@ -419,7 +444,7 @@ function debugRender()
|
|
|
419
444
|
});
|
|
420
445
|
|
|
421
446
|
// remove expired primitives
|
|
422
|
-
debugPrimitives = debugPrimitives.filter(r=>r.
|
|
447
|
+
debugPrimitives = debugPrimitives.filter(r=>r.timer<0);
|
|
423
448
|
}
|
|
424
449
|
|
|
425
450
|
if (debugObject)
|
|
@@ -554,7 +579,7 @@ function debugVideoCaptureStart()
|
|
|
554
579
|
}
|
|
555
580
|
|
|
556
581
|
// start recording
|
|
557
|
-
|
|
582
|
+
LOG('Video capture started.');
|
|
558
583
|
debugVideoCapture.start();
|
|
559
584
|
debugVideoCaptureTimer = new Timer(0);
|
|
560
585
|
|
|
@@ -581,7 +606,7 @@ function debugVideoCaptureStop()
|
|
|
581
606
|
return; // not recording
|
|
582
607
|
|
|
583
608
|
// stop recording
|
|
584
|
-
|
|
609
|
+
LOG(`Video capture ended. ${debugVideoCaptureTimer.get().toFixed(2)} seconds recorded.`);
|
|
585
610
|
debugVideoCapture.stop();
|
|
586
611
|
debugVideoCapture = 0;
|
|
587
612
|
debugVideoCaptureIcon.style.display = 'none';
|
package/src/engineDraw.js
CHANGED
|
@@ -83,7 +83,7 @@ let drawCount;
|
|
|
83
83
|
* Create a tile info object using a grid based system
|
|
84
84
|
* - This can take vecs or floats for easier use and conversion
|
|
85
85
|
* - If an index is passed in, the tile size and index will determine the position
|
|
86
|
-
* @param {Vector2|number} [pos=0] -
|
|
86
|
+
* @param {Vector2|number} [pos=0] - Position of the tile in pixels, or tile index
|
|
87
87
|
* @param {Vector2|number} [size=tileSizeDefault] - Size of tile in pixels
|
|
88
88
|
* @param {number} [textureIndex] - Texture index to use
|
|
89
89
|
* @param {number} [padding] - How many pixels padding around tiles
|
|
@@ -128,6 +128,7 @@ function tile(pos=new Vector2, size=tileSizeDefault, textureIndex=0, padding=0)
|
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
130
|
* Tile Info - Stores info about how to draw a tile
|
|
131
|
+
* @memberof Draw
|
|
131
132
|
*/
|
|
132
133
|
class TileInfo
|
|
133
134
|
{
|
|
@@ -188,7 +189,10 @@ class TileInfo
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
|
|
191
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* Tile Info - Stores info about each texture
|
|
194
|
+
* @memberof Draw
|
|
195
|
+
*/
|
|
192
196
|
class TextureInfo
|
|
193
197
|
{
|
|
194
198
|
/**
|
|
@@ -234,10 +238,11 @@ class TextureInfo
|
|
|
234
238
|
function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
235
239
|
angle=0, mirror, additiveColor, useWebGL=glEnable, screenSpace, context)
|
|
236
240
|
{
|
|
237
|
-
ASSERT(isVector2(pos), '
|
|
238
|
-
ASSERT(isVector2(size), '
|
|
239
|
-
ASSERT(isColor(color)
|
|
240
|
-
ASSERT(isNumber(angle), '
|
|
241
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
242
|
+
ASSERT(isVector2(size), 'size must be a vec2');
|
|
243
|
+
ASSERT(isColor(color), 'color is invalid');
|
|
244
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
245
|
+
ASSERT(!additiveColor || isColor(additiveColor), 'additiveColor must be a color');
|
|
241
246
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
242
247
|
|
|
243
248
|
const textureInfo = tileInfo && tileInfo.textureInfo;
|
|
@@ -332,10 +337,10 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
332
337
|
* @memberof Draw */
|
|
333
338
|
function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0, useWebGL=glEnable, screenSpace=false, context)
|
|
334
339
|
{
|
|
335
|
-
ASSERT(isVector2(pos), '
|
|
336
|
-
ASSERT(isVector2(size), '
|
|
337
|
-
ASSERT(isColor(colorTop) && isColor(colorBottom), '
|
|
338
|
-
ASSERT(isNumber(angle), '
|
|
340
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
341
|
+
ASSERT(isVector2(size), 'size must be a vec2');
|
|
342
|
+
ASSERT(isColor(colorTop) && isColor(colorBottom), 'color is invalid');
|
|
343
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
339
344
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
340
345
|
if (useWebGL)
|
|
341
346
|
{
|
|
@@ -393,11 +398,11 @@ function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0,
|
|
|
393
398
|
* @memberof Draw */
|
|
394
399
|
function drawLineList(points, width=.1, color, wrap=false, pos=vec2(), angle=0, useWebGL=glEnable, screenSpace, context)
|
|
395
400
|
{
|
|
396
|
-
ASSERT(Array.isArray(points), '
|
|
397
|
-
ASSERT(isNumber(width), '
|
|
398
|
-
ASSERT(isColor(color), '
|
|
399
|
-
ASSERT(isVector2(pos), '
|
|
400
|
-
ASSERT(isNumber(angle), '
|
|
401
|
+
ASSERT(Array.isArray(points), 'points must be an array');
|
|
402
|
+
ASSERT(isNumber(width), 'width must be a number');
|
|
403
|
+
ASSERT(isColor(color), 'color is invalid');
|
|
404
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
405
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
401
406
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
402
407
|
if (useWebGL)
|
|
403
408
|
{
|
|
@@ -468,8 +473,8 @@ function drawLine(posA, posB, width=.1, color, pos=vec2(), angle=0, useWebGL, sc
|
|
|
468
473
|
* @memberof Draw */
|
|
469
474
|
function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, lineColor=BLACK, angle=0, useWebGL=glEnable, screenSpace=false, context)
|
|
470
475
|
{
|
|
471
|
-
ASSERT(isVector2(size), '
|
|
472
|
-
ASSERT(isNumber(sides), '
|
|
476
|
+
ASSERT(isVector2(size), 'size must be a vec2');
|
|
477
|
+
ASSERT(isNumber(sides), 'sides must be a number');
|
|
473
478
|
|
|
474
479
|
// build regular polygon points
|
|
475
480
|
const points = [];
|
|
@@ -495,12 +500,13 @@ function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, l
|
|
|
495
500
|
* @memberof Draw */
|
|
496
501
|
function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(), angle=0, useWebGL=glEnable, screenSpace=false, context=undefined)
|
|
497
502
|
{
|
|
498
|
-
ASSERT(isVector2(pos), '
|
|
499
|
-
ASSERT(Array.isArray(points), '
|
|
500
|
-
ASSERT(isColor(color) && isColor(lineColor), '
|
|
501
|
-
ASSERT(isNumber(lineWidth), '
|
|
502
|
-
ASSERT(isNumber(angle), '
|
|
503
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
504
|
+
ASSERT(Array.isArray(points), 'points must be an array');
|
|
505
|
+
ASSERT(isColor(color) && isColor(lineColor), 'color is invalid');
|
|
506
|
+
ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
|
|
507
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
503
508
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
509
|
+
|
|
504
510
|
if (useWebGL)
|
|
505
511
|
{
|
|
506
512
|
let scale = 1;
|
|
@@ -547,13 +553,14 @@ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(),
|
|
|
547
553
|
* @memberof Draw */
|
|
548
554
|
function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
|
|
549
555
|
{
|
|
550
|
-
ASSERT(isVector2(pos), '
|
|
551
|
-
ASSERT(isVector2(size), '
|
|
552
|
-
ASSERT(isColor(color) && isColor(lineColor), '
|
|
553
|
-
ASSERT(isNumber(angle), '
|
|
554
|
-
ASSERT(isNumber(lineWidth), '
|
|
555
|
-
ASSERT(lineWidth >= 0 && lineWidth < size.x && lineWidth < size.y, '
|
|
556
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
557
|
+
ASSERT(isVector2(size), 'size must be a vec2');
|
|
558
|
+
ASSERT(isColor(color) && isColor(lineColor), 'color is invalid');
|
|
559
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
560
|
+
ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
|
|
561
|
+
ASSERT(lineWidth >= 0 && lineWidth < size.x && lineWidth < size.y, 'invalid lineWidth');
|
|
556
562
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
563
|
+
|
|
557
564
|
if (useWebGL)
|
|
558
565
|
{
|
|
559
566
|
// draw as a regular polygon
|
|
@@ -590,21 +597,32 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
590
597
|
* @memberof Draw */
|
|
591
598
|
function drawCircle(pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
|
|
592
599
|
{
|
|
593
|
-
ASSERT(isNumber(size), '
|
|
600
|
+
ASSERT(isNumber(size), 'size must be a number');
|
|
594
601
|
drawEllipse(pos, vec2(size), color, 0, lineWidth, lineColor, useWebGL, screenSpace, context);
|
|
595
602
|
}
|
|
596
603
|
|
|
604
|
+
/**
|
|
605
|
+
* @callback Canvas2DDrawFunction - A function that draws to a 2D canvas context
|
|
606
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
|
|
607
|
+
* @memberof Draw
|
|
608
|
+
*/
|
|
609
|
+
|
|
597
610
|
/** Draw directly to a 2d canvas context in world space
|
|
598
611
|
* @param {Vector2} pos
|
|
599
612
|
* @param {Vector2} size
|
|
600
613
|
* @param {number} angle
|
|
601
614
|
* @param {boolean} [mirror]
|
|
602
|
-
* @param {
|
|
615
|
+
* @param {Canvas2DDrawFunction} [drawFunction]
|
|
603
616
|
* @param {boolean} [screenSpace=false]
|
|
604
617
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
605
618
|
* @memberof Draw */
|
|
606
619
|
function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpace=false, context=drawContext)
|
|
607
620
|
{
|
|
621
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
622
|
+
ASSERT(isVector2(size), 'size must be a vec2');
|
|
623
|
+
ASSERT(isNumber(angle), 'angle must be a number');
|
|
624
|
+
ASSERT(typeof drawFunction === 'function', 'drawFunction must be a function');
|
|
625
|
+
|
|
608
626
|
if (!screenSpace)
|
|
609
627
|
{
|
|
610
628
|
// transform from world space to screen space
|
|
@@ -672,6 +690,16 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
|
|
|
672
690
|
* @memberof Draw */
|
|
673
691
|
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, maxWidth, context=overlayContext)
|
|
674
692
|
{
|
|
693
|
+
ASSERT(isString(text), 'text must be a string');
|
|
694
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
695
|
+
ASSERT(isNumber(size), 'size must be a number');
|
|
696
|
+
ASSERT(isColor(color), 'color must be a color');
|
|
697
|
+
ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
|
|
698
|
+
ASSERT(isColor(lineColor), 'lineColor must be a color');
|
|
699
|
+
ASSERT(isColor(lineColor), 'lineColor must be a color');
|
|
700
|
+
ASSERT(['left','center','right'].includes(textAlign), 'align must be left, center, or right');
|
|
701
|
+
ASSERT(isString(font), 'font must be a string');
|
|
702
|
+
|
|
675
703
|
context.fillStyle = color.toString();
|
|
676
704
|
context.strokeStyle = lineColor.toString();
|
|
677
705
|
context.lineWidth = lineWidth;
|
|
@@ -873,6 +901,7 @@ let engineFontImage;
|
|
|
873
901
|
* - 96 characters (from space to tilde) are stored in an image
|
|
874
902
|
* - Uses a default 8x8 font if none is supplied
|
|
875
903
|
* - You can also use fonts from the main tile sheet
|
|
904
|
+
* @memberof Draw
|
|
876
905
|
* @example
|
|
877
906
|
* // use built in font
|
|
878
907
|
* const font = new FontImage;
|
|
@@ -929,7 +958,7 @@ class FontImage
|
|
|
929
958
|
* @param {boolean} [center]
|
|
930
959
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
931
960
|
*/
|
|
932
|
-
drawTextScreen(text, pos, scale=4, center, context=overlayContext)
|
|
961
|
+
drawTextScreen(text, pos, scale=4, center=true, context=overlayContext)
|
|
933
962
|
{
|
|
934
963
|
context.save();
|
|
935
964
|
const size = this.tileSize;
|
package/src/engineExport.js
CHANGED
|
@@ -31,6 +31,7 @@ export
|
|
|
31
31
|
|
|
32
32
|
// Debug
|
|
33
33
|
ASSERT,
|
|
34
|
+
LOG,
|
|
34
35
|
debugRect,
|
|
35
36
|
debugPoly,
|
|
36
37
|
debugCircle,
|
|
@@ -177,6 +178,7 @@ export
|
|
|
177
178
|
isColor,
|
|
178
179
|
isVector2,
|
|
179
180
|
isNumber,
|
|
181
|
+
isString,
|
|
180
182
|
|
|
181
183
|
// Default Colors
|
|
182
184
|
WHITE,
|
|
@@ -312,7 +314,7 @@ export
|
|
|
312
314
|
tileCollisionGetData,
|
|
313
315
|
tileCollisionTest,
|
|
314
316
|
tileCollisionRaycast,
|
|
315
|
-
|
|
317
|
+
tileLayersLoad,
|
|
316
318
|
TileLayerData,
|
|
317
319
|
CanvasLayer,
|
|
318
320
|
TileLayer,
|
package/src/engineMedals.js
CHANGED
|
@@ -59,8 +59,14 @@ function medalsInit(saveName)
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @callback MedalCallbackFunction - Function that processes a medal
|
|
64
|
+
* @param {Medal} medal
|
|
65
|
+
* @memberof Medals
|
|
66
|
+
*/
|
|
67
|
+
|
|
62
68
|
/** Calls a function for each medal
|
|
63
|
-
* @param {
|
|
69
|
+
* @param {MedalCallbackFunction} callback
|
|
64
70
|
* @memberof Medals */
|
|
65
71
|
function medalsForEach(callback)
|
|
66
72
|
{ Object.values(medals).forEach(medal=>callback(medal)); }
|
|
@@ -69,6 +75,7 @@ function medalsForEach(callback)
|
|
|
69
75
|
|
|
70
76
|
/**
|
|
71
77
|
* Medal - Tracks an unlockable medal
|
|
78
|
+
* @memberof Medals
|
|
72
79
|
* @example
|
|
73
80
|
* // create a medal
|
|
74
81
|
* const medal_example = new Medal(0, 'Example Medal', 'More info about the medal goes here.', '🎖️');
|
|
@@ -137,11 +144,12 @@ class Medal
|
|
|
137
144
|
const height = medalDisplaySize.y;
|
|
138
145
|
const x = overlayCanvas.width - width;
|
|
139
146
|
const y = -height*hidePercent;
|
|
147
|
+
const backgroundColor = hsl(0,0,.9);
|
|
140
148
|
|
|
141
149
|
// draw containing rect and clip to that region
|
|
142
150
|
context.save();
|
|
143
151
|
context.beginPath();
|
|
144
|
-
context.fillStyle =
|
|
152
|
+
context.fillStyle = backgroundColor.toString();
|
|
145
153
|
context.strokeStyle = BLACK.toString();
|
|
146
154
|
context.lineWidth = 3;
|
|
147
155
|
context.rect(x, y, width, height);
|