littlejsengine 1.12.6 → 1.13.4
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/README.md +15 -12
- package/dist/littlejs.d.ts +466 -236
- package/dist/littlejs.esm.js +6126 -5370
- package/dist/littlejs.esm.min.js +4 -1
- package/dist/littlejs.js +6093 -5359
- package/dist/littlejs.min.js +4 -1
- package/dist/littlejs.release.js +5614 -4907
- package/examples/box2d/game.js +2 -2
- package/examples/box2d/gameObjects.js +8 -7
- package/examples/box2d/index.html +1 -1
- package/examples/box2d/scenes.js +8 -8
- package/examples/breakout/game.js +1 -1
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakout/index.html +1 -1
- package/examples/breakoutTutorial/README.md +46 -43
- package/examples/breakoutTutorial/game.js +3 -3
- package/examples/breakoutTutorial/index.html +1 -1
- package/examples/electron/build.bat +7 -0
- package/examples/electron/build.js +124 -0
- package/examples/electron/electron.js +35 -0
- package/examples/electron/game.js +140 -0
- package/examples/electron/index.html +13 -0
- package/examples/electron/package.json +12 -0
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/game.js +1 -0
- package/examples/empty/index.html +1 -1
- package/examples/htmlMenu/game.js +1 -1
- package/examples/htmlMenu/index.html +1 -1
- package/examples/index.html +486 -182
- package/examples/module/game.js +6 -3
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +12 -3
- package/examples/platformer/game.js +4 -4
- package/examples/platformer/gameCharacter.js +6 -6
- package/examples/platformer/gameEffects.js +74 -57
- package/examples/platformer/gameLevel.js +61 -70
- package/examples/platformer/gameObjects.js +4 -4
- package/examples/platformer/index.html +1 -1
- package/examples/puzzle/index.html +1 -1
- package/examples/shorts/base.html +23 -3
- package/examples/shorts/blending.js +9 -5
- package/examples/shorts/box2d.js +1 -1
- package/examples/shorts/box2dCar.js +9 -13
- package/examples/shorts/clock.js +1 -1
- package/examples/shorts/colors.js +2 -2
- package/examples/shorts/flappyGame.js +52 -0
- package/examples/shorts/helloWorld.js +6 -3
- package/examples/shorts/hillGlideGame.js +56 -0
- package/examples/shorts/landerGame.js +32 -0
- package/examples/shorts/maze.js +47 -0
- package/examples/shorts/medals.js +42 -0
- package/examples/shorts/nineSlice.js +21 -0
- package/examples/shorts/piano.js +52 -0
- package/examples/shorts/platformer.js +24 -20
- package/examples/shorts/{pong.js → pongGame.js} +1 -1
- package/examples/shorts/raycasting.js +71 -0
- package/examples/shorts/shapes.js +9 -9
- package/examples/shorts/slidingPuzzle.js +42 -0
- package/examples/shorts/spaceGame.js +56 -0
- package/examples/shorts/starfield.js +15 -0
- package/examples/shorts/systemFont.js +1 -1
- package/examples/shorts/tileLayer.js +3 -5
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +8 -7
- package/examples/shorts/topDown.js +18 -26
- package/examples/shorts/uiSystem.js +5 -7
- package/examples/starter/build.bat +6 -1
- package/examples/starter/build.js +9 -8
- package/examples/starter/game.js +7 -4
- package/examples/starter/index.html +23 -13
- package/examples/stress/index.html +7 -8
- package/examples/style.css +139 -0
- package/examples/typescript/build.js +2 -3
- package/examples/typescript/game.js +4 -4
- package/examples/typescript/game.ts +6 -3
- package/examples/typescript/index.html +1 -1
- package/examples/uiSystem/game.js +10 -25
- package/examples/uiSystem/index.html +1 -1
- package/package.json +2 -2
- package/plugins/box2d.js +22 -97
- package/plugins/drawUtilities.js +132 -0
- package/plugins/newgrounds.js +1 -1
- package/plugins/pluginExport.js +7 -1
- package/plugins/postProcess.js +9 -2
- package/plugins/uiSystem.js +155 -67
- package/plugins/zzfxm.js +1 -1
- package/reference.md +10 -10
- package/src/engine.js +56 -30
- package/src/engineAudio.js +15 -6
- package/src/engineBuild.bat +6 -1
- package/src/engineBuild.js +20 -5
- package/src/engineDebug.js +55 -28
- package/src/engineDraw.js +321 -177
- package/src/engineExport.js +27 -9
- package/src/engineInput.js +110 -38
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +71 -70
- package/src/engineParticles.js +33 -9
- package/src/engineSettings.js +69 -23
- package/src/engineTileLayer.js +312 -153
- package/src/engineUtilities.js +187 -135
- package/src/engineWebGL.js +70 -39
package/src/engineAudio.js
CHANGED
|
@@ -122,11 +122,20 @@ class Sound
|
|
|
122
122
|
this.gainNode.gain.value = volume;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
/** Stop the last instance of this sound that was played
|
|
126
|
-
|
|
125
|
+
/** Stop the last instance of this sound that was played
|
|
126
|
+
* @param {number} [fadeTime] - How long to fade out (seconds)
|
|
127
|
+
*/
|
|
128
|
+
stop(fadeTime=0)
|
|
127
129
|
{
|
|
128
|
-
if (this.source)
|
|
129
|
-
|
|
130
|
+
if (!this.source)
|
|
131
|
+
return;
|
|
132
|
+
|
|
133
|
+
// ramp off gain
|
|
134
|
+
const startFade = audioContext.currentTime;
|
|
135
|
+
const endFade = startFade + fadeTime;
|
|
136
|
+
this.gainNode.gain.linearRampToValueAtTime(1, startFade);
|
|
137
|
+
this.gainNode.gain.linearRampToValueAtTime(0, endFade);
|
|
138
|
+
this.source.stop(endFade);
|
|
130
139
|
this.source = undefined;
|
|
131
140
|
}
|
|
132
141
|
|
|
@@ -414,7 +423,7 @@ function zzfxG
|
|
|
414
423
|
repeatTime = repeatTime * sampleRate | 0;
|
|
415
424
|
|
|
416
425
|
// generate waveform
|
|
417
|
-
for(length = attack + decay + sustain + release + delay | 0;
|
|
426
|
+
for (length = attack + decay + sustain + release + delay | 0;
|
|
418
427
|
i < length; b[i++] = s * volume) // sample
|
|
419
428
|
{
|
|
420
429
|
if (!(++crush%(bitCrush*100|0))) // bit crush
|
|
@@ -469,4 +478,4 @@ function zzfxG
|
|
|
469
478
|
}
|
|
470
479
|
|
|
471
480
|
return b; // return sample buffer
|
|
472
|
-
}
|
|
481
|
+
}
|
package/src/engineBuild.bat
CHANGED
package/src/engineBuild.js
CHANGED
|
@@ -26,7 +26,6 @@ const engineSourceFiles =
|
|
|
26
26
|
`${SOURCE_FOLDER}/engineParticles.js`,
|
|
27
27
|
`${SOURCE_FOLDER}/engineMedals.js`,
|
|
28
28
|
`${SOURCE_FOLDER}/engineWebGL.js`,
|
|
29
|
-
`${SOURCE_FOLDER}/engine.js`,
|
|
30
29
|
];
|
|
31
30
|
const enginePluginFiles =
|
|
32
31
|
[
|
|
@@ -35,6 +34,7 @@ const enginePluginFiles =
|
|
|
35
34
|
`${PLUGIN_FOLDER}/zzfxm.js`,
|
|
36
35
|
`${PLUGIN_FOLDER}/uiSystem.js`,
|
|
37
36
|
`${PLUGIN_FOLDER}/box2d.js`,
|
|
37
|
+
`${PLUGIN_FOLDER}/drawUtilities.js`,
|
|
38
38
|
];
|
|
39
39
|
const engineExtraFiles =
|
|
40
40
|
[
|
|
@@ -49,7 +49,7 @@ const asciiArt =`
|
|
|
49
49
|
OOO OOO OO OO OO=OO-oo\\
|
|
50
50
|
`;
|
|
51
51
|
const license = '// LittleJS Engine - MIT License - Copyright 2021 Frank Force\n'+
|
|
52
|
-
'// https://github.com/KilledByAPixel/LittleJS\n';
|
|
52
|
+
'// https://github.com/KilledByAPixel/LittleJS\n\n';
|
|
53
53
|
|
|
54
54
|
console.log(asciiArt);
|
|
55
55
|
console.log('Choo Choo... Building LittleJS Engine!\n');
|
|
@@ -75,6 +75,7 @@ Build
|
|
|
75
75
|
'Build Engine -- all',
|
|
76
76
|
`${BUILD_FOLDER}/${ENGINE_NAME}.js`,
|
|
77
77
|
[
|
|
78
|
+
`${SOURCE_FOLDER}/engine.js`,
|
|
78
79
|
`${SOURCE_FOLDER}/engineDebug.js`,
|
|
79
80
|
...engineSourceFiles,
|
|
80
81
|
...enginePluginFiles
|
|
@@ -87,6 +88,7 @@ Build
|
|
|
87
88
|
'Build Engine -- release',
|
|
88
89
|
`${BUILD_FOLDER}/${ENGINE_NAME}.release.js`,
|
|
89
90
|
[
|
|
91
|
+
`${SOURCE_FOLDER}/engine.js`,
|
|
90
92
|
`${SOURCE_FOLDER}/engineRelease.js`,
|
|
91
93
|
...engineSourceFiles,
|
|
92
94
|
...enginePluginFiles
|
|
@@ -99,7 +101,7 @@ Build
|
|
|
99
101
|
'Build Engine -- minified',
|
|
100
102
|
`${BUILD_FOLDER}/${ENGINE_NAME}.min.js`,
|
|
101
103
|
[`${BUILD_FOLDER}/${ENGINE_NAME}.release.js`],
|
|
102
|
-
[closureCompilerStep, uglifyBuildStep]
|
|
104
|
+
[closureCompilerStep, uglifyBuildStep, addLicenseStep]
|
|
103
105
|
);
|
|
104
106
|
|
|
105
107
|
Build
|
|
@@ -123,7 +125,7 @@ Build
|
|
|
123
125
|
`${SOURCE_FOLDER}/engineExport.js`,
|
|
124
126
|
`${PLUGIN_FOLDER}/pluginExport.js`
|
|
125
127
|
],
|
|
126
|
-
[uglifyBuildStep]
|
|
128
|
+
[uglifyBuildStep, addLicenseStep]
|
|
127
129
|
);
|
|
128
130
|
|
|
129
131
|
console.log(`Engine built in ${((Date.now() - startTime)/1e3).toFixed(2)} seconds!`);
|
|
@@ -141,7 +143,7 @@ function Build(message, outputFile, files=[], buildSteps=[], isPrimaryBuild)
|
|
|
141
143
|
if (isPrimaryBuild)
|
|
142
144
|
{
|
|
143
145
|
// add license and strict mode to top
|
|
144
|
-
buffer += license
|
|
146
|
+
buffer += license;
|
|
145
147
|
buffer += "'use strict';\n\n";
|
|
146
148
|
}
|
|
147
149
|
|
|
@@ -189,6 +191,19 @@ function uglifyBuildStep(filename)
|
|
|
189
191
|
catch (e) { handleError(e,'Failed to run Uglify minification step!'); }
|
|
190
192
|
};
|
|
191
193
|
|
|
194
|
+
// Add license to top of file
|
|
195
|
+
function addLicenseStep(filename)
|
|
196
|
+
{
|
|
197
|
+
try
|
|
198
|
+
{
|
|
199
|
+
// add license to top of minified file
|
|
200
|
+
let fileContent = fs.readFileSync(filename, 'utf8');
|
|
201
|
+
fileContent = license + fileContent;
|
|
202
|
+
fs.writeFileSync(filename, fileContent);
|
|
203
|
+
}
|
|
204
|
+
catch (e) { handleError(e, 'Failed to add license to minified file!'); }
|
|
205
|
+
};
|
|
206
|
+
|
|
192
207
|
// Build TypeScript definitions
|
|
193
208
|
function typeScriptBuildStep(filename)
|
|
194
209
|
{
|
package/src/engineDebug.js
CHANGED
|
@@ -47,19 +47,19 @@ let debugKey = 'Escape';
|
|
|
47
47
|
let debugOverlay = false;
|
|
48
48
|
|
|
49
49
|
// Engine internal variables not exposed to documentation
|
|
50
|
-
let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParticles = false, debugGamepads = false, debugMedals = false, debugTakeScreenshot, downloadLink;
|
|
50
|
+
let debugPrimitives = [], debugPhysics = false, debugRaycast = false, debugParticles = false, debugGamepads = false, debugMedals = false, debugTakeScreenshot, downloadLink, debugCanvas;
|
|
51
51
|
|
|
52
52
|
///////////////////////////////////////////////////////////////////////////////
|
|
53
53
|
// Debug helper functions
|
|
54
54
|
|
|
55
55
|
/** Asserts if the expression is false, does not do anything in release builds
|
|
56
|
-
* @param {boolean} assert
|
|
57
|
-
* @param {Object} [output]
|
|
56
|
+
* @param {boolean} assert
|
|
57
|
+
* @param {...Object} [output] - error message output
|
|
58
58
|
* @memberof Debug */
|
|
59
|
-
function ASSERT(assert, output)
|
|
59
|
+
function ASSERT(assert, ...output)
|
|
60
60
|
{
|
|
61
61
|
if (enableAsserts)
|
|
62
|
-
|
|
62
|
+
console.assert(assert, ...output);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/** Draw a debug rectangle in world space
|
|
@@ -132,16 +132,22 @@ function debugLine(posA, posB, color, thickness=.1, time)
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/** Draw a debug combined axis aligned bounding box in world space
|
|
135
|
-
* @param {Vector2}
|
|
136
|
-
* @param {Vector2}
|
|
137
|
-
* @param {Vector2}
|
|
138
|
-
* @param {Vector2}
|
|
135
|
+
* @param {Vector2} posA
|
|
136
|
+
* @param {Vector2} sizeA
|
|
137
|
+
* @param {Vector2} posB
|
|
138
|
+
* @param {Vector2} sizeB
|
|
139
139
|
* @param {string} [color]
|
|
140
140
|
* @memberof Debug */
|
|
141
|
-
function debugOverlap(
|
|
141
|
+
function debugOverlap(posA, sizeA, posB, sizeB, color)
|
|
142
142
|
{
|
|
143
|
-
const minPos = vec2(
|
|
144
|
-
|
|
143
|
+
const minPos = vec2(
|
|
144
|
+
min(posA.x - sizeA.x/2, posB.x - sizeB.x/2),
|
|
145
|
+
min(posA.y - sizeA.y/2, posB.y - sizeB.y/2)
|
|
146
|
+
);
|
|
147
|
+
const maxPos = vec2(
|
|
148
|
+
max(posA.x + sizeA.x/2, posB.x + sizeB.x/2),
|
|
149
|
+
max(posA.y + sizeA.y/2, posB.y + sizeB.y/2)
|
|
150
|
+
);
|
|
145
151
|
debugRect(minPos.lerp(maxPos,.5), maxPos.subtract(minPos), color);
|
|
146
152
|
}
|
|
147
153
|
|
|
@@ -169,12 +175,25 @@ function debugClear() { debugPrimitives = []; }
|
|
|
169
175
|
function debugScreenshot() { debugTakeScreenshot = 1; }
|
|
170
176
|
|
|
171
177
|
/** Save a canvas to disk
|
|
172
|
-
* @param {HTMLCanvasElement} canvas
|
|
173
|
-
* @param {string}
|
|
174
|
-
* @param {string}
|
|
178
|
+
* @param {HTMLCanvasElement|OffscreenCanvas} canvas
|
|
179
|
+
* @param {string} [filename]
|
|
180
|
+
* @param {string} [type]
|
|
175
181
|
* @memberof Debug */
|
|
176
182
|
function debugSaveCanvas(canvas, filename='screenshot', type='image/png')
|
|
177
|
-
{
|
|
183
|
+
{
|
|
184
|
+
if (canvas instanceof OffscreenCanvas)
|
|
185
|
+
{
|
|
186
|
+
// copy to temporary canvas and save
|
|
187
|
+
if (!debugCanvas)
|
|
188
|
+
debugCanvas = document.createElement('canvas');
|
|
189
|
+
debugCanvas.width = canvas.width;
|
|
190
|
+
debugCanvas.height = canvas.height;
|
|
191
|
+
debugCanvas.getContext('2d').drawImage(canvas, 0, 0);
|
|
192
|
+
debugSaveDataURL(debugCanvas.toDataURL(type), filename);
|
|
193
|
+
}
|
|
194
|
+
else
|
|
195
|
+
debugSaveDataURL(canvas.toDataURL(type), filename);
|
|
196
|
+
}
|
|
178
197
|
|
|
179
198
|
/** Save a text file to disk
|
|
180
199
|
* @param {string} text
|
|
@@ -252,7 +271,8 @@ function debugRender()
|
|
|
252
271
|
if (debugVideoCaptureIsActive())
|
|
253
272
|
return; // don't show debug info when capturing video
|
|
254
273
|
|
|
255
|
-
|
|
274
|
+
// flush any gl sprites before drawing debug info
|
|
275
|
+
glFlush();
|
|
256
276
|
|
|
257
277
|
if (debugTakeScreenshot)
|
|
258
278
|
{
|
|
@@ -329,8 +349,11 @@ function debugRender()
|
|
|
329
349
|
}
|
|
330
350
|
}
|
|
331
351
|
|
|
332
|
-
if (
|
|
333
|
-
|
|
352
|
+
if (tileCollisionTest(mousePos))
|
|
353
|
+
{
|
|
354
|
+
// show floored tile pick for tile collision
|
|
355
|
+
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5));
|
|
356
|
+
}
|
|
334
357
|
mainContext = saveContext;
|
|
335
358
|
}
|
|
336
359
|
|
|
@@ -405,10 +428,10 @@ function debugRender()
|
|
|
405
428
|
mainContext = overlayContext;
|
|
406
429
|
const raycastHitPos = tileCollisionRaycast(debugObject.pos, mousePos);
|
|
407
430
|
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3));
|
|
408
|
-
drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5)
|
|
431
|
+
drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5));
|
|
409
432
|
|
|
410
433
|
const debugText = 'mouse pos = ' + mousePos +
|
|
411
|
-
'\nmouse collision = ' +
|
|
434
|
+
'\nmouse collision = ' + tileCollisionGetData(mousePos) +
|
|
412
435
|
'\n\n--- object info ---\n' +
|
|
413
436
|
debugObject.toString();
|
|
414
437
|
drawTextScreen(debugText, mousePosScreen, 24, rgb(), .05, undefined, 'center', 'monospace');
|
|
@@ -417,20 +440,24 @@ function debugRender()
|
|
|
417
440
|
|
|
418
441
|
{
|
|
419
442
|
// draw debug overlay
|
|
443
|
+
const fontSize = 20;
|
|
444
|
+
const lineHeight = fontSize * 1.2 | 0;
|
|
420
445
|
overlayContext.save();
|
|
421
446
|
overlayContext.fillStyle = '#fff';
|
|
422
447
|
overlayContext.textAlign = 'left';
|
|
423
448
|
overlayContext.textBaseline = 'top';
|
|
424
|
-
overlayContext.font = '
|
|
449
|
+
overlayContext.font = fontSize + 'px monospace';
|
|
425
450
|
overlayContext.shadowColor = '#000';
|
|
426
451
|
overlayContext.shadowBlur = 9;
|
|
427
452
|
|
|
428
|
-
let x = 9, y =
|
|
453
|
+
let x = 9, y = 0, h = lineHeight;
|
|
429
454
|
if (debugOverlay)
|
|
430
455
|
{
|
|
431
|
-
overlayContext.fillText(engineName, x, y += h);
|
|
432
|
-
overlayContext.fillText('Objects: ' + engineObjects.length, x, y += h);
|
|
456
|
+
overlayContext.fillText(engineName, x, y += h/2 );
|
|
433
457
|
overlayContext.fillText('Time: ' + formatTime(time), x, y += h);
|
|
458
|
+
overlayContext.fillText('FPS: ' + averageFPS.toFixed(1), x, y += h);
|
|
459
|
+
overlayContext.fillText('Objects: ' + engineObjects.length, x, y += h);
|
|
460
|
+
overlayContext.fillText('Draw Count: ' + drawCount, x, y += h);
|
|
434
461
|
overlayContext.fillText('---------', x, y += h);
|
|
435
462
|
overlayContext.fillStyle = '#f00';
|
|
436
463
|
overlayContext.fillText('ESC: Debug Overlay', x, y += h);
|
|
@@ -444,10 +471,10 @@ function debugRender()
|
|
|
444
471
|
overlayContext.fillText('4: Debug Raycasts', x, y += h);
|
|
445
472
|
overlayContext.fillStyle = '#fff';
|
|
446
473
|
overlayContext.fillText('5: Save Screenshot', x, y += h);
|
|
447
|
-
overlayContext.fillText('6:
|
|
474
|
+
overlayContext.fillText('6: Toggle Video Capture', x, y += h);
|
|
448
475
|
|
|
449
476
|
let keysPressed = '';
|
|
450
|
-
for(const i in inputData[0])
|
|
477
|
+
for (const i in inputData[0])
|
|
451
478
|
{
|
|
452
479
|
if (keyIsDown(i, 0))
|
|
453
480
|
keysPressed += i + ' ' ;
|
|
@@ -456,7 +483,7 @@ function debugRender()
|
|
|
456
483
|
|
|
457
484
|
let buttonsPressed = '';
|
|
458
485
|
if (inputData[1])
|
|
459
|
-
for(const i in inputData[1])
|
|
486
|
+
for (const i in inputData[1])
|
|
460
487
|
{
|
|
461
488
|
if (keyIsDown(i, 1))
|
|
462
489
|
buttonsPressed += i + ' ' ;
|