littlejsengine 1.11.13 → 1.12.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/dist/littlejs.d.ts +1418 -109
- package/dist/littlejs.esm.js +3495 -581
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +3258 -399
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +3147 -379
- package/examples/box2d/game.js +73 -45
- package/examples/box2d/gameObjects.js +96 -92
- package/examples/box2d/index.html +2 -7
- package/examples/box2d/scenes.js +82 -92
- package/examples/breakout/game.js +62 -30
- package/examples/breakout/gameObjects.js +45 -47
- package/examples/breakout/index.html +1 -5
- package/examples/breakoutTutorial/game.js +36 -29
- package/examples/breakoutTutorial/index.html +1 -3
- package/examples/empty/game.js +5 -2
- package/examples/empty/index.html +1 -3
- package/examples/htmlMenu/game.js +25 -19
- package/examples/htmlMenu/index.html +5 -7
- package/examples/index.html +2 -3
- package/examples/module/game.js +32 -34
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +27 -22
- package/examples/platformer/game.js +71 -48
- package/examples/platformer/gameCharacter.js +42 -34
- package/examples/platformer/gameEffects.js +82 -75
- package/examples/platformer/gameLevel.js +67 -38
- package/examples/platformer/{gameLevelData.js → gameLevelData.json} +1 -11
- package/examples/platformer/gameObjects.js +70 -64
- package/examples/platformer/gamePlayer.js +12 -7
- package/examples/platformer/index.html +1 -9
- package/examples/puzzle/game.js +58 -42
- package/examples/puzzle/index.html +1 -3
- package/examples/shorts/base.html +2 -2
- package/examples/shorts/particles.js +1 -1
- package/examples/shorts/platformer.js +1 -1
- package/examples/shorts/tileLayer.js +5 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/starter/build.js +4 -4
- package/examples/starter/game.js +9 -12
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +44 -43
- package/examples/typescript/build.js +17 -18
- package/examples/typescript/game.js +32 -34
- package/examples/typescript/game.ts +32 -34
- package/examples/typescript/index.html +1 -1
- package/examples/uiSystem/game.js +33 -36
- package/examples/uiSystem/index.html +1 -5
- package/package.json +3 -3
- package/plugins/box2d.js +1556 -640
- package/plugins/{Box2D_v2.3.1_min.wasm.js → box2d.wasm.js} +1 -1
- package/plugins/newgrounds.js +7 -8
- package/plugins/pluginExport.js +50 -0
- package/plugins/postProcess.js +94 -93
- package/plugins/uiSystem.js +145 -161
- package/plugins/zzfxm.js +163 -0
- package/reference.md +29 -27
- package/src/engine.js +15 -20
- package/src/engineAudio.js +74 -204
- package/src/engineBuild.js +29 -4
- package/src/engineDebug.js +105 -9
- package/src/engineDraw.js +27 -14
- package/src/engineExport.js +12 -8
- package/src/engineInput.js +3 -1
- package/src/engineObject.js +18 -14
- package/src/engineParticles.js +6 -1
- package/src/engineRelease.js +6 -1
- package/src/engineSettings.js +8 -8
- package/src/engineTileLayer.js +179 -96
- package/src/engineUtilities.js +5 -11
- package/src/engineWebGL.js +19 -7
- package/examples/starter/build/index.html +0 -2
- package/examples/starter/build/index.js +0 -1
- package/examples/starter/build/tiles.png +0 -0
- package/examples/starter/game.zip +0 -0
- package/examples/typescript/build/dist/littlejs.esm.js +0 -4834
- package/examples/typescript/build/examples/typescript/build.js +0 -24
- package/examples/typescript/build/examples/typescript/game.js +0 -102
- /package/plugins/{Box2D_v2.3.1_min.wasm.wasm → box2d.wasm.wasm} +0 -0
package/src/engineDebug.js
CHANGED
|
@@ -72,8 +72,10 @@ function ASSERT(assert, output)
|
|
|
72
72
|
* @memberof Debug */
|
|
73
73
|
function debugRect(pos, size=vec2(), color='#fff', time=0, angle=0, fill=false)
|
|
74
74
|
{
|
|
75
|
+
if (typeof size == 'number')
|
|
76
|
+
size = vec2(size); // allow passing in floats
|
|
75
77
|
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
76
|
-
debugPrimitives.push({pos, size
|
|
78
|
+
debugPrimitives.push({pos, size, color, time:new Timer(time), angle, fill});
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
/** Draw a debug poly in world space
|
|
@@ -197,17 +199,17 @@ function debugSaveDataURL(dataURL, filename)
|
|
|
197
199
|
* @memberof Debug */
|
|
198
200
|
function debugShowErrors()
|
|
199
201
|
{
|
|
200
|
-
onunhandledrejection = (event)=>showError(event.reason);
|
|
201
|
-
onerror = (event, source, lineno, colno)=>
|
|
202
|
-
showError(`${event}\n${source}\nLn ${lineno}, Col ${colno}`);
|
|
203
|
-
|
|
204
202
|
const showError = (message)=>
|
|
205
203
|
{
|
|
206
204
|
// replace entire page with error message
|
|
207
205
|
document.body.style.display = '';
|
|
208
206
|
document.body.style.backgroundColor = '#111';
|
|
209
|
-
document.body.innerHTML = `<pre style=color:#f00;font-size:50px>` + message;
|
|
207
|
+
document.body.innerHTML = `<pre style=color:#f00;font-size:50px;white-space:pre-wrap>` + message;
|
|
210
208
|
}
|
|
209
|
+
onunhandledrejection = (event)=>
|
|
210
|
+
showError(event.reason.stack || event.reason);
|
|
211
|
+
onerror = (message, source, lineno, colno)=>
|
|
212
|
+
showError(`${message}\n${source}\nLn ${lineno}, Col ${colno}`);
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -240,11 +242,16 @@ function debugUpdate()
|
|
|
240
242
|
debugRaycast = !debugRaycast;
|
|
241
243
|
if (keyWasPressed('Digit5'))
|
|
242
244
|
debugScreenshot();
|
|
245
|
+
if (keyWasPressed('Digit6'))
|
|
246
|
+
debugVideoCaptureIsActive() ? debugVideoCaptureStop() : debugVideoCaptureStart();
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
246
250
|
function debugRender()
|
|
247
251
|
{
|
|
252
|
+
if (debugVideoCaptureIsActive())
|
|
253
|
+
return; // don't show debug info when capturing video
|
|
254
|
+
|
|
248
255
|
glCopyToContext(mainContext);
|
|
249
256
|
|
|
250
257
|
if (debugTakeScreenshot)
|
|
@@ -322,11 +329,9 @@ function debugRender()
|
|
|
322
329
|
}
|
|
323
330
|
}
|
|
324
331
|
|
|
325
|
-
if (
|
|
332
|
+
if (tileCollisionLayers.length) // show floored tile pick if there is tile collision
|
|
326
333
|
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(0,0,1,.5), 0, false);
|
|
327
334
|
mainContext = saveContext;
|
|
328
|
-
|
|
329
|
-
//glCopyToContext(mainContext = saveContext);
|
|
330
335
|
}
|
|
331
336
|
|
|
332
337
|
{
|
|
@@ -439,6 +444,7 @@ function debugRender()
|
|
|
439
444
|
overlayContext.fillText('4: Debug Raycasts', x, y += h);
|
|
440
445
|
overlayContext.fillStyle = '#fff';
|
|
441
446
|
overlayContext.fillText('5: Save Screenshot', x, y += h);
|
|
447
|
+
overlayContext.fillText('6: Capture Video', x, y += h);
|
|
442
448
|
|
|
443
449
|
let keysPressed = '';
|
|
444
450
|
for(const i in inputData[0])
|
|
@@ -467,4 +473,94 @@ function debugRender()
|
|
|
467
473
|
|
|
468
474
|
overlayContext.restore();
|
|
469
475
|
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
479
|
+
// video capture - records video and audio at 60 fps using MediaRecorder API
|
|
480
|
+
|
|
481
|
+
// internal variables used to capture video
|
|
482
|
+
let debugVideoCapture, debugVideoCaptureTrack, debugVideoCaptureIcon, debugVideoCaptureTimer;
|
|
483
|
+
|
|
484
|
+
/** Check if video capture is active
|
|
485
|
+
* @memberof Debug */
|
|
486
|
+
function debugVideoCaptureIsActive() { return !!debugVideoCapture; }
|
|
487
|
+
|
|
488
|
+
/** Start capturing video
|
|
489
|
+
* @memberof Debug */
|
|
490
|
+
function debugVideoCaptureStart()
|
|
491
|
+
{
|
|
492
|
+
if (debugVideoCaptureIsActive())
|
|
493
|
+
return; // already recording
|
|
494
|
+
|
|
495
|
+
// captureStream passing in 0 to only capture when requestFrame() is called
|
|
496
|
+
const stream = mainCanvas.captureStream(0);
|
|
497
|
+
const chunks = [];
|
|
498
|
+
debugVideoCaptureTrack = stream.getVideoTracks()[0];
|
|
499
|
+
if (debugVideoCaptureTrack.applyConstraints)
|
|
500
|
+
debugVideoCaptureTrack.applyConstraints({frameRate:frameRate}); // force 60 fps
|
|
501
|
+
debugVideoCapture = new MediaRecorder(stream, {mimeType:'video/webm;codecs=vp8'});
|
|
502
|
+
debugVideoCapture.ondataavailable = (e)=> chunks.push(e.data);
|
|
503
|
+
debugVideoCapture.onstop = ()=>
|
|
504
|
+
{
|
|
505
|
+
const blob = new Blob(chunks, {type: 'video/webm'});
|
|
506
|
+
const url = URL.createObjectURL(blob);
|
|
507
|
+
downloadLink.download = 'capture.webm';
|
|
508
|
+
downloadLink.href = url;
|
|
509
|
+
downloadLink.click();
|
|
510
|
+
URL.revokeObjectURL(url);
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
if (audioMasterGain)
|
|
514
|
+
{
|
|
515
|
+
// connect to audio master gain node
|
|
516
|
+
const audioStreamDestination = audioContext.createMediaStreamDestination();
|
|
517
|
+
audioMasterGain.connect(audioStreamDestination);
|
|
518
|
+
for (const track of audioStreamDestination.stream.getAudioTracks())
|
|
519
|
+
stream.addTrack(track); // add audio tracks to capture stream
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// start recording
|
|
523
|
+
console.log('Video capture started.');
|
|
524
|
+
debugVideoCapture.start();
|
|
525
|
+
debugVideoCaptureTimer = new Timer(0);
|
|
526
|
+
|
|
527
|
+
if (!debugVideoCaptureIcon)
|
|
528
|
+
{
|
|
529
|
+
// create recording icon to show it is capturing video
|
|
530
|
+
debugVideoCaptureIcon = document.createElement('div');
|
|
531
|
+
debugVideoCaptureIcon.style.position = 'absolute';
|
|
532
|
+
debugVideoCaptureIcon.style.padding = '9px';
|
|
533
|
+
debugVideoCaptureIcon.style.color = '#f00';
|
|
534
|
+
debugVideoCaptureIcon.style.font = '50px monospace';
|
|
535
|
+
document.body.appendChild(debugVideoCaptureIcon);
|
|
536
|
+
}
|
|
537
|
+
// show recording icon
|
|
538
|
+
debugVideoCaptureIcon.textContent = '';
|
|
539
|
+
debugVideoCaptureIcon.style.display = '';
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/** Stop capturing video and save to disk
|
|
543
|
+
* @memberof Debug */
|
|
544
|
+
function debugVideoCaptureStop()
|
|
545
|
+
{
|
|
546
|
+
if (!debugVideoCaptureIsActive())
|
|
547
|
+
return; // not recording
|
|
548
|
+
|
|
549
|
+
// stop recording
|
|
550
|
+
console.log(`Video capture ended. ${debugVideoCaptureTimer.get().toFixed(2)} seconds recorded.`);
|
|
551
|
+
debugVideoCapture.stop();
|
|
552
|
+
debugVideoCapture = 0;
|
|
553
|
+
debugVideoCaptureIcon.style.display = 'none';
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// update video capture, called automatically by engine
|
|
557
|
+
function debugVideoCaptureUpdate()
|
|
558
|
+
{
|
|
559
|
+
if (!debugVideoCaptureIsActive())
|
|
560
|
+
return; // not recording
|
|
561
|
+
|
|
562
|
+
// save the video frame
|
|
563
|
+
combineCanvases();
|
|
564
|
+
debugVideoCaptureTrack.requestFrame();
|
|
565
|
+
debugVideoCaptureIcon.textContent = '● REC ' + formatTime(debugVideoCaptureTimer);
|
|
470
566
|
}
|
package/src/engineDraw.js
CHANGED
|
@@ -160,6 +160,8 @@ class TextureInfo
|
|
|
160
160
|
this.image = image;
|
|
161
161
|
/** @property {Vector2} - size of the image */
|
|
162
162
|
this.size = vec2(image.width, image.height);
|
|
163
|
+
/** @property {Vector2} - inverse of the size, cached for rendering */
|
|
164
|
+
this.sizeInverse = vec2(1/image.width, 1/image.height);
|
|
163
165
|
/** @property {WebGLTexture} - webgl texture */
|
|
164
166
|
this.glTexture = glEnable && glCreateTexture(image);
|
|
165
167
|
}
|
|
@@ -205,19 +207,19 @@ function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
|
205
207
|
* @param {Color} [color=(1,1,1,1)] - Color to modulate with
|
|
206
208
|
* @param {number} [angle] - Angle to rotate by
|
|
207
209
|
* @param {boolean} [mirror] - If true image is flipped along the Y axis
|
|
208
|
-
* @param {Color} [additiveColor
|
|
210
|
+
* @param {Color} [additiveColor] - Additive color to be applied if any
|
|
209
211
|
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
210
212
|
* @param {boolean} [screenSpace=false] - If true the pos and size are in screen space
|
|
211
213
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
212
214
|
* @memberof Draw */
|
|
213
215
|
function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
214
|
-
angle=0, mirror, additiveColor
|
|
216
|
+
angle=0, mirror, additiveColor, useWebGL=glEnable, screenSpace, context)
|
|
215
217
|
{
|
|
216
218
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
217
219
|
ASSERT(typeof tileInfo !== 'number' || !tileInfo,
|
|
218
220
|
'this is an old style calls, to fix replace it with tile(tileIndex, tileSize)');
|
|
219
221
|
ASSERT(isVector2(pos) && isVector2(size));
|
|
220
|
-
ASSERT(isColor(color) && isColor(additiveColor));
|
|
222
|
+
ASSERT(isColor(color) && (!additiveColor || isColor(additiveColor)));
|
|
221
223
|
|
|
222
224
|
const textureInfo = tileInfo && tileInfo.getTextureInfo();
|
|
223
225
|
if (useWebGL)
|
|
@@ -228,21 +230,30 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
|
228
230
|
pos = screenToWorld(pos);
|
|
229
231
|
size = size.scale(1/cameraScale);
|
|
230
232
|
}
|
|
231
|
-
|
|
232
233
|
if (textureInfo)
|
|
233
234
|
{
|
|
234
235
|
// calculate uvs and render
|
|
235
|
-
const sizeInverse =
|
|
236
|
+
const sizeInverse = textureInfo.sizeInverse;
|
|
236
237
|
const x = tileInfo.pos.x * sizeInverse.x;
|
|
237
238
|
const y = tileInfo.pos.y * sizeInverse.y;
|
|
238
239
|
const w = tileInfo.size.x * sizeInverse.x;
|
|
239
240
|
const h = tileInfo.size.y * sizeInverse.y;
|
|
240
|
-
const tileImageFixBleed = sizeInverse.scale(tileFixBleedScale);
|
|
241
241
|
glSetTexture(textureInfo.glTexture);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
242
|
+
if (tileFixBleedScale)
|
|
243
|
+
{
|
|
244
|
+
const tileImageFixBleedX = sizeInverse.x*tileFixBleedScale;
|
|
245
|
+
const tileImageFixBleedY = sizeInverse.y*tileFixBleedScale;
|
|
246
|
+
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
247
|
+
x + tileImageFixBleedX, y + tileImageFixBleedY,
|
|
248
|
+
x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
|
|
249
|
+
color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
|
|
250
|
+
}
|
|
251
|
+
else
|
|
252
|
+
{
|
|
253
|
+
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
254
|
+
x, y, x + w, y + h,
|
|
255
|
+
color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
|
|
256
|
+
}
|
|
246
257
|
}
|
|
247
258
|
else
|
|
248
259
|
{
|
|
@@ -454,16 +465,15 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
|
|
|
454
465
|
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, maxWidth=undefined, context=overlayContext)
|
|
455
466
|
{
|
|
456
467
|
context.fillStyle = color.toString();
|
|
457
|
-
context.lineWidth = lineWidth;
|
|
458
468
|
context.strokeStyle = lineColor.toString();
|
|
469
|
+
context.lineWidth = lineWidth;
|
|
459
470
|
context.textAlign = textAlign;
|
|
460
471
|
context.font = size + 'px '+ font;
|
|
461
472
|
context.textBaseline = 'middle';
|
|
462
473
|
context.lineJoin = 'round';
|
|
463
474
|
|
|
464
|
-
pos = pos.copy();
|
|
465
|
-
|
|
466
475
|
const lines = (text+'').split('\n');
|
|
476
|
+
pos = pos.copy();
|
|
467
477
|
pos.y -= (lines.length-1) * size/2; // center text vertically
|
|
468
478
|
lines.forEach(line=>
|
|
469
479
|
{
|
|
@@ -533,7 +543,10 @@ class FontImage
|
|
|
533
543
|
{
|
|
534
544
|
// load default font image
|
|
535
545
|
if (!engineFontImage)
|
|
536
|
-
|
|
546
|
+
{
|
|
547
|
+
engineFontImage = new Image;
|
|
548
|
+
engineFontImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC';
|
|
549
|
+
}
|
|
537
550
|
|
|
538
551
|
this.image = image || engineFontImage;
|
|
539
552
|
this.tileSize = tileSize;
|
package/src/engineExport.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Module Export
|
|
3
|
-
* - Export engine as a module
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
export
|
|
@@ -43,6 +42,10 @@ export
|
|
|
43
42
|
debugSaveCanvas,
|
|
44
43
|
debugSaveText,
|
|
45
44
|
debugSaveDataURL,
|
|
45
|
+
debugShowErrors,
|
|
46
|
+
debugVideoCaptureIsActive,
|
|
47
|
+
debugVideoCaptureStart,
|
|
48
|
+
debugVideoCaptureStop,
|
|
46
49
|
|
|
47
50
|
// Settings
|
|
48
51
|
cameraPos,
|
|
@@ -216,6 +219,7 @@ export
|
|
|
216
219
|
glCopyToContext,
|
|
217
220
|
glCreateProgram,
|
|
218
221
|
glCreateTexture,
|
|
222
|
+
glSetTextureData,
|
|
219
223
|
glDraw,
|
|
220
224
|
glFlush,
|
|
221
225
|
glSetTexture,
|
|
@@ -245,7 +249,8 @@ export
|
|
|
245
249
|
mousePosScreen,
|
|
246
250
|
mouseWheel,
|
|
247
251
|
isUsingGamepad,
|
|
248
|
-
|
|
252
|
+
inputPreventDefault,
|
|
253
|
+
setInputPreventDefault,
|
|
249
254
|
gamepadIsDown,
|
|
250
255
|
gamepadWasPressed,
|
|
251
256
|
gamepadWasReleased,
|
|
@@ -258,28 +263,27 @@ export
|
|
|
258
263
|
// Audio
|
|
259
264
|
Sound,
|
|
260
265
|
SoundWave,
|
|
261
|
-
Music,
|
|
262
266
|
playAudioFile,
|
|
263
267
|
speak,
|
|
264
268
|
speakStop,
|
|
265
269
|
getNoteFrequency,
|
|
266
|
-
audioContext,
|
|
267
270
|
playSamples,
|
|
268
271
|
zzfx,
|
|
272
|
+
zzfxG,
|
|
273
|
+
zzfxR,
|
|
274
|
+
audioContext,
|
|
269
275
|
|
|
270
276
|
// Base Object
|
|
271
277
|
EngineObject,
|
|
272
278
|
|
|
273
279
|
// Tiles
|
|
274
|
-
|
|
275
|
-
tileCollisionSize,
|
|
276
|
-
initTileCollision,
|
|
277
|
-
setTileCollisionData,
|
|
280
|
+
tileCollisionLayers,
|
|
278
281
|
getTileCollisionData,
|
|
279
282
|
tileCollisionTest,
|
|
280
283
|
tileCollisionRaycast,
|
|
281
284
|
TileLayerData,
|
|
282
285
|
TileLayer,
|
|
286
|
+
TileCollisionLayer,
|
|
283
287
|
|
|
284
288
|
// Particles
|
|
285
289
|
ParticleEmitter,
|
package/src/engineInput.js
CHANGED
|
@@ -314,7 +314,9 @@ function gamepadsUpdate()
|
|
|
314
314
|
const button = gamepad.buttons[j];
|
|
315
315
|
const wasDown = gamepadIsDown(j,i);
|
|
316
316
|
data[j] = button.pressed ? wasDown ? 1 : 3 : wasDown ? 4 : 0;
|
|
317
|
-
|
|
317
|
+
if (!button.value || button.value > .9) // must be a full press
|
|
318
|
+
if (!i && button.pressed)
|
|
319
|
+
isUsingGamepad = true;
|
|
318
320
|
}
|
|
319
321
|
|
|
320
322
|
if (gamepadDirectionEmulateStick)
|
package/src/engineObject.js
CHANGED
|
@@ -158,7 +158,10 @@ class EngineObject
|
|
|
158
158
|
this.velocity.x *= this.damping;
|
|
159
159
|
this.velocity.y *= this.damping;
|
|
160
160
|
if (this.mass) // don't apply gravity to static objects
|
|
161
|
-
|
|
161
|
+
{
|
|
162
|
+
this.velocity.x += gravity.x * this.gravityScale;
|
|
163
|
+
this.velocity.y += gravity.y * this.gravityScale;
|
|
164
|
+
}
|
|
162
165
|
this.pos.x += this.velocity.x;
|
|
163
166
|
this.pos.y += this.velocity.y;
|
|
164
167
|
this.angle += this.angleVelocity *= this.angleDamping;
|
|
@@ -173,9 +176,9 @@ class EngineObject
|
|
|
173
176
|
if (this.groundObject)
|
|
174
177
|
{
|
|
175
178
|
// apply friction in local space of ground object
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) *
|
|
179
|
+
const friction = max(this.friction, this.groundObject.friction);
|
|
180
|
+
const groundSpeed = this.groundObject.velocity ? this.groundObject.velocity.x : 0;
|
|
181
|
+
this.velocity.x = groundSpeed + (this.velocity.x - groundSpeed) * friction;
|
|
179
182
|
this.groundObject = undefined;
|
|
180
183
|
//debugOverlay && debugPhysics && debugPoint(this.pos.subtract(vec2(0,this.size.y/2)), '#0f0');
|
|
181
184
|
}
|
|
@@ -217,7 +220,7 @@ class EngineObject
|
|
|
217
220
|
|
|
218
221
|
// check for collision
|
|
219
222
|
const sizeBoth = this.size.add(o.size);
|
|
220
|
-
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity; // prefer to push up if small delta
|
|
223
|
+
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity.y; // prefer to push up if small delta
|
|
221
224
|
const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
|
|
222
225
|
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
|
|
223
226
|
const elasticity = max(this.elasticity, o.elasticity);
|
|
@@ -279,19 +282,21 @@ class EngineObject
|
|
|
279
282
|
if (this.collideTiles)
|
|
280
283
|
{
|
|
281
284
|
// check collision against tiles
|
|
282
|
-
|
|
285
|
+
const hitLayer = tileCollisionTest(this.pos, this.size, this)
|
|
286
|
+
if (hitLayer)
|
|
283
287
|
{
|
|
284
288
|
// if already was stuck in collision, don't do anything
|
|
285
289
|
// this should not happen unless something starts in collision
|
|
286
290
|
if (!tileCollisionTest(oldPos, this.size, this))
|
|
287
291
|
{
|
|
288
292
|
// test which side we bounced off (or both if a corner)
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
293
|
+
const blockedLayerY = tileCollisionTest(vec2(oldPos.x, this.pos.y), this.size, this);
|
|
294
|
+
const blockedLayerX = tileCollisionTest(vec2(this.pos.x, oldPos.y), this.size, this);
|
|
295
|
+
if (blockedLayerY || !blockedLayerX)
|
|
292
296
|
{
|
|
293
297
|
// bounce velocity
|
|
294
|
-
|
|
298
|
+
const elasticity = max(this.elasticity, hitLayer.elasticity);
|
|
299
|
+
this.velocity.y *= -elasticity;
|
|
295
300
|
|
|
296
301
|
if (wasMovingDown)
|
|
297
302
|
{
|
|
@@ -300,9 +305,8 @@ class EngineObject
|
|
|
300
305
|
const epsilon = .0001;
|
|
301
306
|
this.pos.y = (oldPos.y-this.size.y/2|0)+this.size.y/2+epsilon;
|
|
302
307
|
|
|
303
|
-
// set ground object
|
|
304
|
-
|
|
305
|
-
this.groundObject = this;
|
|
308
|
+
// set ground object for tile collision
|
|
309
|
+
this.groundObject = hitLayer;
|
|
306
310
|
}
|
|
307
311
|
else
|
|
308
312
|
{
|
|
@@ -311,7 +315,7 @@ class EngineObject
|
|
|
311
315
|
this.groundObject = undefined;
|
|
312
316
|
}
|
|
313
317
|
}
|
|
314
|
-
if (
|
|
318
|
+
if (blockedLayerX)
|
|
315
319
|
{
|
|
316
320
|
// move to previous position and bounce
|
|
317
321
|
this.pos.x = oldPos.x;
|
package/src/engineParticles.js
CHANGED
|
@@ -166,7 +166,12 @@ class ParticleEmitter extends EngineObject
|
|
|
166
166
|
else
|
|
167
167
|
this.destroy();
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
if (debugParticles)
|
|
170
|
+
{
|
|
171
|
+
// show emitter bounds
|
|
172
|
+
const emitSize = typeof this.emitSize === 'number' ? vec2(this.emitSize) : this.emitSize;
|
|
173
|
+
debugRect(this.pos, emitSize, '#0f0', 0, this.angle);
|
|
174
|
+
}
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
/** Spawn one particle
|
package/src/engineRelease.js
CHANGED
|
@@ -32,4 +32,9 @@ function debugClear (){}
|
|
|
32
32
|
function debugScreenshot (){}
|
|
33
33
|
function debugSaveCanvas (){}
|
|
34
34
|
function debugSaveText (){}
|
|
35
|
-
function debugSaveDataURL(){}
|
|
35
|
+
function debugSaveDataURL(){}
|
|
36
|
+
function debugShowErrors(){}
|
|
37
|
+
function debugVideoCaptureIsActive(){ return false; }
|
|
38
|
+
function debugVideoCaptureStart (){}
|
|
39
|
+
function debugVideoCaptureStop (){}
|
|
40
|
+
function debugVideoCaptureUpdate(){}
|
package/src/engineSettings.js
CHANGED
|
@@ -37,7 +37,7 @@ let canvasMaxSize = vec2(1920, 1080);
|
|
|
37
37
|
* @memberof Settings */
|
|
38
38
|
let canvasFixedSize = vec2();
|
|
39
39
|
|
|
40
|
-
/** Use nearest neighbor scaling
|
|
40
|
+
/** Use nearest neighbor canvas scaling for more pixelated look
|
|
41
41
|
* - Must be set before startup to take effect
|
|
42
42
|
* - If enabled sets css image-rendering:pixelated
|
|
43
43
|
* @type {boolean}
|
|
@@ -147,11 +147,11 @@ let objectDefaultFriction = .8;
|
|
|
147
147
|
* @memberof Settings */
|
|
148
148
|
let objectMaxSpeed = 1;
|
|
149
149
|
|
|
150
|
-
/** How much gravity to apply to objects
|
|
151
|
-
* @type {
|
|
150
|
+
/** How much gravity to apply to objects, negative Y is down
|
|
151
|
+
* @type {Vector2}
|
|
152
152
|
* @default
|
|
153
153
|
* @memberof Settings */
|
|
154
|
-
let gravity =
|
|
154
|
+
let gravity = vec2();
|
|
155
155
|
|
|
156
156
|
/** Scales emit rate of particles, useful for low graphics mode (0 disables particle emitters)
|
|
157
157
|
* @type {number}
|
|
@@ -377,8 +377,8 @@ function setObjectDefaultFriction(friction) { objectDefaultFriction = friction;
|
|
|
377
377
|
* @memberof Settings */
|
|
378
378
|
function setObjectMaxSpeed(speed) { objectMaxSpeed = speed; }
|
|
379
379
|
|
|
380
|
-
/** Set how much gravity to apply to objects
|
|
381
|
-
* @param {
|
|
380
|
+
/** Set how much gravity to apply to objects
|
|
381
|
+
* @param {Vector2} newGravity
|
|
382
382
|
* @memberof Settings */
|
|
383
383
|
function setGravity(newGravity) { gravity = newGravity; }
|
|
384
384
|
|
|
@@ -443,8 +443,8 @@ function setSoundEnable(enable) { soundEnable = enable; }
|
|
|
443
443
|
function setSoundVolume(volume)
|
|
444
444
|
{
|
|
445
445
|
soundVolume = volume;
|
|
446
|
-
if (soundEnable && !headlessMode &&
|
|
447
|
-
|
|
446
|
+
if (soundEnable && !headlessMode && audioMasterGain)
|
|
447
|
+
audioMasterGain.gain.value = volume; // update gain immediately
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
/** Set default range where sound no longer plays
|