littlejsengine 1.9.5 → 1.9.7
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 +76 -58
- package/dist/littlejs.esm.js +349 -221
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +346 -221
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +343 -217
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/index.html +2 -2
- package/examples/js13k/build.js +1 -0
- package/examples/js13k/index.html +13 -13
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/index.html +8 -8
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +1 -1
- package/examples/typescript/index.html +1 -1
- package/package.json +1 -1
- package/src/engine.js +64 -40
- package/src/engineAudio.js +67 -46
- package/src/engineDebug.js +3 -4
- package/src/engineDraw.js +13 -10
- package/src/engineExport.js +3 -0
- package/src/engineInput.js +80 -64
- package/src/engineObject.js +35 -9
- package/src/engineParticles.js +17 -13
- package/src/engineSettings.js +19 -3
- package/src/engineTileLayer.js +15 -4
- package/src/engineUtilities.js +13 -10
- package/src/engineWebGL.js +20 -18
- package/LittleJS.zip +0 -0
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
<link rel=icon type=image/png href=../favicon.png>
|
|
6
6
|
</head><body>
|
|
7
7
|
|
|
8
|
-
<script src=../../dist/littlejs.js?
|
|
9
|
-
<script src=gameObjects.js?
|
|
10
|
-
<script src=game.js?
|
|
8
|
+
<script src=../../dist/littlejs.js?196></script>
|
|
9
|
+
<script src=gameObjects.js?196></script>
|
|
10
|
+
<script src=game.js?196></script>
|
package/examples/js13k/build.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<head><title>LittleJS JS13K Project</title></head><body>
|
|
2
2
|
|
|
3
3
|
<!-- LittleJS Engine -->
|
|
4
|
-
<script src=../../src/engineDebug.js?
|
|
5
|
-
<script src=../../src/engineUtilities.js?
|
|
6
|
-
<script src=../../src/engineSettings.js?
|
|
7
|
-
<script src=../../src/engineObject.js?
|
|
8
|
-
<script src=../../src/engineDraw.js?
|
|
9
|
-
<script src=../../src/engineInput.js?
|
|
10
|
-
<script src=../../src/engineAudio.js?
|
|
11
|
-
<script src=../../src/engineTileLayer.js?
|
|
12
|
-
<script src=../../src/engineParticles.js?
|
|
13
|
-
<script src=../../src/engineMedals.js?
|
|
14
|
-
<script src=../../src/engineWebGL.js?
|
|
15
|
-
<script src=../../src/engine.js?
|
|
4
|
+
<script src=../../src/engineDebug.js?196></script>
|
|
5
|
+
<script src=../../src/engineUtilities.js?196></script>
|
|
6
|
+
<script src=../../src/engineSettings.js?196></script>
|
|
7
|
+
<script src=../../src/engineObject.js?196></script>
|
|
8
|
+
<script src=../../src/engineDraw.js?196></script>
|
|
9
|
+
<script src=../../src/engineInput.js?196></script>
|
|
10
|
+
<script src=../../src/engineAudio.js?196></script>
|
|
11
|
+
<script src=../../src/engineTileLayer.js?196></script>
|
|
12
|
+
<script src=../../src/engineParticles.js?196></script>
|
|
13
|
+
<script src=../../src/engineMedals.js?196></script>
|
|
14
|
+
<script src=../../src/engineWebGL.js?196></script>
|
|
15
|
+
<script src=../../src/engine.js?196></script>
|
|
16
16
|
|
|
17
17
|
<!-- Add your game scripts here -->
|
|
18
|
-
<script src=game.js?
|
|
18
|
+
<script src=game.js?196></script>
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
<link rel=icon type=image/png href=../favicon.png>
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
|
-
<script src=../../dist/littlejs.js?
|
|
10
|
-
<script src=gameObjects.js?
|
|
11
|
-
<script src=gameCharacter.js?
|
|
12
|
-
<script src=gamePlayer.js?
|
|
13
|
-
<script src=gameEffects.js?
|
|
14
|
-
<script src=gameLevel.js?
|
|
15
|
-
<script src=gameLevelData.js?
|
|
16
|
-
<script src=game.js?
|
|
9
|
+
<script src=../../dist/littlejs.js?196></script>
|
|
10
|
+
<script src=gameObjects.js?196></script>
|
|
11
|
+
<script src=gameCharacter.js?196></script>
|
|
12
|
+
<script src=gamePlayer.js?196></script>
|
|
13
|
+
<script src=gameEffects.js?196></script>
|
|
14
|
+
<script src=gameLevel.js?196></script>
|
|
15
|
+
<script src=gameLevelData.js?196></script>
|
|
16
|
+
<script src=game.js?196></script>
|
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
</head><body>
|
|
7
7
|
|
|
8
8
|
<!-- LittleJS Engine -->
|
|
9
|
-
<script src=../../src/engineDebug.js?
|
|
10
|
-
<script src=../../src/engineUtilities.js?
|
|
11
|
-
<script src=../../src/engineSettings.js?
|
|
12
|
-
<script src=../../src/engineObject.js?
|
|
13
|
-
<script src=../../src/engineDraw.js?
|
|
14
|
-
<script src=../../src/engineInput.js?
|
|
15
|
-
<script src=../../src/engineAudio.js?
|
|
16
|
-
<script src=../../src/engineTileLayer.js?
|
|
17
|
-
<script src=../../src/engineParticles.js?
|
|
18
|
-
<script src=../../src/engineMedals.js?
|
|
19
|
-
<script src=../../src/engineWebGL.js?
|
|
20
|
-
<script src=../../src/engine.js?
|
|
9
|
+
<script src=../../src/engineDebug.js?196></script>
|
|
10
|
+
<script src=../../src/engineUtilities.js?196></script>
|
|
11
|
+
<script src=../../src/engineSettings.js?196></script>
|
|
12
|
+
<script src=../../src/engineObject.js?196></script>
|
|
13
|
+
<script src=../../src/engineDraw.js?196></script>
|
|
14
|
+
<script src=../../src/engineInput.js?196></script>
|
|
15
|
+
<script src=../../src/engineAudio.js?196></script>
|
|
16
|
+
<script src=../../src/engineTileLayer.js?196></script>
|
|
17
|
+
<script src=../../src/engineParticles.js?196></script>
|
|
18
|
+
<script src=../../src/engineMedals.js?196></script>
|
|
19
|
+
<script src=../../src/engineWebGL.js?196></script>
|
|
20
|
+
<script src=../../src/engine.js?196></script>
|
|
21
21
|
|
|
22
22
|
<!-- Add your game scripts here -->
|
|
23
|
-
<script src=game.js?
|
|
23
|
+
<script src=game.js?196></script>
|
package/package.json
CHANGED
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.9.
|
|
33
|
+
const engineVersion = '1.9.7';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {Number}
|
|
@@ -107,7 +107,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
107
107
|
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
108
108
|
|
|
109
109
|
// setup gl rendering if enabled
|
|
110
|
-
|
|
110
|
+
glPreRender();
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// internal update loop for engine
|
|
@@ -126,11 +126,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
126
126
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
127
127
|
if (!debugSpeedUp)
|
|
128
128
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp in case of slow framerate
|
|
129
|
+
|
|
129
130
|
updateCanvas();
|
|
130
131
|
|
|
131
132
|
if (paused)
|
|
132
133
|
{
|
|
133
|
-
//
|
|
134
|
+
// update object transforms even when paused
|
|
135
|
+
for (const o of engineObjects)
|
|
136
|
+
o.parent || o.updateTransforms();
|
|
134
137
|
inputUpdate();
|
|
135
138
|
debugUpdate();
|
|
136
139
|
gameUpdatePost();
|
|
@@ -142,7 +145,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
142
145
|
let deltaSmooth = 0;
|
|
143
146
|
if (frameTimeBufferMS < 0 && frameTimeBufferMS > -9)
|
|
144
147
|
{
|
|
145
|
-
// force
|
|
148
|
+
// force at least one update each frame since it is waiting for refresh
|
|
146
149
|
deltaSmooth = frameTimeBufferMS;
|
|
147
150
|
frameTimeBufferMS = 0;
|
|
148
151
|
}
|
|
@@ -167,34 +170,37 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
167
170
|
// add the time smoothing back in
|
|
168
171
|
frameTimeBufferMS += deltaSmooth;
|
|
169
172
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
enginePreRender();
|
|
173
|
-
gameRender();
|
|
174
|
-
engineObjects.sort((a,b)=> a.renderOrder - b.renderOrder);
|
|
175
|
-
for (const o of engineObjects)
|
|
176
|
-
o.destroyed || o.render();
|
|
177
|
-
gameRenderPost();
|
|
178
|
-
glRenderPostProcess();
|
|
179
|
-
medalsRender();
|
|
180
|
-
touchGamepadRender();
|
|
181
|
-
debugRender();
|
|
182
|
-
glEnable && glCopyToContext(mainContext);
|
|
183
|
-
|
|
184
|
-
if (showWatermark)
|
|
173
|
+
|
|
174
|
+
if (!headlessMode)
|
|
185
175
|
{
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
176
|
+
// render sort then render while removing destroyed objects
|
|
177
|
+
enginePreRender();
|
|
178
|
+
gameRender();
|
|
179
|
+
engineObjects.sort((a,b)=> a.renderOrder - b.renderOrder);
|
|
180
|
+
for (const o of engineObjects)
|
|
181
|
+
o.destroyed || o.render();
|
|
182
|
+
gameRenderPost();
|
|
183
|
+
glRenderPostProcess();
|
|
184
|
+
medalsRender();
|
|
185
|
+
touchGamepadRender();
|
|
186
|
+
debugRender();
|
|
187
|
+
glCopyToContext(mainContext);
|
|
188
|
+
|
|
189
|
+
if (showWatermark)
|
|
190
|
+
{
|
|
191
|
+
// update fps
|
|
192
|
+
overlayContext.textAlign = 'right';
|
|
193
|
+
overlayContext.textBaseline = 'top';
|
|
194
|
+
overlayContext.font = '1em monospace';
|
|
195
|
+
overlayContext.fillStyle = '#000';
|
|
196
|
+
const text = engineName + ' ' + 'v' + engineVersion + ' / '
|
|
197
|
+
+ drawCount + ' / ' + engineObjects.length + ' / ' + averageFPS.toFixed(1)
|
|
198
|
+
+ (glEnable ? ' GL' : ' 2D') ;
|
|
199
|
+
overlayContext.fillText(text, mainCanvas.width-3, 3);
|
|
200
|
+
overlayContext.fillStyle = '#fff';
|
|
201
|
+
overlayContext.fillText(text, mainCanvas.width-2, 2);
|
|
202
|
+
drawCount = 0;
|
|
203
|
+
}
|
|
198
204
|
}
|
|
199
205
|
|
|
200
206
|
requestAnimationFrame(engineUpdate);
|
|
@@ -202,6 +208,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
202
208
|
|
|
203
209
|
function updateCanvas()
|
|
204
210
|
{
|
|
211
|
+
if (headlessMode) return;
|
|
212
|
+
|
|
205
213
|
if (canvasFixedSize.x)
|
|
206
214
|
{
|
|
207
215
|
// clear canvas and set fixed size
|
|
@@ -229,8 +237,20 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
229
237
|
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
230
238
|
}
|
|
231
239
|
|
|
240
|
+
function startEngine()
|
|
241
|
+
{
|
|
242
|
+
gameInit();
|
|
243
|
+
engineUpdate();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (headlessMode)
|
|
247
|
+
{
|
|
248
|
+
startEngine();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
232
252
|
// setup html
|
|
233
|
-
|
|
253
|
+
const styleBody =
|
|
234
254
|
'margin:0;overflow:hidden;' + // fill the window
|
|
235
255
|
'background:#000;' + // set background color
|
|
236
256
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
@@ -242,8 +262,10 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
242
262
|
mainContext = mainCanvas.getContext('2d');
|
|
243
263
|
|
|
244
264
|
// init stuff and start engine
|
|
265
|
+
inputInit();
|
|
266
|
+
audioInit();
|
|
245
267
|
debugInit();
|
|
246
|
-
|
|
268
|
+
glInit();
|
|
247
269
|
|
|
248
270
|
// create overlay canvas for hud to appear above gl canvas
|
|
249
271
|
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
@@ -284,12 +306,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
284
306
|
}));
|
|
285
307
|
|
|
286
308
|
// load all of the images
|
|
287
|
-
Promise.all(promises).then(
|
|
288
|
-
{
|
|
289
|
-
// start the engine
|
|
290
|
-
gameInit();
|
|
291
|
-
engineUpdate();
|
|
292
|
-
});
|
|
309
|
+
Promise.all(promises).then(startEngine);
|
|
293
310
|
}
|
|
294
311
|
|
|
295
312
|
/** Update each engine object, remove destroyed objects, and update time
|
|
@@ -310,7 +327,14 @@ function engineObjectsUpdate()
|
|
|
310
327
|
}
|
|
311
328
|
}
|
|
312
329
|
for (const o of engineObjects)
|
|
313
|
-
|
|
330
|
+
{
|
|
331
|
+
// update top level objects
|
|
332
|
+
if (!o.parent)
|
|
333
|
+
{
|
|
334
|
+
updateObject(o);
|
|
335
|
+
o.updateTransforms();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
314
338
|
|
|
315
339
|
// remove destroyed objects
|
|
316
340
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
package/src/engineAudio.js
CHANGED
|
@@ -11,6 +11,32 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
/** Audio context used by the engine
|
|
15
|
+
* @type {AudioContext}
|
|
16
|
+
* @memberof Audio */
|
|
17
|
+
let audioContext;
|
|
18
|
+
|
|
19
|
+
/** Master gain node for all audio to pass through
|
|
20
|
+
* @type {GainNode}
|
|
21
|
+
* @memberof Audio */
|
|
22
|
+
let audioGainNode;
|
|
23
|
+
|
|
24
|
+
function audioInit()
|
|
25
|
+
{
|
|
26
|
+
if (!soundEnable || headlessMode) return;
|
|
27
|
+
|
|
28
|
+
// create audio context
|
|
29
|
+
audioContext = new AudioContext;
|
|
30
|
+
|
|
31
|
+
// create and connect gain node
|
|
32
|
+
// (createGain is more widely spported then GainNode construtor)
|
|
33
|
+
audioGainNode = audioContext.createGain();
|
|
34
|
+
audioGainNode.connect(audioContext.destination);
|
|
35
|
+
setSoundVolume(soundVolume); // update gain volume
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
39
|
+
|
|
14
40
|
/**
|
|
15
41
|
* Sound Object - Stores a sound for later use and can be played positionally
|
|
16
42
|
*
|
|
@@ -31,7 +57,7 @@ class Sound
|
|
|
31
57
|
*/
|
|
32
58
|
constructor(zzfxSound, range=soundDefaultRange, taper=soundDefaultTaper)
|
|
33
59
|
{
|
|
34
|
-
if (!soundEnable) return;
|
|
60
|
+
if (!soundEnable || headlessMode) return;
|
|
35
61
|
|
|
36
62
|
/** @property {Number} - World space max range of sound, will not play if camera is farther away */
|
|
37
63
|
this.range = range;
|
|
@@ -45,8 +71,8 @@ class Sound
|
|
|
45
71
|
if (zzfxSound)
|
|
46
72
|
{
|
|
47
73
|
// generate zzfx sound now for fast playback
|
|
48
|
-
|
|
49
|
-
zzfxSound[1]
|
|
74
|
+
const defaultRandomness = .05;
|
|
75
|
+
this.randomness = zzfxSound[1] || defaultRandomness;
|
|
50
76
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
51
77
|
this.sampleRate = zzfxR;
|
|
52
78
|
}
|
|
@@ -62,7 +88,8 @@ class Sound
|
|
|
62
88
|
*/
|
|
63
89
|
play(pos, volume=1, pitch=1, randomnessScale=1, loop=false)
|
|
64
90
|
{
|
|
65
|
-
if (!soundEnable ||
|
|
91
|
+
if (!soundEnable || headlessMode) return;
|
|
92
|
+
if (!this.sampleChannels) return;
|
|
66
93
|
|
|
67
94
|
let pan;
|
|
68
95
|
if (pos)
|
|
@@ -139,14 +166,14 @@ class SoundWave extends Sound
|
|
|
139
166
|
* @param {Number} [randomness] - How much to randomize frequency each time sound plays
|
|
140
167
|
* @param {Number} [range=soundDefaultRange] - World space max range of sound, will not play if camera is farther away
|
|
141
168
|
* @param {Number} [taper=soundDefaultTaper] - At what percentage of range should it start tapering off
|
|
169
|
+
* @param {Function} [onloadCallback] - callback function to call when sound is loaded
|
|
142
170
|
*/
|
|
143
|
-
constructor(filename, randomness=0, range, taper)
|
|
171
|
+
constructor(filename, randomness=0, range, taper, onloadCallback)
|
|
144
172
|
{
|
|
145
173
|
super(undefined, range, taper);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!soundEnable) return;
|
|
174
|
+
if (!soundEnable || headlessMode) return;
|
|
149
175
|
|
|
176
|
+
this.randomness = randomness;
|
|
150
177
|
fetch(filename)
|
|
151
178
|
.then(response => response.arrayBuffer())
|
|
152
179
|
.then(arrayBuffer => audioContext.decodeAudioData(arrayBuffer))
|
|
@@ -156,10 +183,23 @@ class SoundWave extends Sound
|
|
|
156
183
|
for (let i = audioBuffer.numberOfChannels; i--;)
|
|
157
184
|
this.sampleChannels[i] = Array.from(audioBuffer.getChannelData(i));
|
|
158
185
|
this.sampleRate = audioBuffer.sampleRate;
|
|
159
|
-
});
|
|
186
|
+
}).then(() => onloadCallback && onloadCallback(this));
|
|
160
187
|
}
|
|
161
188
|
}
|
|
162
189
|
|
|
190
|
+
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
191
|
+
* @param {String} filename - Location of sound file to play
|
|
192
|
+
* @param {Number} [volume] - How much to scale volume by
|
|
193
|
+
* @param {Boolean} [loop] - True if the music should loop
|
|
194
|
+
* @return {SoundWave} - The sound object for this file
|
|
195
|
+
* @memberof Audio */
|
|
196
|
+
function playAudioFile(filename, volume=1, loop=false)
|
|
197
|
+
{
|
|
198
|
+
if (!soundEnable || headlessMode) return;
|
|
199
|
+
|
|
200
|
+
return new SoundWave(filename,0,0,0, s=>s.play(undefined, volume, 1, 1, loop));
|
|
201
|
+
}
|
|
202
|
+
|
|
163
203
|
/**
|
|
164
204
|
* Music Object - Stores a zzfx music track for later use
|
|
165
205
|
*
|
|
@@ -199,7 +239,7 @@ class Music extends Sound
|
|
|
199
239
|
{
|
|
200
240
|
super(undefined);
|
|
201
241
|
|
|
202
|
-
if (!soundEnable) return;
|
|
242
|
+
if (!soundEnable || headlessMode) return;
|
|
203
243
|
this.randomness = 0;
|
|
204
244
|
this.sampleChannels = zzfxM(...zzfxMusic);
|
|
205
245
|
this.sampleRate = zzfxR;
|
|
@@ -214,23 +254,6 @@ class Music extends Sound
|
|
|
214
254
|
{ return super.play(undefined, volume, 1, 1, loop); }
|
|
215
255
|
}
|
|
216
256
|
|
|
217
|
-
/** Play an mp3, ogg, or wav audio from a local file or url
|
|
218
|
-
* @param {String} filename - Location of sound file to play
|
|
219
|
-
* @param {Number} [volume] - How much to scale volume by
|
|
220
|
-
* @param {Boolean} [loop] - True if the music should loop
|
|
221
|
-
* @return {HTMLAudioElement} - The audio element for this sound
|
|
222
|
-
* @memberof Audio */
|
|
223
|
-
function playAudioFile(filename, volume=1, loop=false)
|
|
224
|
-
{
|
|
225
|
-
if (!soundEnable) return;
|
|
226
|
-
|
|
227
|
-
const audio = new Audio(filename);
|
|
228
|
-
audio.volume = soundVolume * volume;
|
|
229
|
-
audio.loop = loop;
|
|
230
|
-
audio.play();
|
|
231
|
-
return audio;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
257
|
/** Speak text with passed in settings
|
|
235
258
|
* @param {String} text - The text to speak
|
|
236
259
|
* @param {String} [language] - The language/accent to use (examples: en, it, ru, ja, zh)
|
|
@@ -241,7 +264,8 @@ function playAudioFile(filename, volume=1, loop=false)
|
|
|
241
264
|
* @memberof Audio */
|
|
242
265
|
function speak(text, language='', volume=1, rate=1, pitch=1)
|
|
243
266
|
{
|
|
244
|
-
if (!soundEnable ||
|
|
267
|
+
if (!soundEnable || headlessMode) return;
|
|
268
|
+
if (!speechSynthesis) return;
|
|
245
269
|
|
|
246
270
|
// common languages (not supported by all browsers)
|
|
247
271
|
// en - english, it - italian, fr - french, de - german, es - spanish
|
|
@@ -271,14 +295,8 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
271
295
|
|
|
272
296
|
///////////////////////////////////////////////////////////////////////////////
|
|
273
297
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
* @memberof Audio */
|
|
277
|
-
let audioContext = new AudioContext;
|
|
278
|
-
|
|
279
|
-
/** Keep track if audio was suspended when last sound was played
|
|
280
|
-
* @type {Boolean}
|
|
281
|
-
* @memberof Audio */
|
|
298
|
+
// internal tracking if audio was suspended when last sound was played
|
|
299
|
+
// allows first suspended sound to play when audio is resumed
|
|
282
300
|
let audioSuspended = false;
|
|
283
301
|
|
|
284
302
|
/** Play cached audio samples with given settings
|
|
@@ -292,7 +310,7 @@ let audioSuspended = false;
|
|
|
292
310
|
* @memberof Audio */
|
|
293
311
|
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=zzfxR)
|
|
294
312
|
{
|
|
295
|
-
if (!soundEnable) return;
|
|
313
|
+
if (!soundEnable || headlessMode) return;
|
|
296
314
|
|
|
297
315
|
// prevent sounds from building up if they can't be played
|
|
298
316
|
const audioWasSuspended = audioSuspended;
|
|
@@ -316,10 +334,13 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
316
334
|
source.playbackRate.value = rate;
|
|
317
335
|
source.loop = loop;
|
|
318
336
|
|
|
319
|
-
//
|
|
337
|
+
// set master gain volume
|
|
338
|
+
setSoundVolume(soundVolume);
|
|
339
|
+
|
|
340
|
+
// create and connect gain node
|
|
320
341
|
const gainNode = audioContext.createGain();
|
|
321
|
-
gainNode.gain.value =
|
|
322
|
-
gainNode.connect(
|
|
342
|
+
gainNode.gain.value = volume;
|
|
343
|
+
gainNode.connect(audioGainNode);
|
|
323
344
|
|
|
324
345
|
// connect source to stereo panner and gain
|
|
325
346
|
source.connect(new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)})).connect(gainNode);
|
|
@@ -338,7 +359,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
338
359
|
* @param {Array} zzfxSound - Array of ZzFX parameters, ex. [.5,.5]
|
|
339
360
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
340
361
|
* @memberof Audio */
|
|
341
|
-
function zzfx(...zzfxSound) { return
|
|
362
|
+
function zzfx(...zzfxSound) { return new Sound(zzfxSound).play(); }
|
|
342
363
|
|
|
343
364
|
/** Sample rate used for all ZzFX sounds
|
|
344
365
|
* @default 44100
|
|
@@ -347,7 +368,7 @@ const zzfxR = 44100;
|
|
|
347
368
|
|
|
348
369
|
/** Generate samples for a ZzFX sound
|
|
349
370
|
* @param {Number} [volume] - Volume scale (percent)
|
|
350
|
-
* @param {Number} [randomness] -
|
|
371
|
+
* @param {Number} [randomness] - Unused in this fuction, handled by Sound class
|
|
351
372
|
* @param {Number} [frequency] - Frequency of sound (Hz)
|
|
352
373
|
* @param {Number} [attack] - Attack time, how fast sound starts (seconds)
|
|
353
374
|
* @param {Number} [sustain] - Sustain time, how long sound holds (seconds)
|
|
@@ -373,17 +394,18 @@ const zzfxR = 44100;
|
|
|
373
394
|
function zzfxG
|
|
374
395
|
(
|
|
375
396
|
// parameters
|
|
376
|
-
volume = 1, randomness =
|
|
397
|
+
volume = 1, randomness = 0, frequency = 220, attack = 0, sustain = 0,
|
|
377
398
|
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
|
|
378
399
|
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
|
|
379
400
|
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
|
|
380
401
|
)
|
|
381
402
|
{
|
|
403
|
+
// LJS Note: ZZFX modded so randomness is handled by Sound class
|
|
404
|
+
|
|
382
405
|
// init parameters
|
|
383
406
|
let PI2 = PI*2, sampleRate = zzfxR,
|
|
384
407
|
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
|
|
385
|
-
startFrequency = frequency *=
|
|
386
|
-
rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
|
|
408
|
+
startFrequency = frequency *= PI2 / sampleRate,
|
|
387
409
|
b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
|
|
388
410
|
|
|
389
411
|
// biquad LP/HP filter
|
|
@@ -405,7 +427,6 @@ function zzfxG
|
|
|
405
427
|
pitchJump *= PI2 / sampleRate;
|
|
406
428
|
pitchJumpTime *= sampleRate;
|
|
407
429
|
repeatTime = repeatTime * sampleRate | 0;
|
|
408
|
-
volume *= soundVolume;
|
|
409
430
|
|
|
410
431
|
// generate waveform
|
|
411
432
|
for(length = attack + decay + sustain + release + delay | 0;
|
package/src/engineDebug.js
CHANGED
|
@@ -149,7 +149,7 @@ function debugClear() { debugPrimitives = []; }
|
|
|
149
149
|
* @param {String} [filename]
|
|
150
150
|
* @param {String} [type]
|
|
151
151
|
* @memberof Debug */
|
|
152
|
-
function debugSaveCanvas(canvas, filename=
|
|
152
|
+
function debugSaveCanvas(canvas, filename='screenshot', type='image/png')
|
|
153
153
|
{ debugSaveDataURL(canvas.toDataURL(type), filename); }
|
|
154
154
|
|
|
155
155
|
/** Save a text file to disk
|
|
@@ -157,7 +157,7 @@ function debugSaveCanvas(canvas, filename=engineName, type='image/png')
|
|
|
157
157
|
* @param {String} [filename]
|
|
158
158
|
* @param {String} [type]
|
|
159
159
|
* @memberof Debug */
|
|
160
|
-
function debugSaveText(text, filename=
|
|
160
|
+
function debugSaveText(text, filename='text', type='text/plain')
|
|
161
161
|
{ debugSaveDataURL(URL.createObjectURL(new Blob([text], {'type':type})), filename); }
|
|
162
162
|
|
|
163
163
|
/** Save a data url to disk
|
|
@@ -177,8 +177,7 @@ function debugSaveDataURL(dataURL, filename)
|
|
|
177
177
|
function debugInit()
|
|
178
178
|
{
|
|
179
179
|
// create link for saving screenshots
|
|
180
|
-
|
|
181
|
-
downloadLink.style.display = 'none';
|
|
180
|
+
downloadLink = document.createElement('a');
|
|
182
181
|
}
|
|
183
182
|
|
|
184
183
|
function debugUpdate()
|