littlejsengine 1.14.7 → 1.14.9
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 +15 -7
- package/dist/littlejs.esm.js +72 -54
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +72 -54
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +72 -54
- package/examples/index.html +10 -5
- package/examples/platformer/gameEffects.js +6 -2
- package/examples/platformer/gameLevel.js +1 -7
- package/examples/shorts/box2dCar.js +2 -1
- package/examples/shorts/piano.js +24 -25
- package/examples/shorts/sound.js +21 -33
- package/examples/shorts/uiSystem.js +13 -6
- package/package.json +1 -1
- package/plugins/uiSystem.js +49 -41
- package/reference.md +1 -0
- package/src/engine.js +1 -1
- package/src/engineDraw.js +1 -1
- package/src/engineInput.js +7 -0
- package/src/engineObject.js +4 -4
- package/src/engineSettings.js +1 -1
- package/src/engineTileLayer.js +2 -2
- package/src/engineUtilities.js +5 -2
- package/src/engineWebGL.js +2 -2
package/dist/littlejs.release.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.14.
|
|
36
|
+
const engineVersion = '1.14.9';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -865,8 +865,11 @@ function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
|
865
865
|
* @memberof Utilities */
|
|
866
866
|
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
867
867
|
{
|
|
868
|
-
|
|
869
|
-
|
|
868
|
+
const dx = (posA.x - posB.x)*2;
|
|
869
|
+
const dy = (posA.y - posB.y)*2;
|
|
870
|
+
const sx = sizeA.x + sizeB.x;
|
|
871
|
+
const sy = sizeA.y + sizeB.y;
|
|
872
|
+
return dx >= -sx && dx < sx && dy >= -sy && dy < sy;
|
|
870
873
|
}
|
|
871
874
|
|
|
872
875
|
/** Returns true if a line segment is intersecting an axis aligned box
|
|
@@ -2097,7 +2100,7 @@ function setGLEnable(enable)
|
|
|
2097
2100
|
glCanvas.style.visibility = enable ? 'visible' : 'hidden';
|
|
2098
2101
|
}
|
|
2099
2102
|
|
|
2100
|
-
/** Set how many sided polygons to use when drawing circles and
|
|
2103
|
+
/** Set how many sided polygons to use when drawing circles and ellipses with WebGL
|
|
2101
2104
|
* @param {number} sides
|
|
2102
2105
|
* @memberof Settings */
|
|
2103
2106
|
function setGLCircleSides(sides) { glCircleSides = sides; }
|
|
@@ -2308,7 +2311,7 @@ class EngineObject
|
|
|
2308
2311
|
/** @property {Vector2} - World space position of the object */
|
|
2309
2312
|
this.pos = pos.copy();
|
|
2310
2313
|
/** @property {Vector2} - World space width and height of the object */
|
|
2311
|
-
this.size = size;
|
|
2314
|
+
this.size = size.copy();
|
|
2312
2315
|
/** @property {Vector2} - Size of object used for drawing, uses size if not set */
|
|
2313
2316
|
this.drawSize = undefined;
|
|
2314
2317
|
/** @property {TileInfo} - Tile info to render object (undefined is untextured) */
|
|
@@ -2316,7 +2319,7 @@ class EngineObject
|
|
|
2316
2319
|
/** @property {number} - Angle to rotate the object */
|
|
2317
2320
|
this.angle = angle;
|
|
2318
2321
|
/** @property {Color} - Color to apply when rendered */
|
|
2319
|
-
this.color = color;
|
|
2322
|
+
this.color = color.copy();
|
|
2320
2323
|
/** @property {Color} - Additive color to apply when rendered */
|
|
2321
2324
|
this.additiveColor = undefined;
|
|
2322
2325
|
/** @property {boolean} - Should it flip along y axis when rendered */
|
|
@@ -2440,7 +2443,7 @@ class EngineObject
|
|
|
2440
2443
|
for (const o of engineObjectsCollide)
|
|
2441
2444
|
{
|
|
2442
2445
|
// non solid objects don't collide with each other
|
|
2443
|
-
if (!this.isSolid && !o.isSolid || o.destroyed || o.parent || o === this)
|
|
2446
|
+
if ((!this.isSolid && !o.isSolid) || o.destroyed || o.parent || o === this)
|
|
2444
2447
|
continue;
|
|
2445
2448
|
|
|
2446
2449
|
// check collision
|
|
@@ -2479,7 +2482,7 @@ class EngineObject
|
|
|
2479
2482
|
{
|
|
2480
2483
|
// push outside object collision
|
|
2481
2484
|
this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
|
|
2482
|
-
if (o.groundObject && wasMovingDown || !o.mass)
|
|
2485
|
+
if ((o.groundObject && wasMovingDown) || !o.mass)
|
|
2483
2486
|
{
|
|
2484
2487
|
// set ground object if landed on something
|
|
2485
2488
|
if (wasMovingDown)
|
|
@@ -3630,7 +3633,7 @@ class FontImage
|
|
|
3630
3633
|
* @param {Vector2} pos
|
|
3631
3634
|
* @param {number} [scale=.25]
|
|
3632
3635
|
* @param {boolean} [center]
|
|
3633
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}[context=drawContext]
|
|
3636
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
3634
3637
|
*/
|
|
3635
3638
|
drawText(text, pos, scale=1, center, context=drawContext)
|
|
3636
3639
|
{
|
|
@@ -3897,6 +3900,7 @@ function inputInit()
|
|
|
3897
3900
|
document.addEventListener('wheel', onMouseWheel);
|
|
3898
3901
|
document.addEventListener('contextmenu', onContextMenu);
|
|
3899
3902
|
document.addEventListener('blur', onBlur);
|
|
3903
|
+
document.addEventListener('mouseleave', onMouseLeave);
|
|
3900
3904
|
|
|
3901
3905
|
// init touch input
|
|
3902
3906
|
if (isTouchDevice && touchInputEnable)
|
|
@@ -3955,6 +3959,12 @@ function inputInit()
|
|
|
3955
3959
|
function onMouseWheel(e) { mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY); }
|
|
3956
3960
|
function onContextMenu(e) { e.preventDefault(); } // prevent right click menu
|
|
3957
3961
|
function onBlur() { inputClear(); } // reset input when focus is lost
|
|
3962
|
+
function onMouseLeave()
|
|
3963
|
+
{
|
|
3964
|
+
// set mouse position and delta when leaving canvas
|
|
3965
|
+
mousePosScreen = vec2(Infinity);
|
|
3966
|
+
mouseDeltaScreen = vec2(0);
|
|
3967
|
+
}
|
|
3958
3968
|
}
|
|
3959
3969
|
|
|
3960
3970
|
// convert a mouse or touch event position to screen space
|
|
@@ -5076,7 +5086,7 @@ class TileLayerData
|
|
|
5076
5086
|
/** @property {boolean} - If the tile should be mirrored along the x axis */
|
|
5077
5087
|
this.mirror = mirror;
|
|
5078
5088
|
/** @property {Color} - Color of the tile */
|
|
5079
|
-
this.color = color;
|
|
5089
|
+
this.color = color.copy();
|
|
5080
5090
|
}
|
|
5081
5091
|
|
|
5082
5092
|
/** Set this tile to clear, it will not be rendered */
|
|
@@ -5175,7 +5185,7 @@ class CanvasLayer extends EngineObject
|
|
|
5175
5185
|
* @param {TileInfo} [tileInfo]
|
|
5176
5186
|
* @param {Color} [color=(1,1,1,1)]
|
|
5177
5187
|
* @param {number} [angle=0]
|
|
5178
|
-
* @param {boolean} [mirror=
|
|
5188
|
+
* @param {boolean} [mirror=false] */
|
|
5179
5189
|
drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
|
|
5180
5190
|
{
|
|
5181
5191
|
this.drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
@@ -6773,7 +6783,7 @@ function glPolyStrip(points)
|
|
|
6773
6783
|
while (indices.length > 3 && attempts++ < maxAttempts)
|
|
6774
6784
|
{
|
|
6775
6785
|
let foundEar = false;
|
|
6776
|
-
for (let i = indices.length;
|
|
6786
|
+
for (let i = 0; i < indices.length; i++)
|
|
6777
6787
|
{
|
|
6778
6788
|
const i0 = indices[(i + indices.length - 1) % indices.length];
|
|
6779
6789
|
const i1 = indices[i];
|
|
@@ -6810,7 +6820,7 @@ function glPolyStrip(points)
|
|
|
6810
6820
|
if (!foundEar)
|
|
6811
6821
|
{
|
|
6812
6822
|
let worstIndex = -1, worstValue = Infinity;
|
|
6813
|
-
for (let i = indices.length;
|
|
6823
|
+
for (let i = 0; i < indices.length; i++)
|
|
6814
6824
|
{
|
|
6815
6825
|
const i0 = indices[(i + indices.length - 1) % indices.length];
|
|
6816
6826
|
const i1 = indices[i];
|
|
@@ -7373,6 +7383,10 @@ class UISystemPlugin
|
|
|
7373
7383
|
this.uiObjects = [];
|
|
7374
7384
|
/** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
|
|
7375
7385
|
this.uiContext = context;
|
|
7386
|
+
/** @property {UIObject} - Top most object user is over */
|
|
7387
|
+
this.hoverObject = undefined;
|
|
7388
|
+
/** @property {UIObject} - Object user is currently interacting with */
|
|
7389
|
+
this.activeObject = undefined;
|
|
7376
7390
|
|
|
7377
7391
|
engineAddPlugin(uiUpdate, uiRender);
|
|
7378
7392
|
|
|
@@ -7402,6 +7416,8 @@ class UISystemPlugin
|
|
|
7402
7416
|
else
|
|
7403
7417
|
updateInvisibleObject(o);
|
|
7404
7418
|
}
|
|
7419
|
+
// reset hover object at start of update
|
|
7420
|
+
uiSystem.hoverObject = undefined;
|
|
7405
7421
|
for (let i = uiSystem.uiObjects.length; i--;)
|
|
7406
7422
|
{
|
|
7407
7423
|
const o = uiSystem.uiObjects[i];
|
|
@@ -7513,6 +7529,8 @@ class UIObject
|
|
|
7513
7529
|
this.size = size.copy();
|
|
7514
7530
|
/** @property {Color} - Color of the object */
|
|
7515
7531
|
this.color = uiSystem.defaultColor;
|
|
7532
|
+
/** @property {Color} - Color of the object when active, uses color if undefined */
|
|
7533
|
+
this.activeColor = undefined;
|
|
7516
7534
|
/** @property {string} - Text for this ui object */
|
|
7517
7535
|
this.text = undefined;
|
|
7518
7536
|
/** @property {Color} - Color when disabled */
|
|
@@ -7543,7 +7561,7 @@ class UIObject
|
|
|
7543
7561
|
this.children = [];
|
|
7544
7562
|
/** @property {UIObject} - This object's parent, position is in parent space */
|
|
7545
7563
|
this.parent = undefined;
|
|
7546
|
-
/** @property {number} -
|
|
7564
|
+
/** @property {number} - Added size to make small buttons easier to touch on mobile devices */
|
|
7547
7565
|
this.extraTouchSize = 0;
|
|
7548
7566
|
/** @property {Sound} - Sound when interactive element is pressed */
|
|
7549
7567
|
this.soundPress = uiSystem.defaultSoundPress;
|
|
@@ -7551,12 +7569,10 @@ class UIObject
|
|
|
7551
7569
|
this.soundRelease = uiSystem.defaultSoundRelease;
|
|
7552
7570
|
/** @property {Sound} - Sound when interactive element is clicked */
|
|
7553
7571
|
this.soundClick = uiSystem.defaultSoundClick;
|
|
7554
|
-
/** @property {boolean} - Is the mouse over this element */
|
|
7555
|
-
this.mouseIsOver = false;
|
|
7556
7572
|
/** @property {boolean} - Is this element interactive */
|
|
7557
7573
|
this.interactive = false;
|
|
7558
|
-
/** @property {boolean} -
|
|
7559
|
-
this.
|
|
7574
|
+
/** @property {boolean} - Activate when dragged over with mouse held down */
|
|
7575
|
+
this.dragActivate = false;
|
|
7560
7576
|
uiSystem.uiObjects.push(this);
|
|
7561
7577
|
}
|
|
7562
7578
|
|
|
@@ -7583,15 +7599,18 @@ class UIObject
|
|
|
7583
7599
|
/** Update the object, called automatically by plugin once each frame */
|
|
7584
7600
|
update()
|
|
7585
7601
|
{
|
|
7586
|
-
const
|
|
7587
|
-
const
|
|
7602
|
+
const wasHover = this.isHoverObject();
|
|
7603
|
+
const isActive = this.isActiveObject();
|
|
7588
7604
|
const mouseDown = mouseIsDown(0);
|
|
7589
|
-
|
|
7605
|
+
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
7606
|
+
if (!uiSystem.hoverObject)
|
|
7607
|
+
if (mousePress || !mouseDown || isActive)
|
|
7590
7608
|
{
|
|
7591
7609
|
const size = this.size.add(vec2(isTouchDevice && this.extraTouchSize || 0));
|
|
7592
|
-
|
|
7610
|
+
if (isOverlapping(this.pos, size, mousePosScreen))
|
|
7611
|
+
uiSystem.hoverObject = this;
|
|
7593
7612
|
}
|
|
7594
|
-
if (this.
|
|
7613
|
+
if (this.isHoverObject())
|
|
7595
7614
|
{
|
|
7596
7615
|
if (mousePress)
|
|
7597
7616
|
inputClearKey(0,0,0,1,0); // clear mouse was pressed state
|
|
@@ -7604,10 +7623,12 @@ class UIObject
|
|
|
7604
7623
|
this.onPress();
|
|
7605
7624
|
if (this.soundPress)
|
|
7606
7625
|
this.soundPress.play();
|
|
7626
|
+
if (uiSystem.activeObject && !isActive)
|
|
7627
|
+
uiSystem.activeObject.onRelease();
|
|
7628
|
+
uiSystem.activeObject = this;
|
|
7607
7629
|
}
|
|
7608
|
-
this.mouseIsHeld = true;
|
|
7609
7630
|
}
|
|
7610
|
-
if (!mouseDown &&
|
|
7631
|
+
if (!mouseDown && uiSystem.activeObject === this && this.interactive)
|
|
7611
7632
|
{
|
|
7612
7633
|
this.onClick();
|
|
7613
7634
|
if (this.soundClick)
|
|
@@ -7615,35 +7636,35 @@ class UIObject
|
|
|
7615
7636
|
}
|
|
7616
7637
|
}
|
|
7617
7638
|
}
|
|
7618
|
-
if (
|
|
7639
|
+
if (isActive)
|
|
7640
|
+
if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
|
|
7619
7641
|
{
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
this.
|
|
7623
|
-
|
|
7624
|
-
this.soundRelease.play();
|
|
7625
|
-
}
|
|
7626
|
-
if (isTouchDevice)
|
|
7627
|
-
this.mouseIsOver = false;
|
|
7628
|
-
this.mouseIsHeld = false;
|
|
7642
|
+
this.onRelease();
|
|
7643
|
+
if (this.soundRelease)
|
|
7644
|
+
this.soundRelease.play();
|
|
7645
|
+
uiSystem.activeObject = undefined;
|
|
7629
7646
|
}
|
|
7630
7647
|
|
|
7631
|
-
if (this.
|
|
7632
|
-
this.
|
|
7648
|
+
if (this.isHoverObject() !== wasHover)
|
|
7649
|
+
this.isHoverObject() ? this.onEnter() : this.onLeave();
|
|
7633
7650
|
}
|
|
7634
7651
|
|
|
7635
7652
|
/** Render the object, called automatically by plugin once each frame */
|
|
7636
7653
|
render()
|
|
7637
7654
|
{
|
|
7638
|
-
if (this.size.x
|
|
7639
|
-
|
|
7655
|
+
if (!this.size.x || !this.size.y) return;
|
|
7656
|
+
|
|
7657
|
+
const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
|
|
7658
|
+
const color = this.interactive ? this.disabled ? this.disabledColor : this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
|
|
7659
|
+
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
7640
7660
|
}
|
|
7641
7661
|
|
|
7642
7662
|
/** Special update when object is not visible */
|
|
7643
7663
|
updateInvisible()
|
|
7644
7664
|
{
|
|
7645
7665
|
// reset input state when not visible
|
|
7646
|
-
|
|
7666
|
+
if (this.isActiveObject())
|
|
7667
|
+
uiSystem.activeObject = undefined;
|
|
7647
7668
|
}
|
|
7648
7669
|
|
|
7649
7670
|
/** Get the size for text with overrides and scale
|
|
@@ -7656,6 +7677,12 @@ class UIObject
|
|
|
7656
7677
|
this.textHeight || this.textScale * this.size.y);
|
|
7657
7678
|
}
|
|
7658
7679
|
|
|
7680
|
+
/** @return {boolean} - Is the mouse hovering over this element */
|
|
7681
|
+
isHoverObject() { return uiSystem.hoverObject === this; }
|
|
7682
|
+
|
|
7683
|
+
/** @return {boolean} - Is the mouse held onto this element */
|
|
7684
|
+
isActiveObject() { return uiSystem.activeObject === this; }
|
|
7685
|
+
|
|
7659
7686
|
/** Called when the mouse enters the object */
|
|
7660
7687
|
onEnter() {}
|
|
7661
7688
|
|
|
@@ -7766,10 +7793,7 @@ class UIButton extends UIObject
|
|
|
7766
7793
|
}
|
|
7767
7794
|
render()
|
|
7768
7795
|
{
|
|
7769
|
-
|
|
7770
|
-
const lineColor = this.mouseIsHeld && !this.disabled ? this.color : this.lineColor;
|
|
7771
|
-
const color = this.disabled ? this.disabledColor : this.mouseIsOver ? this.hoverColor : this.color;
|
|
7772
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
7796
|
+
super.render();
|
|
7773
7797
|
|
|
7774
7798
|
// draw the text scaled to fit
|
|
7775
7799
|
const textSize = this.getTextSize();
|
|
@@ -7810,8 +7834,7 @@ class UICheckbox extends UIObject
|
|
|
7810
7834
|
}
|
|
7811
7835
|
render()
|
|
7812
7836
|
{
|
|
7813
|
-
|
|
7814
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
7837
|
+
super.render();
|
|
7815
7838
|
if (this.checked)
|
|
7816
7839
|
{
|
|
7817
7840
|
const p = this.cornerRadius / min(this.size.x, this.size.y) * 2;
|
|
@@ -7861,7 +7884,7 @@ class UIScrollbar extends UIObject
|
|
|
7861
7884
|
update()
|
|
7862
7885
|
{
|
|
7863
7886
|
super.update();
|
|
7864
|
-
if (this.
|
|
7887
|
+
if (this.isActiveObject() && this.interactive)
|
|
7865
7888
|
{
|
|
7866
7889
|
// check if value changed
|
|
7867
7890
|
const handleSize = vec2(this.size.y);
|
|
@@ -7875,12 +7898,7 @@ class UIScrollbar extends UIObject
|
|
|
7875
7898
|
}
|
|
7876
7899
|
render()
|
|
7877
7900
|
{
|
|
7878
|
-
|
|
7879
|
-
const lineColor = this.interactive && this.mouseIsHeld && !this.disabled ?
|
|
7880
|
-
this.color : this.lineColor;
|
|
7881
|
-
const color = this.disabled ? this.disabledColor :
|
|
7882
|
-
this.interactive && this.mouseIsHeld ? this.hoverColor : this.color;
|
|
7883
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
7901
|
+
super.render();
|
|
7884
7902
|
|
|
7885
7903
|
// draw the scrollbar handle
|
|
7886
7904
|
const handleSize = vec2(this.size.y);
|
|
@@ -7889,7 +7907,7 @@ class UIScrollbar extends UIObject
|
|
|
7889
7907
|
const p2 = this.pos.x + handleWidth/2;
|
|
7890
7908
|
const handlePos = vec2(lerp(p1, p2, this.value), this.pos.y);
|
|
7891
7909
|
const handleColor = this.disabled ? this.disabledColor :
|
|
7892
|
-
this.interactive && this.
|
|
7910
|
+
this.interactive && this.isActiveObject() ? this.color : this.handleColor;
|
|
7893
7911
|
uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
7894
7912
|
|
|
7895
7913
|
// draw the text scaled to fit on the scrollbar
|
package/examples/index.html
CHANGED
|
@@ -72,12 +72,12 @@ const exampleList =
|
|
|
72
72
|
[
|
|
73
73
|
new ExampleInfo('--- SHORT EXAMPLES ---'),
|
|
74
74
|
new ExampleInfo('Hello World', 'helloWorld.js', 'Minimal starter example'),
|
|
75
|
-
new ExampleInfo('
|
|
75
|
+
new ExampleInfo('Texture', 'texture.js', 'Texture display and manipulation'),
|
|
76
|
+
new ExampleInfo('Animation', 'animation.js', 'Sprite animation system'),
|
|
76
77
|
new ExampleInfo('Shapes', 'shapes.js', 'Draw geometric shapes and primitives'),
|
|
77
78
|
new ExampleInfo('Colors', 'colors.js', 'Color manipulation and HSL'),
|
|
78
|
-
new ExampleInfo('
|
|
79
|
+
new ExampleInfo('Starfield', 'starfield.js', 'Animated parallax starfield'),
|
|
79
80
|
new ExampleInfo('Sprite Atlas', 'spriteAtlas.js', 'Sprite atlas and tile rendering'),
|
|
80
|
-
new ExampleInfo('Animation', 'animation.js', 'Sprite animation system'),
|
|
81
81
|
new ExampleInfo('Blending', 'blending.js', 'Additive blending and transparency'),
|
|
82
82
|
new ExampleInfo('Tile Layer', 'tileLayer.js', 'Tile layer rendering system'),
|
|
83
83
|
new ExampleInfo('Particles', 'particles.js', 'Particle system'),
|
|
@@ -423,7 +423,7 @@ function setCode(code, filename)
|
|
|
423
423
|
{
|
|
424
424
|
// try to extract line number from stack trace
|
|
425
425
|
// look for <anonymous> or injectedScript to find user code
|
|
426
|
-
const anonymousMatch = stack
|
|
426
|
+
const anonymousMatch = stack?.match(/(<anonymous>|injectedScript):(\d+)/);
|
|
427
427
|
return anonymousMatch ? parseInt(anonymousMatch[2]) : -1;
|
|
428
428
|
}
|
|
429
429
|
iframeContent.onerror = (message, source, lineno, colno, error) =>
|
|
@@ -520,7 +520,12 @@ function setCode(code, filename)
|
|
|
520
520
|
const errorLine = getErrorLine(error.stack);
|
|
521
521
|
if (errorLine >= 0)
|
|
522
522
|
setErrorLine(errorLine);
|
|
523
|
-
|
|
523
|
+
let message = error;
|
|
524
|
+
if (error.message)
|
|
525
|
+
message = error.message;
|
|
526
|
+
if (error.stack)
|
|
527
|
+
message += '\n' + error.stack;
|
|
528
|
+
setErrorMessage(message);
|
|
524
529
|
throw error;
|
|
525
530
|
})
|
|
526
531
|
.then(()=>
|
|
@@ -36,7 +36,11 @@ export const persistentParticleDestroyCallback = (particle)=>
|
|
|
36
36
|
// copy particle to tile layer on death
|
|
37
37
|
LJS.ASSERT(!particle.tileInfo, 'quick draw to tile layer uses canvas 2d so must be untextured');
|
|
38
38
|
if (particle.groundObject)
|
|
39
|
+
{
|
|
39
40
|
GameLevel.foregroundTileLayer.drawTile(particle.pos, particle.size, particle.tileInfo, particle.color, particle.angle, particle.mirror);
|
|
41
|
+
// update WebGL texture
|
|
42
|
+
GameLevel.foregroundTileLayer.useWebGL();
|
|
43
|
+
}
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export function makeBlood(pos, amount) { makeDebris(pos, hsl(0,1,.5), amount, .1, 0); }
|
|
@@ -83,7 +87,7 @@ export function explosion(pos, radius=3)
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
// update WebGL texture
|
|
86
|
-
GameLevel.
|
|
90
|
+
GameLevel.foregroundTileLayer.useWebGL();
|
|
87
91
|
|
|
88
92
|
// kill/push objects
|
|
89
93
|
LJS.engineObjectsCallback(pos, radius*3, (o)=>
|
|
@@ -159,7 +163,7 @@ export function destroyTile(pos, makeSound = 1, cleanup = 1)
|
|
|
159
163
|
for (let i=-1;i<=1;++i)
|
|
160
164
|
for (let j=-1;j<=1;++j)
|
|
161
165
|
GameLevel.decorateTile(pos.add(vec2(i,j)));
|
|
162
|
-
|
|
166
|
+
layer.useWebGL();
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
return true;
|
|
@@ -14,7 +14,6 @@ import * as GameEffects from './gameEffects.js';
|
|
|
14
14
|
import * as Game from './game.js';
|
|
15
15
|
const {vec2, hsl, tile} = LJS;
|
|
16
16
|
|
|
17
|
-
export const useWebGLTileLayers = true;
|
|
18
17
|
export const tileType_ladder = -1;
|
|
19
18
|
export const tileType_empty = 0;
|
|
20
19
|
export const tileType_solid = 1;
|
|
@@ -138,7 +137,7 @@ function loadLevelData()
|
|
|
138
137
|
for (pos.x=levelSize.x; pos.x--;)
|
|
139
138
|
for (pos.y=levelSize.y; pos.y--;)
|
|
140
139
|
decorateTile(pos, layer);
|
|
141
|
-
|
|
140
|
+
tileLayers[layer].useWebGL();
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
|
|
@@ -204,9 +203,4 @@ export function getCameraTarget()
|
|
|
204
203
|
// camera is above player
|
|
205
204
|
const offset = 100/LJS.cameraScale*LJS.percent(LJS.mainCanvasSize.y, 300, 600);
|
|
206
205
|
return Game.player.pos.add(vec2(0, offset));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function updateWebGL(layer)
|
|
210
|
-
{
|
|
211
|
-
layer.useWebGL(useWebGLTileLayers);
|
|
212
206
|
}
|
|
@@ -38,7 +38,8 @@ class CarObject extends Box2dObject
|
|
|
38
38
|
|
|
39
39
|
// car controls - use mouse, arrow keys, or A/D to drive
|
|
40
40
|
const maxSpeed = 40;
|
|
41
|
-
const input =
|
|
41
|
+
const input = mouseIsDown(0) ? 1 :
|
|
42
|
+
mouseIsDown(2) ? -1 : keyDirection().x ;
|
|
42
43
|
let s = this.wheels[0].motorJoint.getMotorSpeed();
|
|
43
44
|
s = input ? clamp(s - input, -maxSpeed, maxSpeed) : 0;
|
|
44
45
|
this.wheels[0].motorJoint.setMotorSpeed(s);
|
package/examples/shorts/piano.js
CHANGED
|
@@ -1,51 +1,50 @@
|
|
|
1
|
-
const pianoSound = new Sound([,0,220,,9])
|
|
1
|
+
const pianoSound = new Sound([,0,220,,9]);
|
|
2
2
|
|
|
3
|
-
class PianoKey extends
|
|
3
|
+
class PianoKey extends UIButton
|
|
4
4
|
{
|
|
5
5
|
constructor(pos, size, semitone, isWhite)
|
|
6
6
|
{
|
|
7
|
-
const keySize =
|
|
7
|
+
const keySize = 65;
|
|
8
8
|
size = size.scale(keySize);
|
|
9
|
-
pos = pos.scale(keySize).add(vec2(0,
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
pos = pos.scale(keySize).add(vec2(0,size.y/2-keySize*2));
|
|
10
|
+
pos = pos.add(mainCanvasSize.scale(.5));
|
|
11
|
+
super(pos, size, '', hsl(0,0,isWhite ? 1 : .3));
|
|
12
12
|
this.semitone = semitone;
|
|
13
|
+
this.dragActivate = true;
|
|
14
|
+
this.hoverColor = hsl(0,1,isWhite ? .9 : .3);
|
|
15
|
+
this.activeColor = RED;
|
|
13
16
|
}
|
|
14
|
-
|
|
17
|
+
onPress()
|
|
15
18
|
{
|
|
16
19
|
if (!this.soundInstance)
|
|
17
20
|
this.soundInstance = pianoSound.playNote(this.semitone);
|
|
18
21
|
}
|
|
19
|
-
|
|
22
|
+
onRelease()
|
|
20
23
|
{
|
|
21
24
|
if (this.soundInstance)
|
|
22
25
|
this.soundInstance.stop(.2);
|
|
23
26
|
this.soundInstance = 0;
|
|
24
27
|
}
|
|
25
|
-
render()
|
|
26
|
-
{
|
|
27
|
-
const color = this.soundInstance ? RED : this.color;
|
|
28
|
-
drawRect(this.pos, this.drawSize, color);
|
|
29
|
-
}
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
function gameInit()
|
|
33
31
|
{
|
|
32
|
+
// initialize UI system
|
|
33
|
+
new UISystemPlugin;
|
|
34
|
+
|
|
34
35
|
// create piano keyboard
|
|
35
36
|
for (let i=15; i--;)
|
|
36
|
-
|
|
37
|
+
{
|
|
38
|
+
const pos = vec2(i-7,0);
|
|
39
|
+
const size = vec2(1,4);
|
|
40
|
+
const semitone = [0,2,4,5,7,9,11][i%7]+(i/7|0)*12;
|
|
41
|
+
new PianoKey(pos, size, semitone, true);
|
|
42
|
+
}
|
|
37
43
|
for (let i=10; i--;)
|
|
38
|
-
keys.unshift(new PianoKey(vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5,0), vec2(1,2), [1,3,6,8,10][i%5]+(i/5|0)*12));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function gameUpdate()
|
|
42
|
-
{
|
|
43
|
-
// update state of piano keys
|
|
44
|
-
const pressedKey = keys.find(k=>k.soundInstance);
|
|
45
|
-
const newPressedKey = mouseIsDown(0) && keys.find(k=>isOverlapping(k.pos, k.size, mousePos));
|
|
46
|
-
if (newPressedKey != pressedKey)
|
|
47
44
|
{
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const pos = vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5,0)
|
|
46
|
+
const size = vec2(1,2);
|
|
47
|
+
const semitone = [1,3,6,8,10][i%5]+(i/5|0)*12;
|
|
48
|
+
new PianoKey(pos, size, semitone);
|
|
50
49
|
}
|
|
51
50
|
}
|
package/examples/shorts/sound.js
CHANGED
|
@@ -1,38 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
function gameInit()
|
|
2
2
|
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.icon = icon;
|
|
7
|
-
this.sound = sound;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
update()
|
|
11
|
-
{
|
|
12
|
-
// play sound when clicked
|
|
13
|
-
if (mouseWasPressed(0) && isOverlapping(this.pos, this.size, mousePos))
|
|
14
|
-
this.sound.play(this.pos);
|
|
15
|
-
}
|
|
3
|
+
// initialize UI system
|
|
4
|
+
new UISystemPlugin;
|
|
5
|
+
canvasClearColor = hsl(.6,.3,.2);
|
|
16
6
|
|
|
17
|
-
|
|
7
|
+
// create a grid of buttons with different sounds
|
|
8
|
+
const w = 200, h = 150, gap = 20;
|
|
9
|
+
function makeSoundButton(pos, icon, sound)
|
|
18
10
|
{
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
pos = pos.multiply(vec2(w+gap, h+gap));
|
|
12
|
+
pos = pos.add(mainCanvasSize.scale(.5));
|
|
13
|
+
const button = new UIButton(pos, vec2(w, h), icon);
|
|
14
|
+
button.textHeight = 100;
|
|
15
|
+
button.onClick = ()=> sound.play();
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
new SoundButton(vec2( 0, 0),'🎹', new Sound([1.5,.5,270,,.1,,1,1.5,,,,,,,,.1,.01]));
|
|
33
|
-
new SoundButton(vec2( 6, 0),'🏌️', new Sound([,,150,.05,,.05,,1.3,,,,,,3]));
|
|
34
|
-
new SoundButton(vec2(-6,-5),'🌊', new Sound([,.2,40,.5,,1.5,,11,,,,,,199]));
|
|
35
|
-
new SoundButton(vec2( 0,-5),'🛰️', new Sound([,.5,847,.02,.3,.9,1,1.67,,,-294,.04,.13,,,,.1]));
|
|
36
|
-
new SoundButton(vec2( 6,-5),'⚡', new Sound([,,471,,.09,.47,4,1.06,-6.7,,,,,.9,61,.1,,.82,.1]));
|
|
37
|
-
canvasClearColor = hsl(.6,.3,.2); // background color
|
|
17
|
+
makeSoundButton(vec2(-1, 1),'💰', new Sound([,,1675,,.06,.24,1,1.82,,,837,.06]));
|
|
18
|
+
makeSoundButton(vec2( 0, 1),'🥊', new Sound([,,925,.04,.3,.6,1,.3,,6.27,-184,.09,.17]));
|
|
19
|
+
makeSoundButton(vec2( 1, 1),'✨', new Sound([,,539,0,.04,.29,1,1.92,,,567,.02,.02,,,,.04]));
|
|
20
|
+
makeSoundButton(vec2(-1, 0),'🐁', new Sound([,.2,1e3,.02,,.01,2,,18,,475,.01,.01]));
|
|
21
|
+
makeSoundButton(vec2( 0, 0),'🎹', new Sound([1.5,.5,270,,.1,,1,1.5,,,,,,,,.1,.01]));
|
|
22
|
+
makeSoundButton(vec2( 1, 0),'🏌️', new Sound([,,150,.05,,.05,,1.3,,,,,,3]));
|
|
23
|
+
makeSoundButton(vec2(-1,-1),'🌊', new Sound([,.2,40,.5,,1.5,,11,,,,,,199]));
|
|
24
|
+
makeSoundButton(vec2( 0,-1),'🛰️', new Sound([,.5,847,.02,.3,.9,1,1.67,,,-294,.04,.13,,,,.1]));
|
|
25
|
+
makeSoundButton(vec2( 1,-1),'⚡', new Sound([,,471,,.09,.47,4,1.06,-6.7,,,,,.9,61,.1,,.82,.1]));
|
|
38
26
|
}
|
|
@@ -10,22 +10,29 @@ function gameInit()
|
|
|
10
10
|
uiSystem.defaultSoundClick = new Sound([1,0,440]);
|
|
11
11
|
uiSystem.defaultCornerRadius = 8;
|
|
12
12
|
|
|
13
|
+
// example button that returns to menu
|
|
14
|
+
const buttonBack = new UIButton(mainCanvasSize.scale(.5), vec2(200), 'Back\nto\nMenu');
|
|
15
|
+
buttonBack.textHeight = 60;
|
|
16
|
+
buttonBack.onClick = ()=> uiMenu.visible = true;
|
|
17
|
+
|
|
13
18
|
// setup example menu
|
|
14
|
-
const uiMenu = new UIObject(mainCanvasSize.scale(.5), vec2(450));
|
|
19
|
+
const uiMenu = new UIObject(mainCanvasSize.scale(.5), vec2(600,450));
|
|
15
20
|
canvasClearColor = hsl(0,0,.8);
|
|
16
21
|
|
|
17
22
|
// example text
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
uiMenu.addChild(new UIText(vec2(-80,-120), vec2(500, 80), 'LittleJS UI\nSystem Demo'));
|
|
24
|
+
|
|
25
|
+
// example image
|
|
26
|
+
uiMenu.addChild(new UITile(vec2(200,-140), vec2(128), tile(3, 128)));
|
|
20
27
|
|
|
21
28
|
// example button
|
|
22
|
-
const button1 = new UIButton(vec2(
|
|
29
|
+
const button1 = new UIButton(vec2(80,0), vec2(140, 80), 'Test');
|
|
23
30
|
button1.textHeight = 60;
|
|
24
31
|
uiMenu.addChild(button1);
|
|
25
|
-
button1.onClick = ()=>
|
|
32
|
+
button1.onClick = ()=> canvasClearColor = randColor();
|
|
26
33
|
|
|
27
34
|
// example checkbox
|
|
28
|
-
const checkbox = new UICheckbox(vec2(-
|
|
35
|
+
const checkbox = new UICheckbox(vec2(-80,0), vec2(50));
|
|
29
36
|
checkbox.onChange = ()=> button1.disabled = checkbox.checked;
|
|
30
37
|
uiMenu.addChild(checkbox);
|
|
31
38
|
|