littlejsengine 1.16.1 → 1.17.1
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 +287 -240
- package/dist/littlejs.esm.js +1419 -1259
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1076 -910
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +977 -815
- package/examples/box2d/gameObjects.js +6 -6
- package/examples/breakout/game.js +5 -6
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +1 -1
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/tiles.png +0 -0
- package/examples/platformer/gameEffects.js +24 -23
- package/examples/platformer/gameLevel.js +24 -25
- package/examples/shorts/base.html +2 -1
- package/examples/shorts/clock.js +3 -3
- package/examples/shorts/fontImage.js +4 -3
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +1 -1
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/texture.js +10 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +2 -0
- package/examples/starter/index.html +3 -2
- package/examples/starter/tiles.png +0 -0
- package/examples/typescript/tiles.png +0 -0
- package/examples/uiSystem/game.js +1 -1
- package/examples/uiSystem/tiles.png +0 -0
- package/package.json +1 -1
- package/plugins/postProcess.js +47 -28
- package/plugins/uiSystem.js +16 -16
- package/reference.md +6 -6
- package/src/engine.js +186 -198
- package/src/engineAudio.js +6 -10
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +100 -98
- package/src/engineDraw.js +185 -148
- package/src/engineExport.js +327 -333
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +17 -26
- package/src/engineMath.js +1112 -0
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +27 -27
- package/src/engineParticles.js +2 -2
- package/src/engineRelease.js +1 -3
- package/src/engineSettings.js +2 -2
- package/src/engineTileLayer.js +200 -176
- package/src/engineUtilities.js +48 -1097
- package/src/engineWebGL.js +127 -79
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
|
|
@@ -65,7 +65,7 @@ function LOG(...output) { console.log(...output); }
|
|
|
65
65
|
|
|
66
66
|
/** Draw a debug rectangle in world space
|
|
67
67
|
* @param {Vector2} pos
|
|
68
|
-
* @param {Vector2} [size=
|
|
68
|
+
* @param {Vector2} [size=vec2(0)]
|
|
69
69
|
* @param {Color|string} [color]
|
|
70
70
|
* @param {number} [time]
|
|
71
71
|
* @param {number} [angle]
|
|
@@ -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
|
|
|
@@ -433,7 +389,7 @@ function debugRender()
|
|
|
433
389
|
if (tileCollisionTest(mousePos))
|
|
434
390
|
{
|
|
435
391
|
// show floored tile pick for tile collision
|
|
436
|
-
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5));
|
|
392
|
+
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5), 0, false);
|
|
437
393
|
}
|
|
438
394
|
}
|
|
439
395
|
|
|
@@ -512,8 +468,8 @@ function debugRender()
|
|
|
512
468
|
if (debugObject)
|
|
513
469
|
{
|
|
514
470
|
const raycastHitPos = tileCollisionRaycast(debugObject.pos, mousePos);
|
|
515
|
-
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3));
|
|
516
|
-
drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5));
|
|
471
|
+
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3), 0, false);
|
|
472
|
+
drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5), undefined, undefined, false);
|
|
517
473
|
|
|
518
474
|
let debugText = 'mouse pos = ' + mousePos;
|
|
519
475
|
if (tileCollisionLayers.length)
|
|
@@ -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
|
///////////////////////////////////////////////////////////////////////////////
|