littlejsengine 1.14.7 → 1.14.8
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 +71 -54
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +71 -54
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +71 -54
- package/examples/index.html +10 -5
- 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 +48 -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.8';
|
|
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,34 @@ class UIObject
|
|
|
7615
7636
|
}
|
|
7616
7637
|
}
|
|
7617
7638
|
}
|
|
7618
|
-
if (!mouseDown)
|
|
7639
|
+
if (isActive && (!mouseDown || !this.isHoverObject()))
|
|
7619
7640
|
{
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
this.
|
|
7623
|
-
|
|
7624
|
-
this.soundRelease.play();
|
|
7625
|
-
}
|
|
7626
|
-
if (isTouchDevice)
|
|
7627
|
-
this.mouseIsOver = false;
|
|
7628
|
-
this.mouseIsHeld = false;
|
|
7641
|
+
this.onRelease();
|
|
7642
|
+
if (this.soundRelease)
|
|
7643
|
+
this.soundRelease.play();
|
|
7644
|
+
uiSystem.activeObject = undefined;
|
|
7629
7645
|
}
|
|
7630
7646
|
|
|
7631
|
-
if (this.
|
|
7632
|
-
this.
|
|
7647
|
+
if (this.isHoverObject() !== wasHover)
|
|
7648
|
+
this.isHoverObject() ? this.onEnter() : this.onLeave();
|
|
7633
7649
|
}
|
|
7634
7650
|
|
|
7635
7651
|
/** Render the object, called automatically by plugin once each frame */
|
|
7636
7652
|
render()
|
|
7637
7653
|
{
|
|
7638
|
-
if (this.size.x
|
|
7639
|
-
|
|
7654
|
+
if (!this.size.x || !this.size.y) return;
|
|
7655
|
+
|
|
7656
|
+
const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
|
|
7657
|
+
const color = this.interactive ? this.disabled ? this.disabledColor : this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
|
|
7658
|
+
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
7640
7659
|
}
|
|
7641
7660
|
|
|
7642
7661
|
/** Special update when object is not visible */
|
|
7643
7662
|
updateInvisible()
|
|
7644
7663
|
{
|
|
7645
7664
|
// reset input state when not visible
|
|
7646
|
-
|
|
7665
|
+
if (this.isActiveObject())
|
|
7666
|
+
uiSystem.activeObject = undefined;
|
|
7647
7667
|
}
|
|
7648
7668
|
|
|
7649
7669
|
/** Get the size for text with overrides and scale
|
|
@@ -7656,6 +7676,12 @@ class UIObject
|
|
|
7656
7676
|
this.textHeight || this.textScale * this.size.y);
|
|
7657
7677
|
}
|
|
7658
7678
|
|
|
7679
|
+
/** @return {boolean} - Is the mouse hovering over this element */
|
|
7680
|
+
isHoverObject() { return uiSystem.hoverObject === this; }
|
|
7681
|
+
|
|
7682
|
+
/** @return {boolean} - Is the mouse held onto this element */
|
|
7683
|
+
isActiveObject() { return uiSystem.activeObject === this; }
|
|
7684
|
+
|
|
7659
7685
|
/** Called when the mouse enters the object */
|
|
7660
7686
|
onEnter() {}
|
|
7661
7687
|
|
|
@@ -7766,10 +7792,7 @@ class UIButton extends UIObject
|
|
|
7766
7792
|
}
|
|
7767
7793
|
render()
|
|
7768
7794
|
{
|
|
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);
|
|
7795
|
+
super.render();
|
|
7773
7796
|
|
|
7774
7797
|
// draw the text scaled to fit
|
|
7775
7798
|
const textSize = this.getTextSize();
|
|
@@ -7810,8 +7833,7 @@ class UICheckbox extends UIObject
|
|
|
7810
7833
|
}
|
|
7811
7834
|
render()
|
|
7812
7835
|
{
|
|
7813
|
-
|
|
7814
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
7836
|
+
super.render();
|
|
7815
7837
|
if (this.checked)
|
|
7816
7838
|
{
|
|
7817
7839
|
const p = this.cornerRadius / min(this.size.x, this.size.y) * 2;
|
|
@@ -7861,7 +7883,7 @@ class UIScrollbar extends UIObject
|
|
|
7861
7883
|
update()
|
|
7862
7884
|
{
|
|
7863
7885
|
super.update();
|
|
7864
|
-
if (this.
|
|
7886
|
+
if (this.isActiveObject() && this.interactive)
|
|
7865
7887
|
{
|
|
7866
7888
|
// check if value changed
|
|
7867
7889
|
const handleSize = vec2(this.size.y);
|
|
@@ -7875,12 +7897,7 @@ class UIScrollbar extends UIObject
|
|
|
7875
7897
|
}
|
|
7876
7898
|
render()
|
|
7877
7899
|
{
|
|
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);
|
|
7900
|
+
super.render();
|
|
7884
7901
|
|
|
7885
7902
|
// draw the scrollbar handle
|
|
7886
7903
|
const handleSize = vec2(this.size.y);
|
|
@@ -7889,7 +7906,7 @@ class UIScrollbar extends UIObject
|
|
|
7889
7906
|
const p2 = this.pos.x + handleWidth/2;
|
|
7890
7907
|
const handlePos = vec2(lerp(p1, p2, this.value), this.pos.y);
|
|
7891
7908
|
const handleColor = this.disabled ? this.disabledColor :
|
|
7892
|
-
this.interactive && this.
|
|
7909
|
+
this.interactive && this.isActiveObject() ? this.color : this.handleColor;
|
|
7893
7910
|
uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
7894
7911
|
|
|
7895
7912
|
// 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(()=>
|
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
|
|