littlejsengine 1.16.1 → 1.16.2
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 +91 -78
- package/dist/littlejs.esm.js +287 -272
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +279 -266
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +184 -175
- package/examples/box2d/gameObjects.js +5 -5
- package/examples/electron/index.html +2 -2
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/shorts/base.html +2 -1
- package/examples/starter/index.html +3 -2
- package/package.json +1 -1
- package/plugins/uiSystem.js +1 -1
- package/reference.md +5 -5
- package/src/engine.js +16 -28
- package/src/engineAudio.js +2 -4
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +96 -94
- package/src/engineDraw.js +8 -28
- package/src/engineExport.js +8 -6
- package/src/engineInput.js +3 -6
- package/src/engineMath.js +1201 -0
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +1 -2
- package/src/engineRelease.js +1 -3
- package/src/engineSettings.js +2 -2
- package/src/engineTileLayer.js +7 -9
- package/src/engineUtilities.js +34 -1179
- package/src/engineWebGL.js +7 -10
|
@@ -478,11 +478,11 @@ export function explosion(pos, radius=3, strength=300)
|
|
|
478
478
|
|
|
479
479
|
// fire
|
|
480
480
|
new LJS.ParticleEmitter(
|
|
481
|
-
pos, 0,
|
|
482
|
-
radius, .1, 100*radius, 3.14,
|
|
483
|
-
Game.spriteAtlas.dot,
|
|
484
|
-
hsl(0
|
|
485
|
-
hsl(0,1,.5,0), hsl(.1, 1,.5,0)
|
|
481
|
+
pos, 0, // pos, angle
|
|
482
|
+
radius, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
|
|
483
|
+
Game.spriteAtlas.dot, // tileInfo
|
|
484
|
+
hsl(0,.8,.5), hsl(.15,.8,.5), // colorStartA, colorStartB
|
|
485
|
+
hsl(0,1,.5,0), hsl(.1, 1,.5,0),// colorEndA, colorEndB
|
|
486
486
|
.7, 1, .5, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
487
487
|
.9, 1, 0, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
488
488
|
1, 0, 1, 0, 1e9 // randomness, collide, additive, colorLinear, renderOrder
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.16.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.16.2></script>
|
|
11
11
|
|
|
12
12
|
<!-- Add your game scripts here -->
|
|
13
|
-
<script src=game.js?1.16.
|
|
13
|
+
<script src=game.js?1.16.2></script>
|
package/examples/logo.png
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -128,7 +128,7 @@ export function explosion(pos, radius=3)
|
|
|
128
128
|
pos, 0, // pos, angle
|
|
129
129
|
radius/2, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
|
|
130
130
|
0, // tileInfo
|
|
131
|
-
rgb(1,.5,.1),
|
|
131
|
+
rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
|
|
132
132
|
rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
|
|
133
133
|
.7, .8, .2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
|
|
134
134
|
.9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<!DOCTYPE html><meta charset=utf-8><body>
|
|
2
|
-
<script src=../../dist/littlejs.js?1.16.
|
|
2
|
+
<script src=../../dist/littlejs.js?1.16.2></script>
|
|
3
3
|
<script src=../../dist/box2d.wasm.js></script>
|
|
4
4
|
|
|
5
5
|
<!-- LittleJS Engine Source
|
|
6
6
|
<script src=../../src/engine.js></script>
|
|
7
7
|
<script src=../../src/engineDebug.js></script>
|
|
8
|
+
<script src=../../src/engineMath.js></script>
|
|
8
9
|
<script src=../../src/engineUtilities.js></script>
|
|
9
10
|
<script src=../../src/engineSettings.js></script>
|
|
10
11
|
<script src=../../src/engineObject.js></script>
|
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.16.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.16.2></script>
|
|
11
11
|
|
|
12
12
|
<!-- LittleJS Engine Source
|
|
13
13
|
<script src=../../src/engine.js></script>
|
|
14
14
|
<script src=../../src/engineDebug.js></script>
|
|
15
|
+
<script src=../../src/engineMath.js></script>
|
|
15
16
|
<script src=../../src/engineUtilities.js></script>
|
|
16
17
|
<script src=../../src/engineSettings.js></script>
|
|
17
18
|
<script src=../../src/engineObject.js></script>
|
|
@@ -31,4 +32,4 @@
|
|
|
31
32
|
-->
|
|
32
33
|
|
|
33
34
|
<!-- Add your game scripts here -->
|
|
34
|
-
<script src=game.js?1.16.
|
|
35
|
+
<script src=game.js?1.16.2></script>
|
package/package.json
CHANGED
package/plugins/uiSystem.js
CHANGED
|
@@ -762,7 +762,7 @@ class UIObject
|
|
|
762
762
|
this.onUpdate();
|
|
763
763
|
|
|
764
764
|
// unset active if disabled
|
|
765
|
-
if (this.disabled && this
|
|
765
|
+
if (this.disabled && this === uiSystem.activeObject)
|
|
766
766
|
uiSystem.activeObject = undefined;
|
|
767
767
|
|
|
768
768
|
const wasHover = uiSystem.lastHoverObject === this;
|
package/reference.md
CHANGED
|
@@ -428,11 +428,11 @@ debugCircle(pos, size, color='#fff', time=0, fill) // Draw debug circle
|
|
|
428
428
|
debugPoint(pos, color, time, angle) // Draw debug point
|
|
429
429
|
debugLine(posA, posB, color, width=.1, time) // Draw debug line
|
|
430
430
|
debugText(text, pos, size=1, color='#fff', time=0, angle=0) // Draw debug text
|
|
431
|
-
debugAABB(pA, sA, pB, sB, color)
|
|
432
|
-
debugClear()
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
431
|
+
debugAABB(pA, sA, pB, sB, color) // Draw a debug axis aligned box
|
|
432
|
+
debugClear() // Clear all debug primitives
|
|
433
|
+
saveCanvas(canvas, filename) // Save canvas to a file
|
|
434
|
+
saveText(text, filename) // Save text to a file
|
|
435
|
+
saveDataURL(dataURL, filename) // Save url to a file
|
|
436
436
|
|
|
437
437
|
// Debug settings
|
|
438
438
|
debug // Is debug enabled?
|
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.16.
|
|
33
|
+
const engineVersion = '1.16.2';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -269,33 +269,20 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
269
269
|
if (!wasUpdated)
|
|
270
270
|
updateCanvas();
|
|
271
271
|
|
|
272
|
-
// render
|
|
272
|
+
// render the game and objects
|
|
273
273
|
enginePreRender();
|
|
274
274
|
gameRender();
|
|
275
275
|
engineObjects.sort((a,b)=> a.renderOrder - b.renderOrder);
|
|
276
276
|
for (const o of engineObjects)
|
|
277
277
|
o.destroyed || o.render();
|
|
278
|
+
|
|
279
|
+
// post rendering
|
|
278
280
|
gameRenderPost();
|
|
279
281
|
pluginList.forEach(plugin=>plugin.render?.());
|
|
280
282
|
inputRender();
|
|
281
283
|
debugRender();
|
|
282
284
|
glFlush();
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (debugWatermark && !debugVideoCaptureIsActive())
|
|
286
|
-
{
|
|
287
|
-
// update fps display
|
|
288
|
-
mainContext.textAlign = 'right';
|
|
289
|
-
mainContext.textBaseline = 'top';
|
|
290
|
-
mainContext.font = '1em monospace';
|
|
291
|
-
mainContext.fillStyle = '#000';
|
|
292
|
-
const text = engineName + ' ' + 'v' + engineVersion + ' / '
|
|
293
|
-
+ drawCount + ' / ' + engineObjects.length + ' / ' + averageFPS.toFixed(1)
|
|
294
|
-
+ (glEnable ? ' GL' : ' 2D') ;
|
|
295
|
-
mainContext.fillText(text, mainCanvas.width-3, 3);
|
|
296
|
-
mainContext.fillStyle = '#fff';
|
|
297
|
-
mainContext.fillText(text, mainCanvas.width-2, 2);
|
|
298
|
-
}
|
|
285
|
+
debugRenderPost();
|
|
299
286
|
drawCount = 0;
|
|
300
287
|
}
|
|
301
288
|
}
|
|
@@ -361,15 +348,9 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
361
348
|
mainContext.lineJoin = 'round';
|
|
362
349
|
mainContext.lineCap = 'round';
|
|
363
350
|
}
|
|
364
|
-
|
|
365
|
-
//
|
|
366
|
-
|
|
367
|
-
{
|
|
368
|
-
await gameInit();
|
|
369
|
-
engineUpdate();
|
|
370
|
-
}
|
|
371
|
-
if (headlessMode)
|
|
372
|
-
return startEngine();
|
|
351
|
+
|
|
352
|
+
// skip setup if headless
|
|
353
|
+
if (headlessMode) return startEngine();
|
|
373
354
|
|
|
374
355
|
// setup webgl
|
|
375
356
|
glInit(rootElement);
|
|
@@ -384,7 +365,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
384
365
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
385
366
|
'-webkit-touch-callout:none'; // compatibility for ios
|
|
386
367
|
rootElement.style.cssText = styleRoot;
|
|
387
|
-
|
|
368
|
+
mainCanvas = rootElement.appendChild(document.createElement('canvas'));
|
|
388
369
|
drawContext = mainContext = mainCanvas.getContext('2d');
|
|
389
370
|
|
|
390
371
|
// init stuff and start engine
|
|
@@ -459,6 +440,13 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
459
440
|
await Promise.all(promises);
|
|
460
441
|
return startEngine();
|
|
461
442
|
|
|
443
|
+
async function startEngine()
|
|
444
|
+
{
|
|
445
|
+
// wait for gameInit to load
|
|
446
|
+
await gameInit();
|
|
447
|
+
engineUpdate();
|
|
448
|
+
}
|
|
449
|
+
|
|
462
450
|
///////////////////////////////////////////////////////////////////////////
|
|
463
451
|
// LittleJS Splash Screen
|
|
464
452
|
function drawEngineSplashScreen(t)
|
package/src/engineAudio.js
CHANGED
|
@@ -383,8 +383,7 @@ class SoundInstance
|
|
|
383
383
|
/** Pause this sound instance */
|
|
384
384
|
pause()
|
|
385
385
|
{
|
|
386
|
-
if (this.isPaused())
|
|
387
|
-
return;
|
|
386
|
+
if (this.isPaused()) return;
|
|
388
387
|
|
|
389
388
|
// save current time and stop sound
|
|
390
389
|
this.pausedTime = this.getCurrentTime();
|
|
@@ -396,8 +395,7 @@ class SoundInstance
|
|
|
396
395
|
/** Unpauses this sound instance */
|
|
397
396
|
resume()
|
|
398
397
|
{
|
|
399
|
-
if (!this.isPaused())
|
|
400
|
-
return;
|
|
398
|
+
if (!this.isPaused()) return;
|
|
401
399
|
|
|
402
400
|
// restart sound from paused time
|
|
403
401
|
this.start(this.pausedTime);
|
package/src/engineBuild.js
CHANGED
package/src/engineDebug.js
CHANGED
|
@@ -41,7 +41,7 @@ let debugKey = 'Escape';
|
|
|
41
41
|
let debugOverlay = false;
|
|
42
42
|
|
|
43
43
|
// Engine internal variables not exposed to documentation
|
|
44
|
-
let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParticles = false, debugGamepads = false, debugMedals = false, debugTakeScreenshot
|
|
44
|
+
let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParticles = false, debugGamepads = false, debugMedals = false, debugTakeScreenshot;
|
|
45
45
|
|
|
46
46
|
///////////////////////////////////////////////////////////////////////////////
|
|
47
47
|
// Debug helper functions
|
|
@@ -228,46 +228,6 @@ function debugClear() { debugPrimitives = []; }
|
|
|
228
228
|
* @memberof Debug */
|
|
229
229
|
function debugScreenshot() { debugTakeScreenshot = 1; }
|
|
230
230
|
|
|
231
|
-
/** Save a canvas to disk
|
|
232
|
-
* @param {HTMLCanvasElement|OffscreenCanvas} canvas
|
|
233
|
-
* @param {string} [filename]
|
|
234
|
-
* @param {string} [type]
|
|
235
|
-
* @memberof Debug */
|
|
236
|
-
function debugSaveCanvas(canvas, filename='screenshot', type='image/png')
|
|
237
|
-
{
|
|
238
|
-
if (canvas instanceof OffscreenCanvas)
|
|
239
|
-
{
|
|
240
|
-
// copy to temporary canvas and save
|
|
241
|
-
if (!debugCanvas)
|
|
242
|
-
debugCanvas = document.createElement('canvas');
|
|
243
|
-
debugCanvas.width = canvas.width;
|
|
244
|
-
debugCanvas.height = canvas.height;
|
|
245
|
-
debugCanvas.getContext('2d').drawImage(canvas, 0, 0);
|
|
246
|
-
debugSaveDataURL(debugCanvas.toDataURL(type), filename);
|
|
247
|
-
}
|
|
248
|
-
else
|
|
249
|
-
debugSaveDataURL(canvas.toDataURL(type), filename);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/** Save a text file to disk
|
|
253
|
-
* @param {string} text
|
|
254
|
-
* @param {string} [filename]
|
|
255
|
-
* @param {string} [type]
|
|
256
|
-
* @memberof Debug */
|
|
257
|
-
function debugSaveText(text, filename='text', type='text/plain')
|
|
258
|
-
{ debugSaveDataURL(URL.createObjectURL(new Blob([text], {'type':type})), filename); }
|
|
259
|
-
|
|
260
|
-
/** Save a data url to disk
|
|
261
|
-
* @param {string} dataURL
|
|
262
|
-
* @param {string} filename
|
|
263
|
-
* @memberof Debug */
|
|
264
|
-
function debugSaveDataURL(dataURL, filename)
|
|
265
|
-
{
|
|
266
|
-
downloadLink.download = filename;
|
|
267
|
-
downloadLink.href = dataURL;
|
|
268
|
-
downloadLink.click();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
231
|
/** Breaks on all asserts/errors, hides the canvas, and shows message in plain text
|
|
272
232
|
* This is a good function to call at the start of your game to catch all errors
|
|
273
233
|
* In release builds this function has no effect
|
|
@@ -303,21 +263,11 @@ function debugShowErrors()
|
|
|
303
263
|
|
|
304
264
|
function debugInit()
|
|
305
265
|
{
|
|
306
|
-
// create link for saving screenshots
|
|
307
|
-
downloadLink = document.createElement('a');
|
|
308
266
|
}
|
|
309
267
|
|
|
310
268
|
function debugUpdate()
|
|
311
269
|
{
|
|
312
|
-
if (!debug)
|
|
313
|
-
return;
|
|
314
|
-
|
|
315
|
-
if (debugVideoCaptureIsActive())
|
|
316
|
-
{
|
|
317
|
-
// control to stop video capture
|
|
318
|
-
if (keyWasPressed('Digit6') || keyWasPressed(debugKey))
|
|
319
|
-
debugVideoCaptureStop();
|
|
320
|
-
}
|
|
270
|
+
if (!debug) return;
|
|
321
271
|
|
|
322
272
|
if (keyWasPressed(debugKey)) // Esc
|
|
323
273
|
debugOverlay = !debugOverlay;
|
|
@@ -335,9 +285,15 @@ function debugUpdate()
|
|
|
335
285
|
debugRaycast = !debugRaycast;
|
|
336
286
|
if (keyWasPressed('Digit5'))
|
|
337
287
|
debugScreenshot();
|
|
338
|
-
if (keyWasPressed('Digit6') && !debugVideoCaptureIsActive())
|
|
339
|
-
debugVideoCaptureStart();
|
|
340
288
|
}
|
|
289
|
+
if (debugVideoCaptureIsActive())
|
|
290
|
+
{
|
|
291
|
+
// control to stop video capture
|
|
292
|
+
if (!debugOverlay || keyWasPressed('Digit6'))
|
|
293
|
+
debugVideoCaptureStop();
|
|
294
|
+
}
|
|
295
|
+
else if (debugOverlay && keyWasPressed('Digit6'))
|
|
296
|
+
debugVideoCaptureStart();
|
|
341
297
|
}
|
|
342
298
|
|
|
343
299
|
function debugRender()
|
|
@@ -352,7 +308,7 @@ function debugRender()
|
|
|
352
308
|
{
|
|
353
309
|
// combine canvases, remove alpha and save
|
|
354
310
|
combineCanvases();
|
|
355
|
-
|
|
311
|
+
saveCanvas(mainCanvas);
|
|
356
312
|
debugTakeScreenshot = 0;
|
|
357
313
|
}
|
|
358
314
|
|
|
@@ -598,11 +554,34 @@ function debugRender()
|
|
|
598
554
|
}
|
|
599
555
|
}
|
|
600
556
|
|
|
557
|
+
function debugRenderPost()
|
|
558
|
+
{
|
|
559
|
+
if (debugVideoCaptureIsActive())
|
|
560
|
+
{
|
|
561
|
+
debugVideoCaptureUpdate();
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (!debugWatermark) return;
|
|
566
|
+
|
|
567
|
+
// update fps display
|
|
568
|
+
mainContext.textAlign = 'right';
|
|
569
|
+
mainContext.textBaseline = 'top';
|
|
570
|
+
mainContext.font = '1em monospace';
|
|
571
|
+
mainContext.fillStyle = '#000';
|
|
572
|
+
const text = engineName + ' v' + engineVersion + ' / '
|
|
573
|
+
+ drawCount + ' / ' + engineObjects.length + ' / ' + averageFPS.toFixed(1)
|
|
574
|
+
+ (glEnable ? ' GL' : ' 2D') ;
|
|
575
|
+
mainContext.fillText(text, mainCanvas.width-3, 3);
|
|
576
|
+
mainContext.fillStyle = '#fff';
|
|
577
|
+
mainContext.fillText(text, mainCanvas.width-2, 2);
|
|
578
|
+
}
|
|
579
|
+
|
|
601
580
|
///////////////////////////////////////////////////////////////////////////////
|
|
602
581
|
// video capture - records video and audio at 60 fps using MediaRecorder API
|
|
603
582
|
|
|
604
583
|
// internal variables used to capture video
|
|
605
|
-
let debugVideoCapture,
|
|
584
|
+
let debugVideoCapture, debugVideoCaptureIcon;
|
|
606
585
|
|
|
607
586
|
/** Check if video capture is active
|
|
608
587
|
* @memberof Debug */
|
|
@@ -612,80 +591,103 @@ function debugVideoCaptureIsActive() { return !!debugVideoCapture; }
|
|
|
612
591
|
* @memberof Debug */
|
|
613
592
|
function debugVideoCaptureStart()
|
|
614
593
|
{
|
|
615
|
-
|
|
616
|
-
return; // already recording
|
|
594
|
+
ASSERT(!debugVideoCaptureIsActive(), 'Already capturing video!');
|
|
617
595
|
|
|
618
|
-
|
|
596
|
+
if (!debugVideoCaptureIcon)
|
|
597
|
+
{
|
|
598
|
+
// create recording icon to show it is capturing video
|
|
599
|
+
debugVideoCaptureIcon = document.createElement('div');
|
|
600
|
+
debugVideoCaptureIcon.style.position = 'absolute';
|
|
601
|
+
debugVideoCaptureIcon.style.padding = '9px';
|
|
602
|
+
debugVideoCaptureIcon.style.color = '#f00';
|
|
603
|
+
debugVideoCaptureIcon.style.font = '50px monospace';
|
|
604
|
+
document.body.appendChild(debugVideoCaptureIcon);
|
|
605
|
+
}
|
|
606
|
+
// show recording icon
|
|
607
|
+
debugVideoCaptureIcon.textContent = '';
|
|
608
|
+
debugVideoCaptureIcon.style.display = '';
|
|
609
|
+
|
|
610
|
+
// setup captureStream to capture manually by passing 0
|
|
619
611
|
const stream = mainCanvas.captureStream(0);
|
|
612
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
613
|
+
const captureTimer = new Timer(0, true);
|
|
620
614
|
const chunks = [];
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
615
|
+
videoTrack.applyConstraints({frameRate:frameRate});
|
|
616
|
+
|
|
617
|
+
// set up the media recorder
|
|
618
|
+
const mediaRecorder = new MediaRecorder(stream,
|
|
619
|
+
{mimeType:'video/webm;codecs=vp8'});
|
|
620
|
+
mediaRecorder.ondataavailable = (e)=> chunks.push(e.data);
|
|
621
|
+
mediaRecorder.onstop = ()=>
|
|
627
622
|
{
|
|
628
623
|
const blob = new Blob(chunks, {type: 'video/webm'});
|
|
629
624
|
const url = URL.createObjectURL(blob);
|
|
630
|
-
|
|
631
|
-
downloadLink.href = url;
|
|
632
|
-
downloadLink.click();
|
|
633
|
-
URL.revokeObjectURL(url);
|
|
625
|
+
saveDataURL(url, 'capture.webm', 1e3);
|
|
634
626
|
};
|
|
635
627
|
|
|
636
|
-
|
|
628
|
+
let audioStreamDestination, silentAudioSource;
|
|
629
|
+
if (soundEnable)
|
|
637
630
|
{
|
|
631
|
+
// create silent audio source
|
|
632
|
+
// fixes issue where video can not start recording without audio
|
|
633
|
+
silentAudioSource = new ConstantSourceNode(audioContext, { offset: 0 });
|
|
634
|
+
silentAudioSource.connect(audioMasterGain);
|
|
635
|
+
silentAudioSource.start();
|
|
636
|
+
|
|
638
637
|
// connect to audio master gain node
|
|
639
|
-
|
|
638
|
+
audioStreamDestination = audioContext.createMediaStreamDestination();
|
|
640
639
|
audioMasterGain.connect(audioStreamDestination);
|
|
641
640
|
for (const track of audioStreamDestination.stream.getAudioTracks())
|
|
642
641
|
stream.addTrack(track); // add audio tracks to capture stream
|
|
643
642
|
}
|
|
644
643
|
|
|
645
644
|
// start recording
|
|
645
|
+
try { mediaRecorder.start(); }
|
|
646
|
+
catch(e)
|
|
647
|
+
{
|
|
648
|
+
LOG('Video capture not supported in this browser!');
|
|
649
|
+
silentAudioSource?.stop();
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
646
653
|
LOG('Video capture started.');
|
|
647
|
-
debugVideoCapture.start();
|
|
648
|
-
debugVideoCaptureTimer = new Timer(0, true);
|
|
649
654
|
|
|
650
|
-
|
|
655
|
+
// save debug video info
|
|
656
|
+
debugVideoCapture =
|
|
651
657
|
{
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
document.body.appendChild(debugVideoCaptureIcon);
|
|
659
|
-
}
|
|
660
|
-
// show recording icon
|
|
661
|
-
debugVideoCaptureIcon.textContent = '';
|
|
662
|
-
debugVideoCaptureIcon.style.display = '';
|
|
658
|
+
mediaRecorder,
|
|
659
|
+
captureTimer,
|
|
660
|
+
videoTrack,
|
|
661
|
+
silentAudioSource,
|
|
662
|
+
audioStreamDestination
|
|
663
|
+
};
|
|
663
664
|
}
|
|
664
665
|
|
|
665
666
|
/** Stop capturing video and save to disk
|
|
666
667
|
* @memberof Debug */
|
|
667
668
|
function debugVideoCaptureStop()
|
|
668
669
|
{
|
|
669
|
-
|
|
670
|
-
return; // not recording
|
|
670
|
+
ASSERT(debugVideoCaptureIsActive(), 'Not capturing video!');
|
|
671
671
|
|
|
672
672
|
// stop recording
|
|
673
|
-
LOG(`Video capture ended. ${
|
|
674
|
-
debugVideoCapture.stop();
|
|
675
|
-
debugVideoCapture = 0;
|
|
673
|
+
LOG(`Video capture ended. ${debugVideoCapture.captureTimer.get().toFixed(2)} seconds recorded.`);
|
|
676
674
|
debugVideoCaptureIcon.style.display = 'none';
|
|
675
|
+
debugVideoCapture.silentAudioSource?.stop();
|
|
676
|
+
debugVideoCapture.mediaRecorder?.stop();
|
|
677
|
+
debugVideoCapture.videoTrack?.stop();
|
|
678
|
+
debugVideoCapture = undefined;
|
|
677
679
|
}
|
|
678
680
|
|
|
679
681
|
// update video capture, called automatically by engine
|
|
680
682
|
function debugVideoCaptureUpdate()
|
|
681
683
|
{
|
|
682
|
-
|
|
683
|
-
return; // not recording
|
|
684
|
+
ASSERT(debugVideoCaptureIsActive(), 'Not capturing video!');
|
|
684
685
|
|
|
685
686
|
// save the video frame
|
|
686
687
|
combineCanvases();
|
|
687
|
-
|
|
688
|
-
debugVideoCaptureIcon.textContent = '● REC '
|
|
688
|
+
debugVideoCapture.videoTrack.requestFrame();
|
|
689
|
+
debugVideoCaptureIcon.textContent = '● REC '
|
|
690
|
+
+ formatTime(debugVideoCapture.captureTimer);
|
|
689
691
|
}
|
|
690
692
|
|
|
691
693
|
///////////////////////////////////////////////////////////////////////////////
|
package/src/engineDraw.js
CHANGED
|
@@ -31,11 +31,6 @@ let mainCanvas;
|
|
|
31
31
|
* @memberof Draw */
|
|
32
32
|
let mainContext;
|
|
33
33
|
|
|
34
|
-
/** The default canvas to use for drawing, usually mainCanvas
|
|
35
|
-
* @type {HTMLCanvasElement|OffscreenCanvas}
|
|
36
|
-
* @memberof Draw */
|
|
37
|
-
let drawCanvas;
|
|
38
|
-
|
|
39
34
|
/** The default 2d context to use for drawing, usually mainContext
|
|
40
35
|
* @type {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}
|
|
41
36
|
* @memberof Draw */
|
|
@@ -623,7 +618,11 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
|
|
|
623
618
|
ASSERT(typeof drawFunction === 'function', 'drawFunction must be a function');
|
|
624
619
|
|
|
625
620
|
if (!screenSpace)
|
|
626
|
-
|
|
621
|
+
{
|
|
622
|
+
pos = worldToScreen(pos);
|
|
623
|
+
size = size.scale(cameraScale);
|
|
624
|
+
angle -= cameraAngle;
|
|
625
|
+
}
|
|
627
626
|
context.save();
|
|
628
627
|
context.translate(pos.x+.5, pos.y+.5);
|
|
629
628
|
context.rotate(angle);
|
|
@@ -675,9 +674,9 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
675
674
|
* @param {string} [fontStyle]
|
|
676
675
|
* @param {number} [maxWidth]
|
|
677
676
|
* @param {number} [angle]
|
|
678
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=
|
|
677
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
679
678
|
* @memberof Draw */
|
|
680
|
-
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=
|
|
679
|
+
function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=drawContext)
|
|
681
680
|
{
|
|
682
681
|
ASSERT(isString(text), 'text must be a string');
|
|
683
682
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
@@ -818,25 +817,6 @@ function screenToWorldTransform(screenPos, screenSize, screenAngle=0)
|
|
|
818
817
|
];
|
|
819
818
|
}
|
|
820
819
|
|
|
821
|
-
/** Convert world space transform to screen space
|
|
822
|
-
* @param {Vector2} worldPos
|
|
823
|
-
* @param {Vector2} worldSize
|
|
824
|
-
* @param {number} [worldAngle]
|
|
825
|
-
* @return {[Vector2, Vector2, number]} - [pos, size, angle]
|
|
826
|
-
* @memberof Draw */
|
|
827
|
-
function worldToScreenTransform(worldPos, worldSize, worldAngle=0)
|
|
828
|
-
{
|
|
829
|
-
ASSERT(isVector2(worldPos), 'worldPos must be a vec2');
|
|
830
|
-
ASSERT(isVector2(worldSize), 'worldSize must be a vec2');
|
|
831
|
-
ASSERT(isNumber(worldAngle), 'worldAngle must be a number');
|
|
832
|
-
|
|
833
|
-
return [
|
|
834
|
-
worldToScreen(worldPos),
|
|
835
|
-
worldSize.scale(cameraScale),
|
|
836
|
-
worldAngle - cameraAngle
|
|
837
|
-
];
|
|
838
|
-
}
|
|
839
|
-
|
|
840
820
|
/** Get the size of the camera window in world space
|
|
841
821
|
* @return {Vector2}
|
|
842
822
|
* @memberof Draw */
|
|
@@ -1059,7 +1039,7 @@ class FontImage
|
|
|
1059
1039
|
* @param {boolean} [center]
|
|
1060
1040
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
1061
1041
|
*/
|
|
1062
|
-
drawTextScreen(text, pos, scale=4, center=true, context=
|
|
1042
|
+
drawTextScreen(text, pos, scale=4, center=true, context=drawContext)
|
|
1063
1043
|
{
|
|
1064
1044
|
context.save();
|
|
1065
1045
|
const size = this.tileSize;
|
package/src/engineExport.js
CHANGED
|
@@ -41,13 +41,10 @@ export
|
|
|
41
41
|
debugText,
|
|
42
42
|
debugClear,
|
|
43
43
|
debugScreenshot,
|
|
44
|
-
debugSaveCanvas,
|
|
45
|
-
debugSaveText,
|
|
46
|
-
debugSaveDataURL,
|
|
47
44
|
debugShowErrors,
|
|
48
|
-
debugVideoCaptureIsActive,
|
|
49
45
|
debugVideoCaptureStart,
|
|
50
46
|
debugVideoCaptureStop,
|
|
47
|
+
debugVideoCaptureIsActive,
|
|
51
48
|
|
|
52
49
|
// Settings
|
|
53
50
|
cameraPos,
|
|
@@ -144,7 +141,7 @@ export
|
|
|
144
141
|
setDebugWatermark,
|
|
145
142
|
setDebugKey,
|
|
146
143
|
|
|
147
|
-
//
|
|
144
|
+
// Math
|
|
148
145
|
PI,
|
|
149
146
|
abs,
|
|
150
147
|
floor,
|
|
@@ -172,8 +169,13 @@ export
|
|
|
172
169
|
isOverlapping,
|
|
173
170
|
isIntersecting,
|
|
174
171
|
wave,
|
|
172
|
+
|
|
173
|
+
// Utilities
|
|
175
174
|
formatTime,
|
|
176
175
|
fetchJSON,
|
|
176
|
+
saveText,
|
|
177
|
+
saveCanvas,
|
|
178
|
+
saveDataURL,
|
|
177
179
|
|
|
178
180
|
// Random
|
|
179
181
|
rand,
|
|
@@ -219,7 +221,6 @@ export
|
|
|
219
221
|
TextureInfo,
|
|
220
222
|
mainCanvas,
|
|
221
223
|
mainContext,
|
|
222
|
-
drawCanvas,
|
|
223
224
|
drawContext,
|
|
224
225
|
workCanvas,
|
|
225
226
|
workContext,
|
|
@@ -232,6 +233,7 @@ export
|
|
|
232
233
|
worldToScreen,
|
|
233
234
|
screenToWorldDelta,
|
|
234
235
|
worldToScreenDelta,
|
|
236
|
+
screenToWorldTransform,
|
|
235
237
|
drawTile,
|
|
236
238
|
drawRect,
|
|
237
239
|
drawRectGradient,
|
package/src/engineInput.js
CHANGED
|
@@ -365,8 +365,7 @@ function inputInit()
|
|
|
365
365
|
}
|
|
366
366
|
function onMouseDown(e)
|
|
367
367
|
{
|
|
368
|
-
if (isTouchDevice && touchInputEnable)
|
|
369
|
-
return;
|
|
368
|
+
if (isTouchDevice && touchInputEnable) return;
|
|
370
369
|
|
|
371
370
|
// fix stalled audio requiring user interaction
|
|
372
371
|
if (soundEnable && !headlessMode && audioContext && !audioIsRunning())
|
|
@@ -417,8 +416,7 @@ function inputInit()
|
|
|
417
416
|
let wasTouching;
|
|
418
417
|
function handleTouch(e)
|
|
419
418
|
{
|
|
420
|
-
if (!touchInputEnable)
|
|
421
|
-
return;
|
|
419
|
+
if (!touchInputEnable) return;
|
|
422
420
|
|
|
423
421
|
// route touch to gamepad
|
|
424
422
|
if (touchGamepadEnable)
|
|
@@ -482,8 +480,7 @@ function inputInit()
|
|
|
482
480
|
}
|
|
483
481
|
|
|
484
482
|
// don't process touch gamepad if paused
|
|
485
|
-
if (paused)
|
|
486
|
-
return;
|
|
483
|
+
if (paused) return;
|
|
487
484
|
|
|
488
485
|
// get center of left and right sides
|
|
489
486
|
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|