littlejsengine 1.9.8 → 1.9.11
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 +2 -0
- package/dist/littlejs.d.ts +38 -5
- package/dist/littlejs.esm.js +106 -58
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +98 -56
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +81 -54
- package/examples/box2d/game.js +34 -16
- package/examples/box2d/gameObjects.js +485 -0
- package/examples/box2d/index.html +6 -18
- package/examples/box2d/scenes.js +32 -251
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/build.js +1 -1
- package/examples/electron/index.html +2 -2
- package/examples/js13k/build.js +19 -1
- package/examples/js13k/index.html +13 -13
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/gameCharacter.js +1 -0
- package/examples/platformer/gameEffects.js +0 -2
- package/examples/platformer/gameObjects.js +1 -1
- package/examples/platformer/index.html +8 -8
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/build.js +1 -1
- package/examples/starter/game.js +1 -1
- 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/plugins/box2d.js +126 -47
- package/plugins/postProcess.js +3 -2
- package/src/engine.js +12 -11
- package/src/engineAudio.js +16 -16
- package/src/engineBuild.js +1 -1
- package/src/engineDebug.js +17 -2
- package/src/engineExport.js +7 -2
- package/src/engineInput.js +13 -6
- package/src/engineMedals.js +3 -2
- package/src/engineObject.js +25 -19
- package/src/engineSettings.js +12 -0
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ LittleJS is a small but powerful game engine with many features and no dependenc
|
|
|
56
56
|
|
|
57
57
|
- Robust arcade physics system with collision handling
|
|
58
58
|
- Very fast collision and raycasting for tile maps
|
|
59
|
+
- Full Box2d support using [super fast wasm build of box2d.js](https://github.com/kripken/box2d.js/)
|
|
59
60
|
|
|
60
61
|
### 🚀 Flexibility
|
|
61
62
|
|
|
@@ -209,6 +210,7 @@ Here are a few of the amazing games people made using LittleJS...
|
|
|
209
210
|
- [Data Warrior: 13kb limit](https://js13kgames.com/2024/games/data-warrior-13kb-limit) - Vampire Survivors-like game by [rndD](https://github.com/rndD)
|
|
210
211
|
- [The Way of the Dodo](https://js13kgames.com/2024/games/the-way-of-the-dodo) - Single button platformer by [repsej](https://github.com/repsej)
|
|
211
212
|
- [Wendol Village](https://js13kgames.com/2024/games/wendol-village) - Warcraft-like RTS game by [sanojian](https://github.com/sanojian)
|
|
213
|
+
- [Unblock](https://js13kgames.com/games/unblock) - Retro style space shooter by [Isaac Benitez](https://github.com/isacben)
|
|
212
214
|
|
|
213
215
|

|
|
214
216
|
|
package/dist/littlejs.d.ts
CHANGED
|
@@ -85,6 +85,11 @@ declare module "littlejsengine" {
|
|
|
85
85
|
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
86
86
|
* @memberof Engine */
|
|
87
87
|
export function engineObjectsCallback(pos?: Vector2, size?: number | Vector2, callbackFunction?: Function, objects?: any[]): void;
|
|
88
|
+
/** Add a new update function for a plugin
|
|
89
|
+
* @param {Function} [updateFunction]
|
|
90
|
+
* @param {Function} [renderFunction]
|
|
91
|
+
* @memberof Engine */
|
|
92
|
+
export function engineAddPlugin(updateFunction?: Function, renderFunction?: Function): void;
|
|
88
93
|
/**
|
|
89
94
|
* LittleJS Debug System
|
|
90
95
|
* - Press Esc to show debug overlay with mouse pick
|
|
@@ -470,6 +475,10 @@ declare module "littlejsengine" {
|
|
|
470
475
|
* @param {Number} scale
|
|
471
476
|
* @memberof Settings */
|
|
472
477
|
export function setParticleEmitRateScale(scale: number): void;
|
|
478
|
+
/** Set if touch input is allowed
|
|
479
|
+
* @param {Boolean} enable
|
|
480
|
+
* @memberof Settings */
|
|
481
|
+
export function setTouchInputEnable(enable: boolean): void;
|
|
473
482
|
/** Set if gamepads are enabled
|
|
474
483
|
* @param {Boolean} enable
|
|
475
484
|
* @memberof Settings */
|
|
@@ -1279,17 +1288,17 @@ declare module "littlejsengine" {
|
|
|
1279
1288
|
* @type {WebGL2RenderingContext}
|
|
1280
1289
|
* @memberof WebGL */
|
|
1281
1290
|
export let glContext: WebGL2RenderingContext;
|
|
1282
|
-
/** Set the WebGl texture, called automatically if using multiple textures
|
|
1283
|
-
* - This may also flush the gl buffer resulting in more draw calls and worse performance
|
|
1284
|
-
* @param {WebGLTexture} texture
|
|
1285
|
-
* @memberof WebGL */
|
|
1286
|
-
export function glSetTexture(texture: WebGLTexture): void;
|
|
1287
1291
|
/** Compile WebGL shader of the given type, will throw errors if in debug mode
|
|
1288
1292
|
* @param {String} source
|
|
1289
1293
|
* @param {Number} type
|
|
1290
1294
|
* @return {WebGLShader}
|
|
1291
1295
|
* @memberof WebGL */
|
|
1292
1296
|
export function glCompileShader(source: string, type: number): WebGLShader;
|
|
1297
|
+
/** Draw any sprites still in the buffer, copy to main canvas and clear
|
|
1298
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
|
|
1299
|
+
* @param {Boolean} [forceDraw]
|
|
1300
|
+
* @memberof WebGL */
|
|
1301
|
+
export function glCopyToContext(context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, forceDraw?: boolean): void;
|
|
1293
1302
|
/** Create WebGL program with given shaders
|
|
1294
1303
|
* @param {String} vsSource
|
|
1295
1304
|
* @param {String} fsSource
|
|
@@ -1301,11 +1310,34 @@ declare module "littlejsengine" {
|
|
|
1301
1310
|
* @return {WebGLTexture}
|
|
1302
1311
|
* @memberof WebGL */
|
|
1303
1312
|
export function glCreateTexture(image: HTMLImageElement): WebGLTexture;
|
|
1313
|
+
/** Add a sprite to the gl draw list, used by all gl draw functions
|
|
1314
|
+
* @param {Number} x
|
|
1315
|
+
* @param {Number} y
|
|
1316
|
+
* @param {Number} sizeX
|
|
1317
|
+
* @param {Number} sizeY
|
|
1318
|
+
* @param {Number} angle
|
|
1319
|
+
* @param {Number} uv0X
|
|
1320
|
+
* @param {Number} uv0Y
|
|
1321
|
+
* @param {Number} uv1X
|
|
1322
|
+
* @param {Number} uv1Y
|
|
1323
|
+
* @param {Number} rgba
|
|
1324
|
+
* @param {Number} [rgbaAdditive=0]
|
|
1325
|
+
* @memberof WebGL */
|
|
1326
|
+
export function glDraw(x: number, y: number, sizeX: number, sizeY: number, angle: number, uv0X: number, uv0Y: number, uv1X: number, uv1Y: number, rgba: number, rgbaAdditive?: number): void;
|
|
1327
|
+
/** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
|
|
1328
|
+
* @memberof WebGL */
|
|
1329
|
+
export function glFlush(): void;
|
|
1330
|
+
/** Set the WebGl texture, called automatically if using multiple textures
|
|
1331
|
+
* - This may also flush the gl buffer resulting in more draw calls and worse performance
|
|
1332
|
+
* @param {WebGLTexture} texture
|
|
1333
|
+
* @memberof WebGL */
|
|
1334
|
+
export function glSetTexture(texture: WebGLTexture): void;
|
|
1304
1335
|
/**
|
|
1305
1336
|
* LittleJS Input System
|
|
1306
1337
|
* - Tracks keyboard down, pressed, and released
|
|
1307
1338
|
* - Tracks mouse buttons, position, and wheel
|
|
1308
1339
|
* - Tracks multiple analog gamepads
|
|
1340
|
+
* - Touch input is handled as mouse input
|
|
1309
1341
|
* - Virtual gamepad for touch devices
|
|
1310
1342
|
* @namespace Input
|
|
1311
1343
|
*/
|
|
@@ -1335,6 +1367,7 @@ declare module "littlejsengine" {
|
|
|
1335
1367
|
* - Tracks keyboard down, pressed, and released
|
|
1336
1368
|
* - Tracks mouse buttons, position, and wheel
|
|
1337
1369
|
* - Tracks multiple analog gamepads
|
|
1370
|
+
* - Touch input is handled as mouse input
|
|
1338
1371
|
* - Virtual gamepad for touch devices
|
|
1339
1372
|
* @namespace Input
|
|
1340
1373
|
*/
|
package/dist/littlejs.esm.js
CHANGED
|
@@ -194,8 +194,23 @@ function debugSaveDataURL(dataURL, filename)
|
|
|
194
194
|
downloadLink.click();
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/** Show error as full page of red text
|
|
198
|
+
* @memberof Debug */
|
|
199
|
+
function debugShowErrors()
|
|
200
|
+
{
|
|
201
|
+
onunhandledrejection = (event)=>showError(event.reason);
|
|
202
|
+
onerror = (event, source, lineno, colno)=>
|
|
203
|
+
showError(`${event}\n${source}\nLn ${lineno}, Col ${colno}`);
|
|
204
|
+
|
|
205
|
+
const showError = (message)=>
|
|
206
|
+
{
|
|
207
|
+
document.body.style.backgroundColor = '#111';
|
|
208
|
+
document.body.innerHTML = `<pre style=color:#f00;font-size:50px>` + message;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
197
212
|
///////////////////////////////////////////////////////////////////////////////
|
|
198
|
-
// Engine debug
|
|
213
|
+
// Engine debug functions (called automatically)
|
|
199
214
|
|
|
200
215
|
function debugInit()
|
|
201
216
|
{
|
|
@@ -326,7 +341,7 @@ function debugRender()
|
|
|
326
341
|
const pos = worldToScreen(p.pos);
|
|
327
342
|
overlayContext.translate(pos.x|0, pos.y|0);
|
|
328
343
|
overlayContext.rotate(p.angle);
|
|
329
|
-
overlayContext.scale(1, -1);
|
|
344
|
+
overlayContext.scale(1, p.text ? 1 : -1);
|
|
330
345
|
overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
|
|
331
346
|
|
|
332
347
|
if (p.text != undefined)
|
|
@@ -1500,6 +1515,13 @@ let gamepadDirectionEmulateStick = true;
|
|
|
1500
1515
|
* @memberof Settings */
|
|
1501
1516
|
let inputWASDEmulateDirection = true;
|
|
1502
1517
|
|
|
1518
|
+
/** True if touch input is enabled for mobile devices
|
|
1519
|
+
* - Touch events will be routed to mouse events
|
|
1520
|
+
* @type {Boolean}
|
|
1521
|
+
* @default
|
|
1522
|
+
* @memberof Settings */
|
|
1523
|
+
let touchInputEnable = true;
|
|
1524
|
+
|
|
1503
1525
|
/** True if touch gamepad should appear on mobile devices
|
|
1504
1526
|
* - Supports left analog stick, 4 face buttons and start button (button 9)
|
|
1505
1527
|
* - Must be set by end of gameInit to be activated
|
|
@@ -1715,6 +1737,11 @@ function setGamepadDirectionEmulateStick(enable) { gamepadDirectionEmulateStick
|
|
|
1715
1737
|
* @memberof Settings */
|
|
1716
1738
|
function setInputWASDEmulateDirection(enable) { inputWASDEmulateDirection = enable; }
|
|
1717
1739
|
|
|
1740
|
+
/** Set if touch input is allowed
|
|
1741
|
+
* @param {Boolean} enable
|
|
1742
|
+
* @memberof Settings */
|
|
1743
|
+
function setTouchInputEnable(enable) { touchInputEnable = enable; }
|
|
1744
|
+
|
|
1718
1745
|
/** Set if touch gamepad should appear on mobile devices
|
|
1719
1746
|
* @param {Boolean} enable
|
|
1720
1747
|
* @memberof Settings */
|
|
@@ -1954,9 +1981,9 @@ class EngineObject
|
|
|
1954
1981
|
|
|
1955
1982
|
// apply physics
|
|
1956
1983
|
const oldPos = this.pos.copy();
|
|
1957
|
-
this.velocity.y += gravity * this.gravityScale;
|
|
1958
1984
|
this.pos.x += this.velocity.x *= this.damping;
|
|
1959
|
-
this.pos.y += this.velocity.y
|
|
1985
|
+
this.pos.y += this.velocity.y = this.damping * this.velocity.y
|
|
1986
|
+
+ gravity * this.gravityScale;
|
|
1960
1987
|
this.angle += this.angleVelocity *= this.angleDamping;
|
|
1961
1988
|
|
|
1962
1989
|
// physics sanity checks
|
|
@@ -2085,19 +2112,22 @@ class EngineObject
|
|
|
2085
2112
|
const isBlockedX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
|
|
2086
2113
|
if (isBlockedY || !isBlockedX)
|
|
2087
2114
|
{
|
|
2088
|
-
// set if landed on ground
|
|
2089
|
-
this.groundObject = wasMovingDown;
|
|
2090
|
-
|
|
2091
2115
|
// bounce velocity
|
|
2092
2116
|
this.velocity.y *= -this.elasticity;
|
|
2093
2117
|
|
|
2094
|
-
//
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2118
|
+
// set if landed on ground
|
|
2119
|
+
if (this.groundObject = wasMovingDown)
|
|
2120
|
+
{
|
|
2121
|
+
// adjust position to slightly above nearest tile boundary
|
|
2122
|
+
// this prevents gap between object and ground
|
|
2123
|
+
const epsilon = .0001;
|
|
2124
|
+
this.pos.y = (oldPos.y-this.size.y/2|0)+this.size.y/2+epsilon;
|
|
2125
|
+
}
|
|
2126
|
+
else
|
|
2127
|
+
{
|
|
2128
|
+
// move to previous position
|
|
2129
|
+
this.pos.y = oldPos.y;
|
|
2130
|
+
}
|
|
2101
2131
|
}
|
|
2102
2132
|
if (isBlockedX)
|
|
2103
2133
|
{
|
|
@@ -2235,13 +2265,16 @@ class EngineObject
|
|
|
2235
2265
|
/** Render debug info for this object */
|
|
2236
2266
|
renderDebugInfo()
|
|
2237
2267
|
{
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2268
|
+
if (debug)
|
|
2269
|
+
{
|
|
2270
|
+
// show object info for debugging
|
|
2271
|
+
const size = vec2(max(this.size.x, .2), max(this.size.y, .2));
|
|
2272
|
+
const color1 = rgb(this.collideTiles?1:0, this.collideSolidObjects?1:0, this.isSolid?1:0, this.parent?.2:.5);
|
|
2273
|
+
const color2 = this.parent ? rgb(1,1,1,.5) : rgb(0,0,0,.8);
|
|
2274
|
+
drawRect(this.pos, size, color1, this.angle, false);
|
|
2275
|
+
drawRect(this.pos, size.scale(.8), color2, this.angle, false);
|
|
2276
|
+
this.parent && drawLine(this.pos, this.parent.pos, .1, rgb(0,0,1,.5), false);
|
|
2277
|
+
}
|
|
2245
2278
|
}
|
|
2246
2279
|
}
|
|
2247
2280
|
/**
|
|
@@ -2748,6 +2781,7 @@ function toggleFullscreen()
|
|
|
2748
2781
|
* - Tracks keyboard down, pressed, and released
|
|
2749
2782
|
* - Tracks mouse buttons, position, and wheel
|
|
2750
2783
|
* - Tracks multiple analog gamepads
|
|
2784
|
+
* - Touch input is handled as mouse input
|
|
2751
2785
|
* - Virtual gamepad for touch devices
|
|
2752
2786
|
* @namespace Input
|
|
2753
2787
|
*/
|
|
@@ -2881,7 +2915,8 @@ function inputUpdate()
|
|
|
2881
2915
|
if (headlessMode) return;
|
|
2882
2916
|
|
|
2883
2917
|
// clear input when lost focus (prevent stuck keys)
|
|
2884
|
-
isTouchDevice
|
|
2918
|
+
if(!(touchInputEnable && isTouchDevice) && !document.hasFocus())
|
|
2919
|
+
clearInput();
|
|
2885
2920
|
|
|
2886
2921
|
// update mouse world space position
|
|
2887
2922
|
mousePos = screenToWorld(mousePosScreen);
|
|
@@ -2942,6 +2977,10 @@ function inputInit()
|
|
|
2942
2977
|
// mouse event handlers
|
|
2943
2978
|
onmousedown = (e)=>
|
|
2944
2979
|
{
|
|
2980
|
+
// fix stalled audio requiring user interaction
|
|
2981
|
+
if (soundEnable && !headlessMode && audioContext && audioContext.state != 'running')
|
|
2982
|
+
audioContext.resume();
|
|
2983
|
+
|
|
2945
2984
|
isUsingGamepad = false;
|
|
2946
2985
|
inputData[0][e.button] = 3;
|
|
2947
2986
|
mousePosScreen = mouseToScreen(e);
|
|
@@ -2953,7 +2992,7 @@ function inputInit()
|
|
|
2953
2992
|
oncontextmenu = (e)=> false; // prevent right click menu
|
|
2954
2993
|
|
|
2955
2994
|
// init touch input
|
|
2956
|
-
if (isTouchDevice)
|
|
2995
|
+
if (isTouchDevice && touchInputEnable)
|
|
2957
2996
|
touchInputInit();
|
|
2958
2997
|
}
|
|
2959
2998
|
|
|
@@ -3081,12 +3120,12 @@ function vibrateStop() { vibrate(0); }
|
|
|
3081
3120
|
|
|
3082
3121
|
/** True if a touch device has been detected
|
|
3083
3122
|
* @memberof Input */
|
|
3084
|
-
const isTouchDevice =
|
|
3123
|
+
const isTouchDevice = window.ontouchstart !== undefined;
|
|
3085
3124
|
|
|
3086
3125
|
// touch gamepad internal variables
|
|
3087
3126
|
let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
|
|
3088
3127
|
|
|
3089
|
-
//
|
|
3128
|
+
// enable touch input mouse passthrough
|
|
3090
3129
|
function touchInputInit()
|
|
3091
3130
|
{
|
|
3092
3131
|
// add non passive touch event listeners
|
|
@@ -3110,8 +3149,8 @@ function touchInputInit()
|
|
|
3110
3149
|
function handleTouchDefault(e)
|
|
3111
3150
|
{
|
|
3112
3151
|
// fix stalled audio requiring user interaction
|
|
3113
|
-
if (soundEnable && audioContext && audioContext.state != 'running')
|
|
3114
|
-
|
|
3152
|
+
if (soundEnable && !headlessMode && audioContext && audioContext.state != 'running')
|
|
3153
|
+
audioContext.resume();
|
|
3115
3154
|
|
|
3116
3155
|
// check if touching and pass to mouse events
|
|
3117
3156
|
const touching = e.touches.length;
|
|
@@ -3195,6 +3234,7 @@ function touchInputInit()
|
|
|
3195
3234
|
// render the touch gamepad, called automatically by the engine
|
|
3196
3235
|
function touchGamepadRender()
|
|
3197
3236
|
{
|
|
3237
|
+
if (!touchInputEnable || !isTouchDevice || headlessMode) return;
|
|
3198
3238
|
if (!touchGamepadEnable || !touchGamepadTimer.isSet())
|
|
3199
3239
|
return;
|
|
3200
3240
|
|
|
@@ -3323,6 +3363,7 @@ class Sound
|
|
|
3323
3363
|
// generate zzfx sound now for fast playback
|
|
3324
3364
|
const defaultRandomness = .05;
|
|
3325
3365
|
this.randomness = zzfxSound[1] || defaultRandomness;
|
|
3366
|
+
zzfxSound[1] = 0; // generate without randomness
|
|
3326
3367
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
3327
3368
|
this.sampleRate = zzfxR;
|
|
3328
3369
|
}
|
|
@@ -3555,10 +3596,6 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
3555
3596
|
|
|
3556
3597
|
///////////////////////////////////////////////////////////////////////////////
|
|
3557
3598
|
|
|
3558
|
-
// internal tracking if audio was suspended when last sound was played
|
|
3559
|
-
// allows first suspended sound to play when audio is resumed
|
|
3560
|
-
let audioSuspended = false;
|
|
3561
|
-
|
|
3562
3599
|
/** Play cached audio samples with given settings
|
|
3563
3600
|
* @param {Array} sampleChannels - Array of arrays of samples to play (for stereo playback)
|
|
3564
3601
|
* @param {Number} [volume] - How much to scale volume by
|
|
@@ -3574,20 +3611,21 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3574
3611
|
if (!soundEnable || headlessMode) return;
|
|
3575
3612
|
|
|
3576
3613
|
// prevent sounds from building up if they can't be played
|
|
3577
|
-
|
|
3578
|
-
if (audioSuspended = audioContext.state != 'running')
|
|
3614
|
+
if (audioContext.state != 'running')
|
|
3579
3615
|
{
|
|
3580
3616
|
// fix stalled audio
|
|
3581
|
-
audioContext.resume()
|
|
3617
|
+
audioContext.resume().then(()=>
|
|
3618
|
+
playSamples(sampleChannels, volume, rate, pan, loop, sampleRate, gainNode));
|
|
3582
3619
|
|
|
3583
3620
|
// prevent suspended sounds from building up
|
|
3584
|
-
|
|
3585
|
-
return;
|
|
3621
|
+
return;
|
|
3586
3622
|
}
|
|
3587
3623
|
|
|
3588
3624
|
// create buffer and source
|
|
3589
|
-
const
|
|
3590
|
-
|
|
3625
|
+
const channelCount = sampleChannels.length;
|
|
3626
|
+
const sampleLength = sampleChannels[0].length;
|
|
3627
|
+
const buffer = audioContext.createBuffer(channelCount, sampleLength, sampleRate);
|
|
3628
|
+
const source = audioContext.createBufferSource();
|
|
3591
3629
|
|
|
3592
3630
|
// copy samples to buffer and setup source
|
|
3593
3631
|
sampleChannels.forEach((c,i)=> buffer.getChannelData(i).set(c));
|
|
@@ -3601,7 +3639,8 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3601
3639
|
gainNode.connect(audioGainNode);
|
|
3602
3640
|
|
|
3603
3641
|
// connect source to stereo panner and gain
|
|
3604
|
-
|
|
3642
|
+
const pannerNode = new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)});
|
|
3643
|
+
source.connect(pannerNode).connect(gainNode);
|
|
3605
3644
|
|
|
3606
3645
|
// play and return sound
|
|
3607
3646
|
source.start();
|
|
@@ -3617,7 +3656,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3617
3656
|
* @param {Array} zzfxSound - Array of ZzFX parameters, ex. [.5,.5]
|
|
3618
3657
|
* @return {AudioBufferSourceNode} - The audio node of the sound played
|
|
3619
3658
|
* @memberof Audio */
|
|
3620
|
-
function zzfx(...zzfxSound) { return
|
|
3659
|
+
function zzfx(...zzfxSound) { return playSamples([zzfxG(...zzfxSound)]); }
|
|
3621
3660
|
|
|
3622
3661
|
/** Sample rate used for all ZzFX sounds
|
|
3623
3662
|
* @default 44100
|
|
@@ -3626,7 +3665,7 @@ const zzfxR = 44100;
|
|
|
3626
3665
|
|
|
3627
3666
|
/** Generate samples for a ZzFX sound
|
|
3628
3667
|
* @param {Number} [volume] - Volume scale (percent)
|
|
3629
|
-
* @param {Number} [randomness] -
|
|
3668
|
+
* @param {Number} [randomness] - How much to randomize frequency (percent Hz)
|
|
3630
3669
|
* @param {Number} [frequency] - Frequency of sound (Hz)
|
|
3631
3670
|
* @param {Number} [attack] - Attack time, how fast sound starts (seconds)
|
|
3632
3671
|
* @param {Number} [sustain] - Sustain time, how long sound holds (seconds)
|
|
@@ -3652,7 +3691,7 @@ const zzfxR = 44100;
|
|
|
3652
3691
|
function zzfxG
|
|
3653
3692
|
(
|
|
3654
3693
|
// parameters
|
|
3655
|
-
volume = 1, randomness =
|
|
3694
|
+
volume = 1, randomness = .05, frequency = 220, attack = 0, sustain = 0,
|
|
3656
3695
|
release = .1, shape = 0, shapeCurve = 1, slide = 0, deltaSlide = 0,
|
|
3657
3696
|
pitchJump = 0, pitchJumpTime = 0, repeatTime = 0, noise = 0, modulation = 0,
|
|
3658
3697
|
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0, filter = 0
|
|
@@ -3663,7 +3702,8 @@ function zzfxG
|
|
|
3663
3702
|
// init parameters
|
|
3664
3703
|
let PI2 = PI*2, sampleRate = zzfxR,
|
|
3665
3704
|
startSlide = slide *= 500 * PI2 / sampleRate / sampleRate,
|
|
3666
|
-
startFrequency = frequency *=
|
|
3705
|
+
startFrequency = frequency *=
|
|
3706
|
+
rand(1 + randomness, 1-randomness) * PI2 / sampleRate,
|
|
3667
3707
|
b = [], t = 0, tm = 0, i = 0, j = 1, r = 0, c = 0, s = 0, f, length,
|
|
3668
3708
|
|
|
3669
3709
|
// biquad LP/HP filter
|
|
@@ -4599,7 +4639,8 @@ function medalsInit(saveName)
|
|
|
4599
4639
|
medalsForEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
|
|
4600
4640
|
|
|
4601
4641
|
// engine automatically renders medals
|
|
4602
|
-
|
|
4642
|
+
engineAddPlugin(undefined, medalsRender);
|
|
4643
|
+
function medalsRender()
|
|
4603
4644
|
{
|
|
4604
4645
|
if (!medalsDisplayQueue.length)
|
|
4605
4646
|
return;
|
|
@@ -4623,7 +4664,7 @@ function medalsInit(saveName)
|
|
|
4623
4664
|
time > slideOffTime ? (time - slideOffTime) / medalDisplaySlideTime : 0;
|
|
4624
4665
|
medal.render(hidePercent);
|
|
4625
4666
|
}
|
|
4626
|
-
}
|
|
4667
|
+
}
|
|
4627
4668
|
}
|
|
4628
4669
|
|
|
4629
4670
|
/** Calls a function for each medal
|
|
@@ -5062,7 +5103,7 @@ const engineName = 'LittleJS';
|
|
|
5062
5103
|
* @type {String}
|
|
5063
5104
|
* @default
|
|
5064
5105
|
* @memberof Engine */
|
|
5065
|
-
const engineVersion = '1.9.
|
|
5106
|
+
const engineVersion = '1.9.11';
|
|
5066
5107
|
|
|
5067
5108
|
/** Frames per second to update
|
|
5068
5109
|
* @type {Number}
|
|
@@ -5121,14 +5162,14 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
5121
5162
|
const pluginUpdateList = [], pluginRenderList = [];
|
|
5122
5163
|
|
|
5123
5164
|
/** Add a new update function for a plugin
|
|
5124
|
-
* @param {Function} updateFunction
|
|
5165
|
+
* @param {Function} [updateFunction]
|
|
5166
|
+
* @param {Function} [renderFunction]
|
|
5125
5167
|
* @memberof Engine */
|
|
5126
|
-
function
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
function addPluginRender(renderFunction) { pluginRenderList.push(renderFunction); }
|
|
5168
|
+
function engineAddPlugin(updateFunction, renderFunction)
|
|
5169
|
+
{
|
|
5170
|
+
updateFunction && pluginUpdateList.push(updateFunction);
|
|
5171
|
+
renderFunction && pluginRenderList.push(renderFunction);
|
|
5172
|
+
}
|
|
5132
5173
|
|
|
5133
5174
|
///////////////////////////////////////////////////////////////////////////////
|
|
5134
5175
|
// Main engine functions
|
|
@@ -5301,10 +5342,11 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5301
5342
|
const styleBody =
|
|
5302
5343
|
'margin:0;overflow:hidden;' + // fill the window
|
|
5303
5344
|
'background:#000;' + // set background color
|
|
5304
|
-
'
|
|
5305
|
-
'user-select:none;' + // prevent mobile hold to select
|
|
5345
|
+
'user-select:none;' + // prevent hold to select
|
|
5306
5346
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
5307
|
-
'
|
|
5347
|
+
(!touchInputEnable ? '' : // no touch css setttings
|
|
5348
|
+
'touch-action:none;' + // prevent mobile pinch to resize
|
|
5349
|
+
'-webkit-touch-callout:none');// compatibility for ios
|
|
5308
5350
|
document.body.style.cssText = styleBody;
|
|
5309
5351
|
document.body.appendChild(mainCanvas = document.createElement('canvas'));
|
|
5310
5352
|
mainContext = mainCanvas.getContext('2d');
|
|
@@ -5645,6 +5687,7 @@ export {
|
|
|
5645
5687
|
engineObjectsUpdate,
|
|
5646
5688
|
engineObjectsDestroy,
|
|
5647
5689
|
engineObjectsCallback,
|
|
5690
|
+
engineAddPlugin,
|
|
5648
5691
|
|
|
5649
5692
|
// Globals
|
|
5650
5693
|
debug,
|
|
@@ -5726,6 +5769,7 @@ export {
|
|
|
5726
5769
|
setObjectMaxSpeed,
|
|
5727
5770
|
setGravity,
|
|
5728
5771
|
setParticleEmitRateScale,
|
|
5772
|
+
setTouchInputEnable,
|
|
5729
5773
|
setGamepadsEnable,
|
|
5730
5774
|
setGamepadDirectionEmulateStick,
|
|
5731
5775
|
setInputWASDEmulateDirection,
|
|
@@ -5811,10 +5855,13 @@ export {
|
|
|
5811
5855
|
// WebGL
|
|
5812
5856
|
glCanvas,
|
|
5813
5857
|
glContext,
|
|
5814
|
-
glSetTexture,
|
|
5815
5858
|
glCompileShader,
|
|
5859
|
+
glCopyToContext,
|
|
5816
5860
|
glCreateProgram,
|
|
5817
5861
|
glCreateTexture,
|
|
5862
|
+
glDraw,
|
|
5863
|
+
glFlush,
|
|
5864
|
+
glSetTexture,
|
|
5818
5865
|
|
|
5819
5866
|
// Input
|
|
5820
5867
|
keyIsDown,
|
|
@@ -5874,4 +5921,5 @@ export {
|
|
|
5874
5921
|
medalsPreventUnlock,
|
|
5875
5922
|
medalsInit,
|
|
5876
5923
|
Medal,
|
|
5877
|
-
};
|
|
5924
|
+
};
|
|
5925
|
+
|