littlejsengine 1.15.2 → 1.15.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 +190 -63
- package/dist/littlejs.esm.js +1267 -605
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1261 -604
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1179 -552
- package/examples/electron/index.html +2 -2
- package/examples/index.html +4 -3
- package/examples/particles/index.html +22 -6
- package/examples/shorts/base.html +2 -1
- package/examples/shorts/box2dCar.js +1 -1
- package/examples/shorts/box2dPool.js +9 -10
- package/examples/shorts/empty.js +1 -1
- package/examples/shorts/input.js +30 -25
- package/examples/shorts/music.js +1 -0
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/sequencer.js +2 -0
- package/examples/shorts/sound.js +1 -0
- package/examples/shorts/tileLayer.js +2 -2
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/timers.js +1 -0
- package/examples/shorts/uiSystem.js +26 -14
- package/examples/shorts/videoPlayer.js +2 -1
- package/examples/starter/index.html +3 -2
- package/examples/uiSystem/game.js +28 -15
- package/package.json +1 -1
- package/plugins/box2d.js +1 -1
- package/plugins/desktop.ini +2 -0
- package/plugins/pluginExport.js +2 -0
- package/plugins/uiSystem.js +503 -91
- package/src/engine.js +2 -169
- package/src/engineAudio.js +0 -1
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +84 -54
- package/src/engineDraw.js +81 -40
- package/src/engineExport.js +4 -1
- package/src/engineInput.js +526 -381
- package/src/engineObject.js +27 -23
- package/src/engineSettings.js +11 -6
- package/src/engineSplash.js +173 -0
- package/src/engineTileLayer.js +3 -3
- package/src/engineUtilities.js +17 -1
package/src/engineObject.js
CHANGED
|
@@ -134,7 +134,7 @@ class EngineObject
|
|
|
134
134
|
child.updateTransforms();
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
/** Update the object physics, called automatically by engine once each frame */
|
|
137
|
+
/** Update the object physics, called automatically by engine once each frame. Can be overridden to stop or change how physics works for an object. */
|
|
138
138
|
updatePhysics()
|
|
139
139
|
{
|
|
140
140
|
// child objects do not have physics
|
|
@@ -167,7 +167,7 @@ class EngineObject
|
|
|
167
167
|
if (!enablePhysicsSolver || !this.mass) // don't do collision for static objects
|
|
168
168
|
return;
|
|
169
169
|
|
|
170
|
-
const
|
|
170
|
+
const wasFalling = this.velocity.y < 0 && gravity.y < 0 || this.velocity.y > 0 && gravity.y > 0;
|
|
171
171
|
if (this.groundObject)
|
|
172
172
|
{
|
|
173
173
|
// apply friction in local space of ground object
|
|
@@ -223,10 +223,10 @@ class EngineObject
|
|
|
223
223
|
{
|
|
224
224
|
// push outside object collision
|
|
225
225
|
this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
|
|
226
|
-
if ((o.groundObject &&
|
|
226
|
+
if ((o.groundObject && wasFalling) || !o.mass)
|
|
227
227
|
{
|
|
228
228
|
// set ground object if landed on something
|
|
229
|
-
if (
|
|
229
|
+
if (wasFalling)
|
|
230
230
|
this.groundObject = o;
|
|
231
231
|
|
|
232
232
|
// bounce if other object is fixed or grounded
|
|
@@ -313,12 +313,15 @@ class EngineObject
|
|
|
313
313
|
const restitution = max(this.restitution, hitLayer.restitution);
|
|
314
314
|
this.velocity.y *= -restitution;
|
|
315
315
|
|
|
316
|
-
if (
|
|
316
|
+
if (wasFalling)
|
|
317
317
|
{
|
|
318
|
-
// adjust position to slightly
|
|
318
|
+
// adjust position to slightly away from nearest tile
|
|
319
319
|
// this prevents gap between object and ground
|
|
320
320
|
const epsilon = .0001;
|
|
321
|
-
|
|
321
|
+
const offset = this.size.y/2 + epsilon;
|
|
322
|
+
this.pos.y = gravity.y < 0 ?
|
|
323
|
+
floor(oldPos.y-this.size.y/2) + offset :
|
|
324
|
+
ceil( oldPos.y+this.size.y/2) - offset;
|
|
322
325
|
|
|
323
326
|
// set ground object for tile collision
|
|
324
327
|
this.groundObject = hitLayer;
|
|
@@ -448,7 +451,9 @@ class EngineObject
|
|
|
448
451
|
{
|
|
449
452
|
ASSERT(child.parent === this && this.children.includes(child));
|
|
450
453
|
ASSERT(child instanceof EngineObject, 'child must be an EngineObject');
|
|
451
|
-
this.children.
|
|
454
|
+
const index = this.children.indexOf(child);
|
|
455
|
+
ASSERT(index >= 0, 'child not found in children array');
|
|
456
|
+
index >= 0 && this.children.splice(index, 1);
|
|
452
457
|
child.parent = 0;
|
|
453
458
|
}
|
|
454
459
|
|
|
@@ -485,21 +490,20 @@ class EngineObject
|
|
|
485
490
|
* @return {string} */
|
|
486
491
|
toString()
|
|
487
492
|
{
|
|
488
|
-
if (debug)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
493
|
+
if (!debug) return;
|
|
494
|
+
|
|
495
|
+
let text = 'type = ' + this.constructor.name;
|
|
496
|
+
if (this.pos.x || this.pos.y)
|
|
497
|
+
text += '\npos = ' + this.pos;
|
|
498
|
+
if (this.velocity.x || this.velocity.y)
|
|
499
|
+
text += '\nvelocity = ' + this.velocity;
|
|
500
|
+
if (this.size.x || this.size.y)
|
|
501
|
+
text += '\nsize = ' + this.size;
|
|
502
|
+
if (this.angle)
|
|
503
|
+
text += '\nangle = ' + this.angle.toFixed(3);
|
|
504
|
+
if (this.color)
|
|
505
|
+
text += '\ncolor = ' + this.color;
|
|
506
|
+
return text;
|
|
503
507
|
}
|
|
504
508
|
|
|
505
509
|
/** Render debug info for this object */
|
package/src/engineSettings.js
CHANGED
|
@@ -224,17 +224,17 @@ let touchGamepadEnable = false;
|
|
|
224
224
|
* @memberof Settings */
|
|
225
225
|
let touchGamepadCenterButton = true;
|
|
226
226
|
|
|
227
|
-
/**
|
|
228
|
-
* @type {
|
|
227
|
+
/** Number of buttons on touch gamepad (0-4), if 1 also acts as right analog stick
|
|
228
|
+
* @type {number}
|
|
229
229
|
* @default
|
|
230
230
|
* @memberof Settings */
|
|
231
|
-
let
|
|
231
|
+
let touchGamepadButtonCount = 4;
|
|
232
232
|
|
|
233
|
-
/**
|
|
234
|
-
* @type {
|
|
233
|
+
/** True if touch gamepad should be analog stick or false to use if 8 way dpad
|
|
234
|
+
* @type {boolean}
|
|
235
235
|
* @default
|
|
236
236
|
* @memberof Settings */
|
|
237
|
-
let
|
|
237
|
+
let touchGamepadAnalog = true;
|
|
238
238
|
|
|
239
239
|
/** Size of virtual gamepad for touch devices in pixels
|
|
240
240
|
* @type {number}
|
|
@@ -500,6 +500,11 @@ function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
|
|
|
500
500
|
* @memberof Settings */
|
|
501
501
|
function setTouchGamepadCenterButton(enable) { touchGamepadCenterButton = enable; }
|
|
502
502
|
|
|
503
|
+
/** Set number of buttons on touch gamepad (0-4), if 1 also acts as right analog stick
|
|
504
|
+
* @param {number} count
|
|
505
|
+
* @memberof Settings */
|
|
506
|
+
function setTouchGamepadButtonCount(count) { touchGamepadButtonCount = count; }
|
|
507
|
+
|
|
503
508
|
/** Set if touch gamepad should be analog stick or 8 way dpad
|
|
504
509
|
* @param {boolean} analog
|
|
505
510
|
* @memberof Settings */
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LittleJS Engine Splash Screen
|
|
3
|
+
* @namespace Settings
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
9
|
+
// LittleJS splash screen and logo
|
|
10
|
+
|
|
11
|
+
function drawEngineSplashScreen(t)
|
|
12
|
+
{
|
|
13
|
+
const x = overlayContext;
|
|
14
|
+
const w = overlayCanvas.width = innerWidth;
|
|
15
|
+
const h = overlayCanvas.height = innerHeight;
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
// background
|
|
19
|
+
const p3 = percent(t, 1, .8);
|
|
20
|
+
const p4 = percent(t, 0, .5);
|
|
21
|
+
const g = x.createRadialGradient(w/2,h/2,0,w/2,h/2,hypot(w,h)*.7);
|
|
22
|
+
g.addColorStop(0,hsl(0,0,lerp(0,p3/2,p4),p3).toString());
|
|
23
|
+
g.addColorStop(1,hsl(0,0,0,p3).toString());
|
|
24
|
+
x.save();
|
|
25
|
+
x.fillStyle = g;
|
|
26
|
+
x.fillRect(0,0,w,h);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// draw LittleJS logo...
|
|
30
|
+
const rect = (X, Y, W, H, C)=>
|
|
31
|
+
{
|
|
32
|
+
x.beginPath();
|
|
33
|
+
x.rect(X,Y,W,C?H*p:H);
|
|
34
|
+
x.fillStyle = C;
|
|
35
|
+
C ? x.fill() : x.stroke();
|
|
36
|
+
};
|
|
37
|
+
const line = (X, Y, Z, W)=>
|
|
38
|
+
{
|
|
39
|
+
x.beginPath();
|
|
40
|
+
x.lineTo(X,Y);
|
|
41
|
+
x.lineTo(Z,W);
|
|
42
|
+
x.stroke();
|
|
43
|
+
};
|
|
44
|
+
const circle = (X, Y, R, A=0, B=2*PI, C, F)=>
|
|
45
|
+
{
|
|
46
|
+
const D = (A+B)/2, E = p*(B-A)/2;
|
|
47
|
+
x.beginPath();
|
|
48
|
+
F && x.lineTo(X,Y);
|
|
49
|
+
x.arc(X,Y,R,D-E,D+E);
|
|
50
|
+
x.fillStyle = C;
|
|
51
|
+
C ? x.fill() : x.stroke();
|
|
52
|
+
};
|
|
53
|
+
const color = (c=0, l=0) =>
|
|
54
|
+
hsl([.98,.3,.57,.14][c%4],.8,[0,.3,.5,.8,.9][l]).toString();
|
|
55
|
+
const alpha = wave(1,1,t);
|
|
56
|
+
const p = percent(alpha, .1, .5);
|
|
57
|
+
|
|
58
|
+
// setup
|
|
59
|
+
x.translate(w/2,h/2);
|
|
60
|
+
const size = min(6, min(w,h)/99); // fit to screen
|
|
61
|
+
x.scale(size,size);
|
|
62
|
+
x.translate(-40,-35);
|
|
63
|
+
x.lineJoin = x.lineCap = 'round';
|
|
64
|
+
x.lineWidth = .1 + p*1.9;
|
|
65
|
+
|
|
66
|
+
// drawing effect
|
|
67
|
+
const p2 = percent(alpha,.1,1);
|
|
68
|
+
x.setLineDash([99*p2,99]);
|
|
69
|
+
|
|
70
|
+
// cab top
|
|
71
|
+
rect(7,16,18,-8,color(2,2));
|
|
72
|
+
rect(7,8,18,4,color(2,3));
|
|
73
|
+
rect(25,8,8,8,color(2,1));
|
|
74
|
+
rect(25,8,-18,8);
|
|
75
|
+
rect(25,8,8,8);
|
|
76
|
+
|
|
77
|
+
// cab
|
|
78
|
+
rect(25,16,7,23,color());
|
|
79
|
+
rect(11,39,14,-23,color(1,1));
|
|
80
|
+
rect(11,16,14,18,color(1,2));
|
|
81
|
+
rect(11,16,14,8,color(1,3));
|
|
82
|
+
rect(25,16,-14,24);
|
|
83
|
+
|
|
84
|
+
// cab window
|
|
85
|
+
rect(15,29,6,-9,color(2,2));
|
|
86
|
+
circle(15,21,5,0,PI/2,color(2,4),1);
|
|
87
|
+
rect(21,21,-6,9);
|
|
88
|
+
|
|
89
|
+
// little stack
|
|
90
|
+
rect(37,14,9,6,color(3,2));
|
|
91
|
+
rect(37,14,4.5,6,color(3,3));
|
|
92
|
+
rect(37,14,9,6);
|
|
93
|
+
|
|
94
|
+
// big stack
|
|
95
|
+
rect(50,20,10,-8,color(0,1));
|
|
96
|
+
rect(50,20,6.5,-8,color(0,2));
|
|
97
|
+
rect(50,20,3.5,-8,color(0,3));
|
|
98
|
+
rect(50,20,10,-8);
|
|
99
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3));
|
|
100
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1);
|
|
101
|
+
circle(55,2,11.4,.5,PI-.5);
|
|
102
|
+
rect(45,7,20,-7,color(0,2));
|
|
103
|
+
rect(45,-1,20,4,color(0,3));
|
|
104
|
+
rect(45,-1,20,8);
|
|
105
|
+
|
|
106
|
+
// engine
|
|
107
|
+
for (let i=5; i--;)
|
|
108
|
+
{
|
|
109
|
+
// stagger radius to fix slight seam
|
|
110
|
+
circle(60-i*6,30, 9.9,0,2*PI,color(i+2,3));
|
|
111
|
+
circle(60-i*6,30,10.0,-.5,PI+.5,color(i+2,2));
|
|
112
|
+
circle(60-i*6,30,10.1,.5,PI-.5,color(i+2,1));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// engine outline
|
|
116
|
+
circle(36,30,10,PI/2,PI*3/2);
|
|
117
|
+
circle(48,30,10,PI/2,PI*3/2);
|
|
118
|
+
circle(60,30,10);
|
|
119
|
+
line(36,20,60,20);
|
|
120
|
+
|
|
121
|
+
// engine front light
|
|
122
|
+
circle(60,30,4,PI,3*PI,color(3,2));
|
|
123
|
+
circle(60,30,4,PI,2*PI,color(3,3));
|
|
124
|
+
circle(60,30,4,PI,3*PI);
|
|
125
|
+
|
|
126
|
+
// front brush
|
|
127
|
+
for (let i=6; i--;)
|
|
128
|
+
{
|
|
129
|
+
x.beginPath();
|
|
130
|
+
x.lineTo(53,54);
|
|
131
|
+
x.lineTo(53,40);
|
|
132
|
+
x.lineTo(53+(1+i*2.9)*p,40);
|
|
133
|
+
x.lineTo(53+(4+i*3.5)*p,54);
|
|
134
|
+
x.fillStyle = color(0,i%2+2);
|
|
135
|
+
x.fill();
|
|
136
|
+
i%2 && x.stroke();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// wheels
|
|
140
|
+
rect(6,40,5,5);
|
|
141
|
+
rect(6,40,5,5,color());
|
|
142
|
+
rect(15,54,38,-14,color());
|
|
143
|
+
for (let i=3; i--;)
|
|
144
|
+
for (let j=2; j--;)
|
|
145
|
+
{
|
|
146
|
+
circle(15*i+15,47,j?7:1,PI,3*PI,color(i,3));
|
|
147
|
+
x.stroke();
|
|
148
|
+
circle(15*i+15,47,j?7:1,0,PI,color(i,2));
|
|
149
|
+
x.stroke();
|
|
150
|
+
}
|
|
151
|
+
line(6,40,68,40); // center
|
|
152
|
+
line(77,54,4,54); // bottom
|
|
153
|
+
|
|
154
|
+
// draw engine name
|
|
155
|
+
const s = engineName;
|
|
156
|
+
x.font = '900 16px arial';
|
|
157
|
+
x.textAlign = 'center';
|
|
158
|
+
x.textBaseline = 'top';
|
|
159
|
+
x.lineWidth = .1+p*3.9;
|
|
160
|
+
let w2 = 0;
|
|
161
|
+
for (let i=0; i<s.length; ++i)
|
|
162
|
+
w2 += x.measureText(s[i]).width;
|
|
163
|
+
for (let j=2; j--;)
|
|
164
|
+
for (let i=0, X=41-w2/2; i<s.length; ++i)
|
|
165
|
+
{
|
|
166
|
+
x.fillStyle = color(i,2);
|
|
167
|
+
const w = x.measureText(s[i]).width;
|
|
168
|
+
x[j?'strokeText':'fillText'](s[i],X+w/2,55.5,17*p);
|
|
169
|
+
X += w;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
x.restore();
|
|
173
|
+
}
|
package/src/engineTileLayer.js
CHANGED
|
@@ -47,7 +47,7 @@ function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
/** Return the exact position of the
|
|
50
|
+
/** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
|
|
51
51
|
* The point will be inside the colliding tile if it hits (may have a tiny shift)
|
|
52
52
|
* @param {Vector2} posStart
|
|
53
53
|
* @param {Vector2} posEnd
|
|
@@ -553,7 +553,7 @@ class TileCollisionLayer extends TileLayer
|
|
|
553
553
|
// remove from collision layers array and destroy
|
|
554
554
|
const index = tileCollisionLayers.indexOf(this);
|
|
555
555
|
ASSERT(index >= 0, 'tile collision layer not found in array');
|
|
556
|
-
tileCollisionLayers.splice(index, 1);
|
|
556
|
+
index >= 0 && tileCollisionLayers.splice(index, 1);
|
|
557
557
|
super.destroy();
|
|
558
558
|
}
|
|
559
559
|
|
|
@@ -621,7 +621,7 @@ class TileCollisionLayer extends TileLayer
|
|
|
621
621
|
return false;
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
-
/** Return the exact position of the
|
|
624
|
+
/** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
|
|
625
625
|
* The point will be inside the colliding tile if it hits (may have a tiny shift)
|
|
626
626
|
* @param {Vector2} posStart
|
|
627
627
|
* @param {Vector2} posEnd
|
package/src/engineUtilities.js
CHANGED
|
@@ -623,9 +623,15 @@ class Vector2
|
|
|
623
623
|
{
|
|
624
624
|
this.x = x;
|
|
625
625
|
this.y = y;
|
|
626
|
+
ASSERT_VECTOR2_VALID(this);
|
|
626
627
|
return this;
|
|
627
628
|
}
|
|
628
629
|
|
|
630
|
+
/** Sets this vector from another vector and returns self
|
|
631
|
+
* @param {Vector2} v - other vector
|
|
632
|
+
* @return {Vector2} */
|
|
633
|
+
setFrom(v) { return this.set(v.x, v.y); }
|
|
634
|
+
|
|
629
635
|
/** Returns a new vector that is a copy of this
|
|
630
636
|
* @return {Vector2} */
|
|
631
637
|
copy() { return new Vector2(this.x, this.y); }
|
|
@@ -688,7 +694,7 @@ class Vector2
|
|
|
688
694
|
clampLength(length=1)
|
|
689
695
|
{
|
|
690
696
|
const l = this.length();
|
|
691
|
-
return l > length ? this.scale(length/l) : this;
|
|
697
|
+
return l > length ? this.scale(length/l) : this.copy();
|
|
692
698
|
}
|
|
693
699
|
|
|
694
700
|
/** Returns the dot product of this and the vector passed in
|
|
@@ -775,6 +781,10 @@ class Vector2
|
|
|
775
781
|
* @return {number} */
|
|
776
782
|
area() { return abs(this.x * this.y); }
|
|
777
783
|
|
|
784
|
+
/** Returns true if this vector is (0,0)
|
|
785
|
+
* @return {boolean} */
|
|
786
|
+
isZero() { return !this.x && !this.y; }
|
|
787
|
+
|
|
778
788
|
/** Returns a new vector that is p percent between this and the vector passed in
|
|
779
789
|
* @param {Vector2} v - other vector
|
|
780
790
|
* @param {number} percent
|
|
@@ -885,9 +895,15 @@ class Color
|
|
|
885
895
|
this.g = g;
|
|
886
896
|
this.b = b;
|
|
887
897
|
this.a = a;
|
|
898
|
+
ASSERT_COLOR_VALID(this);
|
|
888
899
|
return this;
|
|
889
900
|
}
|
|
890
901
|
|
|
902
|
+
/** Sets this color from another color and returns self
|
|
903
|
+
* @param {Color} c - other color
|
|
904
|
+
* @return {Color} */
|
|
905
|
+
setFrom(c) { return this.set(c.r, c.g, c.b, c.a); }
|
|
906
|
+
|
|
891
907
|
/** Returns a new color that is a copy of this
|
|
892
908
|
* @return {Color} */
|
|
893
909
|
copy() { return new Color(this.r, this.g, this.b, this.a); }
|