littlejsengine 1.18.0 → 1.18.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/CLAUDE.md +1 -0
- package/README.md +13 -4
- package/dist/littlejs.d.ts +11 -0
- package/dist/littlejs.esm.js +62 -16
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +60 -16
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +58 -16
- package/examples/box2d/game.js +2 -2
- package/examples/box2d/gameObjects.js +74 -0
- package/examples/box2d/scenes.js +7 -0
- package/examples/shorts/base.html +1 -1
- package/examples/starter/index.html +2 -2
- package/examples/stress/index.html +1 -1
- package/package.json +1 -1
- package/src/engine.js +23 -6
- package/src/engineBuild.mjs +1 -1
- package/src/engineDebug.js +2 -0
- package/src/engineDraw.js +1 -0
- package/src/engineExport.js +2 -0
- package/src/engineInput.js +17 -6
- package/src/engineMath.js +1 -1
- package/src/engineObject.js +3 -3
- package/src/engineSettings.js +13 -0
package/dist/littlejs.release.js
CHANGED
|
@@ -35,7 +35,7 @@ const engineName = 'LittleJS';
|
|
|
35
35
|
* @type {string}
|
|
36
36
|
* @default
|
|
37
37
|
* @memberof Engine */
|
|
38
|
-
const engineVersion = '1.18.
|
|
38
|
+
const engineVersion = '1.18.1';
|
|
39
39
|
|
|
40
40
|
/** Frames per second to update
|
|
41
41
|
* @type {number}
|
|
@@ -318,12 +318,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
318
318
|
}
|
|
319
319
|
else
|
|
320
320
|
{
|
|
321
|
+
// apply device pixel ratio for crisp rendering
|
|
322
|
+
const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
|
|
323
|
+
const viewWidth = innerWidth * dpr | 0;
|
|
324
|
+
const viewHeight = innerHeight * dpr | 0;
|
|
325
|
+
|
|
321
326
|
// get main canvas size based on window size
|
|
322
|
-
mainCanvasSize.x = min(
|
|
323
|
-
mainCanvasSize.y = min(
|
|
327
|
+
mainCanvasSize.x = min(viewWidth, canvasMaxSize.x);
|
|
328
|
+
mainCanvasSize.y = min(viewHeight, canvasMaxSize.y);
|
|
324
329
|
|
|
325
330
|
// responsive aspect ratio with native resolution
|
|
326
|
-
const innerAspect =
|
|
331
|
+
const innerAspect = viewWidth / viewHeight;
|
|
327
332
|
ASSERT(canvasMinAspect <= canvasMaxAspect);
|
|
328
333
|
if (canvasMaxAspect && innerAspect > canvasMaxAspect)
|
|
329
334
|
{
|
|
@@ -337,6 +342,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
337
342
|
const h = mainCanvasSize.x / canvasMinAspect | 0;
|
|
338
343
|
mainCanvasSize.y = min(h, canvasMaxSize.y);
|
|
339
344
|
}
|
|
345
|
+
|
|
346
|
+
// set CSS display size so backing store renders at viewport size
|
|
347
|
+
const cssW = (mainCanvasSize.x / dpr | 0) + 'px';
|
|
348
|
+
const cssH = (mainCanvasSize.y / dpr | 0) + 'px';
|
|
349
|
+
mainCanvas.style.width = cssW;
|
|
350
|
+
mainCanvas.style.height = cssH;
|
|
351
|
+
if (glCanvas)
|
|
352
|
+
{
|
|
353
|
+
glCanvas.style.width = cssW;
|
|
354
|
+
glCanvas.style.height = cssH;
|
|
355
|
+
}
|
|
340
356
|
}
|
|
341
357
|
|
|
342
358
|
// clear main canvas and set size
|
|
@@ -556,8 +572,9 @@ function drawEngineLogo(t)
|
|
|
556
572
|
|
|
557
573
|
// LittleJS Logo and Splash Screen
|
|
558
574
|
const x = mainContext;
|
|
559
|
-
const
|
|
560
|
-
const
|
|
575
|
+
const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
|
|
576
|
+
const w = mainCanvas.width = innerWidth * dpr;
|
|
577
|
+
const h = mainCanvas.height = innerHeight * dpr;
|
|
561
578
|
{
|
|
562
579
|
// background
|
|
563
580
|
const p3 = percent(t, 1, .8);
|
|
@@ -1054,7 +1071,7 @@ function lineTest(posStart, posEnd, testFunction, normal)
|
|
|
1054
1071
|
// get ray direction and length
|
|
1055
1072
|
const dx = posEnd.x - posStart.x;
|
|
1056
1073
|
const dy = posEnd.y - posStart.y;
|
|
1057
|
-
const totalLength =
|
|
1074
|
+
const totalLength = (dx*dx + dy*dy)**.5;
|
|
1058
1075
|
if (!totalLength) return;
|
|
1059
1076
|
|
|
1060
1077
|
// current integer cell we are in
|
|
@@ -2158,6 +2175,13 @@ let canvasPixelated = false;
|
|
|
2158
2175
|
* @memberof Settings */
|
|
2159
2176
|
let tilesPixelated = true;
|
|
2160
2177
|
|
|
2178
|
+
/** Scale factor applied to the canvas backing store for native-resolution rendering.
|
|
2179
|
+
* Pass 1 for no scaling, a number for an explicit ratio, or undefined to track devicePixelRatio each frame.
|
|
2180
|
+
* @type {number|undefined}
|
|
2181
|
+
* @default
|
|
2182
|
+
* @memberof Settings */
|
|
2183
|
+
let canvasPixelRatio = 1;
|
|
2184
|
+
|
|
2161
2185
|
/** Default font used for text rendering
|
|
2162
2186
|
* @type {string}
|
|
2163
2187
|
* @default
|
|
@@ -2470,6 +2494,12 @@ function setCanvasPixelated(pixelated)
|
|
|
2470
2494
|
* @memberof Settings */
|
|
2471
2495
|
function setTilesPixelated(pixelated) { tilesPixelated = pixelated; }
|
|
2472
2496
|
|
|
2497
|
+
/** Set the canvas pixel ratio.
|
|
2498
|
+
* Pass a number for an explicit ratio, or call with no argument to track devicePixelRatio each frame.
|
|
2499
|
+
* @param {number} [pixelRatio]
|
|
2500
|
+
* @memberof Settings */
|
|
2501
|
+
function setCanvasPixelRatio(pixelRatio) { canvasPixelRatio = pixelRatio; }
|
|
2502
|
+
|
|
2473
2503
|
/** Set default font used for text rendering
|
|
2474
2504
|
* @param {string} font
|
|
2475
2505
|
* @memberof Settings */
|
|
@@ -2892,10 +2922,10 @@ class EngineObject
|
|
|
2892
2922
|
// if already was touching, try to push away
|
|
2893
2923
|
const deltaPos = oldPos.subtract(o.pos);
|
|
2894
2924
|
const length = deltaPos.length();
|
|
2895
|
-
const pushAwayAccel = .001;
|
|
2896
|
-
const velocity = length < .
|
|
2925
|
+
const pushAwayAccel = .001;
|
|
2926
|
+
const velocity = length < .001 ? vec2(0,1) : deltaPos.scale(pushAwayAccel/length);
|
|
2897
2927
|
this.velocity = this.velocity.add(velocity);
|
|
2898
|
-
if (o.mass) // push away if not fixed
|
|
2928
|
+
if (o.mass) // push away other object if not fixed
|
|
2899
2929
|
o.velocity = o.velocity.subtract(velocity);
|
|
2900
2930
|
|
|
2901
2931
|
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
|
|
@@ -3324,6 +3354,7 @@ function tile(index=new Vector2, size=tileDefaultSize, texture=0, padding=tileDe
|
|
|
3324
3354
|
const textureInfo = typeof texture === 'number' ?
|
|
3325
3355
|
textureInfos[texture] : texture;
|
|
3326
3356
|
ASSERT(textureInfo instanceof TextureInfo, 'tile texture is not loaded');
|
|
3357
|
+
ASSERT(textureInfo.size.x > 0, 'tile texture is not loaded');
|
|
3327
3358
|
|
|
3328
3359
|
// get the position of the tile
|
|
3329
3360
|
const sizePaddedX = size.x + padding*2;
|
|
@@ -4686,7 +4717,7 @@ function inputInit()
|
|
|
4686
4717
|
document.addEventListener('mouseup', onMouseUp);
|
|
4687
4718
|
document.addEventListener('mousemove', onMouseMove);
|
|
4688
4719
|
document.addEventListener('mouseleave', onMouseLeave);
|
|
4689
|
-
document.addEventListener('wheel', onMouseWheel);
|
|
4720
|
+
document.addEventListener('wheel', onMouseWheel, { passive: false });
|
|
4690
4721
|
document.addEventListener('contextmenu', onContextMenu);
|
|
4691
4722
|
document.addEventListener('blur', onBlur);
|
|
4692
4723
|
|
|
@@ -4705,7 +4736,7 @@ function inputInit()
|
|
|
4705
4736
|
}
|
|
4706
4737
|
|
|
4707
4738
|
// try to prevent default browser handling of input
|
|
4708
|
-
if (!inputPreventDefault || !
|
|
4739
|
+
if (!inputPreventDefault || !e.cancelable || !document.hasFocus()) return;
|
|
4709
4740
|
|
|
4710
4741
|
// don't break browser shortcuts
|
|
4711
4742
|
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
@@ -4764,7 +4795,7 @@ function inputInit()
|
|
|
4764
4795
|
mousePosScreen = mouseEventToScreen(vec2(e.x,e.y));
|
|
4765
4796
|
mouseDeltaScreen = mouseDeltaScreen.add(mousePosScreen.subtract(mousePosScreenLast));
|
|
4766
4797
|
|
|
4767
|
-
if (inputPreventDefault &&
|
|
4798
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
4768
4799
|
e.preventDefault();
|
|
4769
4800
|
}
|
|
4770
4801
|
function onMouseUp(e)
|
|
@@ -4786,7 +4817,12 @@ function inputInit()
|
|
|
4786
4817
|
mouseDeltaScreen = mouseDeltaScreen.add(movement);
|
|
4787
4818
|
}
|
|
4788
4819
|
function onMouseLeave() { mouseInWindow = false; } // mouse moved off window
|
|
4789
|
-
function onMouseWheel(e)
|
|
4820
|
+
function onMouseWheel(e)
|
|
4821
|
+
{
|
|
4822
|
+
mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
|
|
4823
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
4824
|
+
e.preventDefault(); // prevent page scrolling
|
|
4825
|
+
}
|
|
4790
4826
|
function onContextMenu(e) { e.preventDefault(); } // prevent right click menu
|
|
4791
4827
|
function onBlur() { inputClear(); } // reset input when focus is lost
|
|
4792
4828
|
|
|
@@ -4836,7 +4872,7 @@ function inputInit()
|
|
|
4836
4872
|
wasTouching = touching;
|
|
4837
4873
|
|
|
4838
4874
|
// prevent default handling like copy, magnifier lens, and scrolling
|
|
4839
|
-
if (inputPreventDefault &&
|
|
4875
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
4840
4876
|
e.preventDefault();
|
|
4841
4877
|
|
|
4842
4878
|
// must return true so the document will get focus
|
|
@@ -4994,7 +5030,13 @@ function inputUpdate()
|
|
|
4994
5030
|
}
|
|
4995
5031
|
|
|
4996
5032
|
// return if gamepads are disabled or not supported
|
|
4997
|
-
|
|
5033
|
+
try {
|
|
5034
|
+
// protect against getGamepads disallowed security error
|
|
5035
|
+
if (!gamepadsEnable || !navigator?.getGamepads)
|
|
5036
|
+
return;
|
|
5037
|
+
} catch(e) {
|
|
5038
|
+
return;
|
|
5039
|
+
}
|
|
4998
5040
|
|
|
4999
5041
|
// only poll gamepads when focused or in debug mode
|
|
5000
5042
|
if (!debug && !document.hasFocus()) return;
|
package/examples/box2d/game.js
CHANGED
|
@@ -24,7 +24,7 @@ LJS.setTilesPixelated(false);
|
|
|
24
24
|
///////////////////////////////////////////////////////////////////////////////
|
|
25
25
|
// game variables
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const sceneCount = 12;
|
|
28
28
|
const startScene = 0;
|
|
29
29
|
export let spriteAtlas, groundObject, mouseJoint, repeatSpawnTimer = new LJS.Timer;
|
|
30
30
|
const sound_click = new LJS.Sound([.2,.1,,,,.01,,,,,,,,,,,,,,,-500]);
|
|
@@ -125,7 +125,7 @@ function gameUpdate()
|
|
|
125
125
|
{
|
|
126
126
|
// change scene
|
|
127
127
|
const upPressed = LJS.keyWasPressed('ArrowUp');
|
|
128
|
-
setScene(LJS.mod(Scenes.scene + (upPressed?1:-1),
|
|
128
|
+
setScene(LJS.mod(Scenes.scene + (upPressed?1:-1), sceneCount));
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -446,6 +446,80 @@ export class ClothObject extends LJS.Box2dStaticObject
|
|
|
446
446
|
}
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
450
|
+
|
|
451
|
+
// ragdoll with head, arms, and legs connected to torso by revolute joints
|
|
452
|
+
export class RagdollObject extends LJS.Box2dObject
|
|
453
|
+
{
|
|
454
|
+
constructor(pos, scale=1, color=LJS.randColor())
|
|
455
|
+
{
|
|
456
|
+
const headSize = .8 * scale;
|
|
457
|
+
const torsoWidth = 1.2 * scale;
|
|
458
|
+
const torsoHeight = 2 * scale;
|
|
459
|
+
const limbWidth = .4 * scale;
|
|
460
|
+
const upperArmLen = 1 * scale;
|
|
461
|
+
const lowerArmLen = 1 * scale;
|
|
462
|
+
const upperLegLen = 1.1 * scale;
|
|
463
|
+
const lowerLegLen = 1.1 * scale;
|
|
464
|
+
|
|
465
|
+
// torso is the main body
|
|
466
|
+
super(pos, vec2(torsoWidth, torsoHeight), 0, 0, color);
|
|
467
|
+
this.addBox(vec2(torsoWidth, torsoHeight), vec2(), 0, density, friction, restitution);
|
|
468
|
+
this.limbs = [];
|
|
469
|
+
|
|
470
|
+
const addLimb = (offset, size, isCircle=false) =>
|
|
471
|
+
{
|
|
472
|
+
const o = new LJS.Box2dObject(pos.add(offset), size, 0, 0, color);
|
|
473
|
+
if (isCircle)
|
|
474
|
+
o.addCircle(size.x, vec2(), density, friction, restitution);
|
|
475
|
+
else
|
|
476
|
+
o.addBox(size, vec2(), 0, density, friction, restitution);
|
|
477
|
+
this.limbs.push(o);
|
|
478
|
+
return o;
|
|
479
|
+
};
|
|
480
|
+
const addJoint = (a, b, anchor, lower, upper) =>
|
|
481
|
+
{
|
|
482
|
+
const joint = new LJS.Box2dRevoluteJoint(a, b, anchor);
|
|
483
|
+
joint.enableLimit();
|
|
484
|
+
joint.setLimits(lower, upper);
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// head
|
|
488
|
+
const head = addLimb(vec2(0, torsoHeight/2 + headSize/2 + .1*scale), vec2(headSize), true);
|
|
489
|
+
addJoint(this, head, pos.add(vec2(0, torsoHeight/2)), -.5, .5);
|
|
490
|
+
|
|
491
|
+
// arms
|
|
492
|
+
const shoulderY = torsoHeight/2 - .2*scale;
|
|
493
|
+
for (const side of [-1, 1])
|
|
494
|
+
{
|
|
495
|
+
const shoulder = pos.add(vec2(side*torsoWidth/2, shoulderY));
|
|
496
|
+
const upperArm = addLimb(vec2(side*(torsoWidth/2 + upperArmLen/2), shoulderY), vec2(upperArmLen, limbWidth));
|
|
497
|
+
addJoint(this, upperArm, shoulder, -2, 2);
|
|
498
|
+
|
|
499
|
+
const elbow = shoulder.add(vec2(side*upperArmLen, 0));
|
|
500
|
+
const lowerArm = addLimb(vec2(side*(torsoWidth/2 + upperArmLen + lowerArmLen/2), shoulderY), vec2(lowerArmLen, limbWidth));
|
|
501
|
+
addJoint(upperArm, lowerArm, elbow, -2.5, 2.5);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// legs
|
|
505
|
+
for (const side of [-1, 1])
|
|
506
|
+
{
|
|
507
|
+
const hip = pos.add(vec2(side*torsoWidth/4, -torsoHeight/2));
|
|
508
|
+
const upperLeg = addLimb(vec2(side*torsoWidth/4, -torsoHeight/2 - upperLegLen/2), vec2(limbWidth, upperLegLen));
|
|
509
|
+
addJoint(this, upperLeg, hip, -.5, 2.5);
|
|
510
|
+
|
|
511
|
+
const knee = hip.add(vec2(0, -upperLegLen));
|
|
512
|
+
const lowerLeg = addLimb(vec2(side*torsoWidth/4, -torsoHeight/2 - upperLegLen - lowerLegLen/2), vec2(limbWidth, lowerLegLen));
|
|
513
|
+
addJoint(upperLeg, lowerLeg, knee, -2.5, 2.5);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
destroy()
|
|
517
|
+
{
|
|
518
|
+
this.limbs.forEach(o => o.destroy());
|
|
519
|
+
super.destroy();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
449
523
|
///////////////////////////////////////////////////////////////////////////////
|
|
450
524
|
// Effects
|
|
451
525
|
|
package/examples/box2d/scenes.js
CHANGED
|
@@ -184,4 +184,11 @@ export function loadScene(_scene)
|
|
|
184
184
|
for (let i=3;i--;)
|
|
185
185
|
new GameObjects.SoftBodyObject(vec2(20, 3+i*7), vec2(6-i), vec2(9-i), LJS.randColor());
|
|
186
186
|
}
|
|
187
|
+
if (scene == 11)
|
|
188
|
+
{
|
|
189
|
+
sceneName = 'Ragdolls';
|
|
190
|
+
new GameObjects.RagdollObject(vec2(20,5));
|
|
191
|
+
new GameObjects.RagdollObject(vec2(10,8), 2);
|
|
192
|
+
GameObjects.spawnPyramid(vec2(30,0), 6);
|
|
193
|
+
}
|
|
187
194
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</head><body>
|
|
8
8
|
|
|
9
9
|
<!-- LittleJS Engine -->
|
|
10
|
-
<script src=../../dist/littlejs.js?1.18.
|
|
10
|
+
<script src=../../dist/littlejs.js?1.18.1></script>
|
|
11
11
|
|
|
12
12
|
<!-- LittleJS Engine Source
|
|
13
13
|
<script src=../../src/engine.js></script>
|
|
@@ -32,4 +32,4 @@
|
|
|
32
32
|
-->
|
|
33
33
|
|
|
34
34
|
<!-- Add your game scripts here -->
|
|
35
|
-
<script src=game.js?1.18.
|
|
35
|
+
<script src=game.js?1.18.1></script>
|
package/package.json
CHANGED
package/src/engine.js
CHANGED
|
@@ -32,7 +32,7 @@ const engineName = 'LittleJS';
|
|
|
32
32
|
* @type {string}
|
|
33
33
|
* @default
|
|
34
34
|
* @memberof Engine */
|
|
35
|
-
const engineVersion = '1.18.
|
|
35
|
+
const engineVersion = '1.18.1';
|
|
36
36
|
|
|
37
37
|
/** Frames per second to update
|
|
38
38
|
* @type {number}
|
|
@@ -315,12 +315,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
315
315
|
}
|
|
316
316
|
else
|
|
317
317
|
{
|
|
318
|
+
// apply device pixel ratio for crisp rendering
|
|
319
|
+
const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
|
|
320
|
+
const viewWidth = innerWidth * dpr | 0;
|
|
321
|
+
const viewHeight = innerHeight * dpr | 0;
|
|
322
|
+
|
|
318
323
|
// get main canvas size based on window size
|
|
319
|
-
mainCanvasSize.x = min(
|
|
320
|
-
mainCanvasSize.y = min(
|
|
324
|
+
mainCanvasSize.x = min(viewWidth, canvasMaxSize.x);
|
|
325
|
+
mainCanvasSize.y = min(viewHeight, canvasMaxSize.y);
|
|
321
326
|
|
|
322
327
|
// responsive aspect ratio with native resolution
|
|
323
|
-
const innerAspect =
|
|
328
|
+
const innerAspect = viewWidth / viewHeight;
|
|
324
329
|
ASSERT(canvasMinAspect <= canvasMaxAspect);
|
|
325
330
|
if (canvasMaxAspect && innerAspect > canvasMaxAspect)
|
|
326
331
|
{
|
|
@@ -334,6 +339,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
334
339
|
const h = mainCanvasSize.x / canvasMinAspect | 0;
|
|
335
340
|
mainCanvasSize.y = min(h, canvasMaxSize.y);
|
|
336
341
|
}
|
|
342
|
+
|
|
343
|
+
// set CSS display size so backing store renders at viewport size
|
|
344
|
+
const cssW = (mainCanvasSize.x / dpr | 0) + 'px';
|
|
345
|
+
const cssH = (mainCanvasSize.y / dpr | 0) + 'px';
|
|
346
|
+
mainCanvas.style.width = cssW;
|
|
347
|
+
mainCanvas.style.height = cssH;
|
|
348
|
+
if (glCanvas)
|
|
349
|
+
{
|
|
350
|
+
glCanvas.style.width = cssW;
|
|
351
|
+
glCanvas.style.height = cssH;
|
|
352
|
+
}
|
|
337
353
|
}
|
|
338
354
|
|
|
339
355
|
// clear main canvas and set size
|
|
@@ -553,8 +569,9 @@ function drawEngineLogo(t)
|
|
|
553
569
|
|
|
554
570
|
// LittleJS Logo and Splash Screen
|
|
555
571
|
const x = mainContext;
|
|
556
|
-
const
|
|
557
|
-
const
|
|
572
|
+
const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
|
|
573
|
+
const w = mainCanvas.width = innerWidth * dpr;
|
|
574
|
+
const h = mainCanvas.height = innerHeight * dpr;
|
|
558
575
|
{
|
|
559
576
|
// background
|
|
560
577
|
const p3 = percent(t, 1, .8);
|
package/src/engineBuild.mjs
CHANGED
|
@@ -61,7 +61,7 @@ const license = '// LittleJS Engine - MIT License - Copyright 2021 Frank Force\n
|
|
|
61
61
|
'// https://github.com/KilledByAPixel/LittleJS\n\n';
|
|
62
62
|
|
|
63
63
|
console.log(asciiArt);
|
|
64
|
-
console.log('
|
|
64
|
+
console.log('Choo Choo... Building LittleJS Engine!');
|
|
65
65
|
const startTime = Date.now();
|
|
66
66
|
|
|
67
67
|
try
|
package/src/engineDebug.js
CHANGED
package/src/engineDraw.js
CHANGED
|
@@ -110,6 +110,7 @@ function tile(index=new Vector2, size=tileDefaultSize, texture=0, padding=tileDe
|
|
|
110
110
|
const textureInfo = typeof texture === 'number' ?
|
|
111
111
|
textureInfos[texture] : texture;
|
|
112
112
|
ASSERT(textureInfo instanceof TextureInfo, 'tile texture is not loaded');
|
|
113
|
+
ASSERT(textureInfo.size.x > 0, 'tile texture is not loaded');
|
|
113
114
|
|
|
114
115
|
// get the position of the tile
|
|
115
116
|
const sizePaddedX = size.x + padding*2;
|
package/src/engineExport.js
CHANGED
|
@@ -59,6 +59,7 @@ export
|
|
|
59
59
|
canvasFixedSize,
|
|
60
60
|
canvasPixelated,
|
|
61
61
|
tilesPixelated,
|
|
62
|
+
canvasPixelRatio,
|
|
62
63
|
fontDefault,
|
|
63
64
|
showSplashScreen,
|
|
64
65
|
headlessMode,
|
|
@@ -105,6 +106,7 @@ export
|
|
|
105
106
|
setCanvasFixedSize,
|
|
106
107
|
setCanvasPixelated,
|
|
107
108
|
setTilesPixelated,
|
|
109
|
+
setCanvasPixelRatio,
|
|
108
110
|
setFontDefault,
|
|
109
111
|
setShowSplashScreen,
|
|
110
112
|
setHeadlessMode,
|
package/src/engineInput.js
CHANGED
|
@@ -321,7 +321,7 @@ function inputInit()
|
|
|
321
321
|
document.addEventListener('mouseup', onMouseUp);
|
|
322
322
|
document.addEventListener('mousemove', onMouseMove);
|
|
323
323
|
document.addEventListener('mouseleave', onMouseLeave);
|
|
324
|
-
document.addEventListener('wheel', onMouseWheel);
|
|
324
|
+
document.addEventListener('wheel', onMouseWheel, { passive: false });
|
|
325
325
|
document.addEventListener('contextmenu', onContextMenu);
|
|
326
326
|
document.addEventListener('blur', onBlur);
|
|
327
327
|
|
|
@@ -340,7 +340,7 @@ function inputInit()
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
// try to prevent default browser handling of input
|
|
343
|
-
if (!inputPreventDefault || !
|
|
343
|
+
if (!inputPreventDefault || !e.cancelable || !document.hasFocus()) return;
|
|
344
344
|
|
|
345
345
|
// don't break browser shortcuts
|
|
346
346
|
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
@@ -399,7 +399,7 @@ function inputInit()
|
|
|
399
399
|
mousePosScreen = mouseEventToScreen(vec2(e.x,e.y));
|
|
400
400
|
mouseDeltaScreen = mouseDeltaScreen.add(mousePosScreen.subtract(mousePosScreenLast));
|
|
401
401
|
|
|
402
|
-
if (inputPreventDefault &&
|
|
402
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
403
403
|
e.preventDefault();
|
|
404
404
|
}
|
|
405
405
|
function onMouseUp(e)
|
|
@@ -421,7 +421,12 @@ function inputInit()
|
|
|
421
421
|
mouseDeltaScreen = mouseDeltaScreen.add(movement);
|
|
422
422
|
}
|
|
423
423
|
function onMouseLeave() { mouseInWindow = false; } // mouse moved off window
|
|
424
|
-
function onMouseWheel(e)
|
|
424
|
+
function onMouseWheel(e)
|
|
425
|
+
{
|
|
426
|
+
mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
|
|
427
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
428
|
+
e.preventDefault(); // prevent page scrolling
|
|
429
|
+
}
|
|
425
430
|
function onContextMenu(e) { e.preventDefault(); } // prevent right click menu
|
|
426
431
|
function onBlur() { inputClear(); } // reset input when focus is lost
|
|
427
432
|
|
|
@@ -471,7 +476,7 @@ function inputInit()
|
|
|
471
476
|
wasTouching = touching;
|
|
472
477
|
|
|
473
478
|
// prevent default handling like copy, magnifier lens, and scrolling
|
|
474
|
-
if (inputPreventDefault &&
|
|
479
|
+
if (inputPreventDefault && e.cancelable && document.hasFocus())
|
|
475
480
|
e.preventDefault();
|
|
476
481
|
|
|
477
482
|
// must return true so the document will get focus
|
|
@@ -629,7 +634,13 @@ function inputUpdate()
|
|
|
629
634
|
}
|
|
630
635
|
|
|
631
636
|
// return if gamepads are disabled or not supported
|
|
632
|
-
|
|
637
|
+
try {
|
|
638
|
+
// protect against getGamepads disallowed security error
|
|
639
|
+
if (!gamepadsEnable || !navigator?.getGamepads)
|
|
640
|
+
return;
|
|
641
|
+
} catch(e) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
633
644
|
|
|
634
645
|
// only poll gamepads when focused or in debug mode
|
|
635
646
|
if (!debug && !document.hasFocus()) return;
|
package/src/engineMath.js
CHANGED
|
@@ -327,7 +327,7 @@ function lineTest(posStart, posEnd, testFunction, normal)
|
|
|
327
327
|
// get ray direction and length
|
|
328
328
|
const dx = posEnd.x - posStart.x;
|
|
329
329
|
const dy = posEnd.y - posStart.y;
|
|
330
|
-
const totalLength =
|
|
330
|
+
const totalLength = (dx*dx + dy*dy)**.5;
|
|
331
331
|
if (!totalLength) return;
|
|
332
332
|
|
|
333
333
|
// current integer cell we are in
|
package/src/engineObject.js
CHANGED
|
@@ -212,10 +212,10 @@ class EngineObject
|
|
|
212
212
|
// if already was touching, try to push away
|
|
213
213
|
const deltaPos = oldPos.subtract(o.pos);
|
|
214
214
|
const length = deltaPos.length();
|
|
215
|
-
const pushAwayAccel = .001;
|
|
216
|
-
const velocity = length < .
|
|
215
|
+
const pushAwayAccel = .001;
|
|
216
|
+
const velocity = length < .001 ? vec2(0,1) : deltaPos.scale(pushAwayAccel/length);
|
|
217
217
|
this.velocity = this.velocity.add(velocity);
|
|
218
|
-
if (o.mass) // push away if not fixed
|
|
218
|
+
if (o.mass) // push away other object if not fixed
|
|
219
219
|
o.velocity = o.velocity.subtract(velocity);
|
|
220
220
|
|
|
221
221
|
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
|
package/src/engineSettings.js
CHANGED
|
@@ -82,6 +82,13 @@ let canvasPixelated = false;
|
|
|
82
82
|
* @memberof Settings */
|
|
83
83
|
let tilesPixelated = true;
|
|
84
84
|
|
|
85
|
+
/** Scale factor applied to the canvas backing store for native-resolution rendering.
|
|
86
|
+
* Pass 1 for no scaling, a number for an explicit ratio, or undefined to track devicePixelRatio each frame.
|
|
87
|
+
* @type {number|undefined}
|
|
88
|
+
* @default
|
|
89
|
+
* @memberof Settings */
|
|
90
|
+
let canvasPixelRatio = 1;
|
|
91
|
+
|
|
85
92
|
/** Default font used for text rendering
|
|
86
93
|
* @type {string}
|
|
87
94
|
* @default
|
|
@@ -394,6 +401,12 @@ function setCanvasPixelated(pixelated)
|
|
|
394
401
|
* @memberof Settings */
|
|
395
402
|
function setTilesPixelated(pixelated) { tilesPixelated = pixelated; }
|
|
396
403
|
|
|
404
|
+
/** Set the canvas pixel ratio.
|
|
405
|
+
* Pass a number for an explicit ratio, or call with no argument to track devicePixelRatio each frame.
|
|
406
|
+
* @param {number} [pixelRatio]
|
|
407
|
+
* @memberof Settings */
|
|
408
|
+
function setCanvasPixelRatio(pixelRatio) { canvasPixelRatio = pixelRatio; }
|
|
409
|
+
|
|
397
410
|
/** Set default font used for text rendering
|
|
398
411
|
* @param {string} font
|
|
399
412
|
* @memberof Settings */
|