littlejsengine 1.14.16 → 1.14.19
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 +55 -32
- package/dist/littlejs.esm.js +393 -227
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +393 -227
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +393 -227
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/electron/game.js +2 -2
- package/examples/electron/index.html +2 -2
- package/examples/index.html +57 -49
- package/examples/module/game.js +2 -2
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +2 -2
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/tileLayer.js +1 -1
- package/examples/shorts/tiltedView.js +14 -6
- package/examples/shorts/topDown.js +1 -1
- package/examples/starter/game.js +2 -2
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/game.ts +1 -1
- package/examples/uiSystem/game.js +1 -0
- package/package.json +1 -1
- package/plugins/postProcess.js +71 -51
- package/plugins/uiSystem.js +76 -23
- package/src/engine.js +28 -14
- package/src/engineAudio.js +20 -10
- package/src/engineDraw.js +35 -29
- package/src/engineParticles.js +1 -1
- package/src/engineTileLayer.js +31 -39
- package/src/engineWebGL.js +134 -63
package/plugins/postProcess.js
CHANGED
|
@@ -25,80 +25,97 @@ class PostProcessPlugin
|
|
|
25
25
|
/** Create global post processing shader
|
|
26
26
|
* @param {string} shaderCode
|
|
27
27
|
* @param {boolean} [includeOverlay]
|
|
28
|
+
* @param {boolean} [includeMainCanvas]
|
|
28
29
|
* @example
|
|
29
30
|
* // create the post process plugin object
|
|
30
31
|
* new PostProcessPlugin(shaderCode);
|
|
31
32
|
*/
|
|
32
|
-
constructor(shaderCode, includeOverlay=false)
|
|
33
|
+
constructor(shaderCode, includeOverlay=false, includeMainCanvas=true)
|
|
33
34
|
{
|
|
34
35
|
ASSERT(!postProcess, 'Post process already initialized');
|
|
35
36
|
postProcess = this;
|
|
36
37
|
|
|
37
|
-
if (headlessMode) return;
|
|
38
|
-
|
|
39
|
-
if (!glEnable)
|
|
40
|
-
{
|
|
41
|
-
console.warn('PostProcessPlugin: WebGL not enabled!');
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
38
|
if (!shaderCode) // default shader pass through
|
|
46
39
|
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
|
|
47
40
|
|
|
48
41
|
/** @property {WebGLProgram} - Shader for post processing */
|
|
49
|
-
this.shader =
|
|
50
|
-
'#version 300 es\n' + // specify GLSL ES version
|
|
51
|
-
'precision highp float;'+ // use highp for better accuracy
|
|
52
|
-
'in vec2 p;'+ // position
|
|
53
|
-
'void main(){'+ // shader entry point
|
|
54
|
-
'gl_Position=vec4(p+p-1.,1,1);'+ // set position
|
|
55
|
-
'}' // end of shader
|
|
56
|
-
,
|
|
57
|
-
'#version 300 es\n' + // specify GLSL ES version
|
|
58
|
-
'precision highp float;'+ // use highp for better accuracy
|
|
59
|
-
'uniform sampler2D iChannel0;'+ // input texture
|
|
60
|
-
'uniform vec3 iResolution;'+ // size of output texture
|
|
61
|
-
'uniform float iTime;'+ // time
|
|
62
|
-
'out vec4 c;'+ // out color
|
|
63
|
-
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
64
|
-
'void main(){'+ // shader entry point
|
|
65
|
-
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
|
|
66
|
-
'c.a=1.;'+ // always use full alpha
|
|
67
|
-
'}' // end of shader
|
|
68
|
-
);
|
|
42
|
+
this.shader = undefined;
|
|
69
43
|
|
|
70
44
|
/** @property {WebGLTexture} - Texture for post processing */
|
|
71
|
-
this.texture =
|
|
45
|
+
this.texture = undefined;
|
|
72
46
|
|
|
73
|
-
|
|
74
|
-
|
|
47
|
+
// setup the post processing plugin
|
|
48
|
+
initPostProcess();
|
|
49
|
+
engineAddPlugin(undefined, postProcessRender, postProcessContextLost, postProcessContextRestored);
|
|
75
50
|
|
|
76
|
-
|
|
77
|
-
engineAddPlugin(undefined, postProcessRender);
|
|
78
|
-
function postProcessRender()
|
|
51
|
+
function initPostProcess()
|
|
79
52
|
{
|
|
80
53
|
if (headlessMode) return;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (glEnable)
|
|
84
|
-
{
|
|
85
|
-
glFlush(); // clear out the buffer
|
|
86
|
-
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
87
|
-
}
|
|
88
|
-
else
|
|
54
|
+
|
|
55
|
+
if (!glEnable)
|
|
89
56
|
{
|
|
90
|
-
|
|
91
|
-
|
|
57
|
+
console.warn('PostProcessPlugin: WebGL not enabled!');
|
|
58
|
+
return;
|
|
92
59
|
}
|
|
93
60
|
|
|
94
|
-
|
|
61
|
+
// create resources
|
|
62
|
+
postProcess.texture = glCreateTexture();
|
|
63
|
+
postProcess.shader = glCreateProgram(
|
|
64
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
65
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
66
|
+
'in vec2 p;'+ // position
|
|
67
|
+
'void main(){'+ // shader entry point
|
|
68
|
+
'gl_Position=vec4(p+p-1.,1,1);'+ // set position
|
|
69
|
+
'}' // end of shader
|
|
70
|
+
,
|
|
71
|
+
'#version 300 es\n' + // specify GLSL ES version
|
|
72
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
73
|
+
'uniform sampler2D iChannel0;'+ // input texture
|
|
74
|
+
'uniform vec3 iResolution;'+ // size of output texture
|
|
75
|
+
'uniform float iTime;'+ // time
|
|
76
|
+
'out vec4 c;'+ // out color
|
|
77
|
+
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
78
|
+
'void main(){'+ // shader entry point
|
|
79
|
+
'mainImage(c,gl_FragCoord.xy);'+ // call post process function
|
|
80
|
+
'c.a=1.;'+ // always use full alpha
|
|
81
|
+
'}' // end of shader
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function postProcessContextLost()
|
|
85
|
+
{
|
|
86
|
+
postProcess.shader = undefined;
|
|
87
|
+
postProcess.texture = undefined;
|
|
88
|
+
LOG('PostProcessPlugin: WebGL context lost');
|
|
89
|
+
}
|
|
90
|
+
function postProcessContextRestored()
|
|
91
|
+
{
|
|
92
|
+
initPostProcess();
|
|
93
|
+
LOG('PostProcessPlugin: WebGL context restored');
|
|
94
|
+
}
|
|
95
|
+
function postProcessRender()
|
|
96
|
+
{
|
|
97
|
+
if (headlessMode) return;
|
|
98
|
+
|
|
99
|
+
if (!glEnable)
|
|
100
|
+
return;
|
|
101
|
+
|
|
102
|
+
// clear out the buffer
|
|
103
|
+
glFlush();
|
|
104
|
+
|
|
105
|
+
if (includeMainCanvas || includeOverlay)
|
|
95
106
|
{
|
|
96
|
-
// copy
|
|
97
|
-
mainContext.drawImage(
|
|
98
|
-
|
|
107
|
+
// copy WebGL to the main canvas
|
|
108
|
+
mainContext.drawImage(glCanvas, 0, 0);
|
|
109
|
+
|
|
110
|
+
if (includeOverlay)
|
|
111
|
+
{
|
|
112
|
+
// copy overlay canvas so it will be included in post processing
|
|
113
|
+
mainContext.drawImage(overlayCanvas, 0, 0);
|
|
114
|
+
overlayCanvas.width |= 0; // clear overlay canvas
|
|
115
|
+
}
|
|
99
116
|
}
|
|
100
117
|
|
|
101
|
-
// setup shader program to draw
|
|
118
|
+
// setup shader program to draw a quad
|
|
102
119
|
glContext.useProgram(postProcess.shader);
|
|
103
120
|
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
104
121
|
glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, 1);
|
|
@@ -107,7 +124,10 @@ class PostProcessPlugin
|
|
|
107
124
|
// set textures, pass in the 2d canvas and gl canvas in separate texture channels
|
|
108
125
|
glContext.activeTexture(glContext.TEXTURE0);
|
|
109
126
|
glContext.bindTexture(glContext.TEXTURE_2D, postProcess.texture);
|
|
110
|
-
|
|
127
|
+
if (includeMainCanvas || includeOverlay)
|
|
128
|
+
{
|
|
129
|
+
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, mainCanvas);
|
|
130
|
+
}
|
|
111
131
|
|
|
112
132
|
// set vertex position attribute
|
|
113
133
|
const vertexByteStride = 8;
|
package/plugins/uiSystem.js
CHANGED
|
@@ -48,6 +48,8 @@ class UISystemPlugin
|
|
|
48
48
|
this.defaultHoverColor = hsl(0,0,.9);
|
|
49
49
|
/** @property {Color} - Default color for disabled UI elements */
|
|
50
50
|
this.defaultDisabledColor = hsl(0,0,.3);
|
|
51
|
+
/** @property {Color} - Uses a gradient fill combined with color */
|
|
52
|
+
this.defaultGradientColor = undefined;
|
|
51
53
|
/** @property {number} - Default line width for UI elements */
|
|
52
54
|
this.defaultLineWidth = 4;
|
|
53
55
|
/** @property {number} - Default rounded rect corner radius for UI elements */
|
|
@@ -55,7 +57,7 @@ class UISystemPlugin
|
|
|
55
57
|
/** @property {number} - Default scale to use for fitting text to object */
|
|
56
58
|
this.defaultTextScale = .8;
|
|
57
59
|
/** @property {string} - Default font for UI elements */
|
|
58
|
-
this.defaultFont =
|
|
60
|
+
this.defaultFont = fontDefault;
|
|
59
61
|
/** @property {Sound} - Default sound when interactive UI element is pressed */
|
|
60
62
|
this.defaultSoundPress = undefined;
|
|
61
63
|
/** @property {Sound} - Default sound when interactive UI element is released */
|
|
@@ -72,7 +74,9 @@ class UISystemPlugin
|
|
|
72
74
|
this.hoverObject = undefined;
|
|
73
75
|
/** @property {UIObject} - Hover object at start of update */
|
|
74
76
|
this.lastHoverObject = undefined;
|
|
75
|
-
|
|
77
|
+
/** @property {number} - If set ui coords will be renormalized to this canvas height */
|
|
78
|
+
this.nativeHeight = 0;
|
|
79
|
+
|
|
76
80
|
engineAddPlugin(uiUpdate, uiRender);
|
|
77
81
|
|
|
78
82
|
// setup recursive update and render
|
|
@@ -112,6 +116,17 @@ class UISystemPlugin
|
|
|
112
116
|
}
|
|
113
117
|
function uiRender()
|
|
114
118
|
{
|
|
119
|
+
const context = uiSystem.uiContext;
|
|
120
|
+
context.save();
|
|
121
|
+
if (uiSystem.nativeHeight)
|
|
122
|
+
{
|
|
123
|
+
// convert to native height
|
|
124
|
+
const s = mainCanvasSize.y / uiSystem.nativeHeight;
|
|
125
|
+
context.translate(-s*mainCanvasSize.x/2,0);
|
|
126
|
+
context.scale(s,s);
|
|
127
|
+
context.translate(mainCanvasSize.x/2/s,0);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
function renderObject(o)
|
|
116
131
|
{
|
|
117
132
|
if (!o.visible)
|
|
@@ -123,6 +138,7 @@ class UISystemPlugin
|
|
|
123
138
|
renderObject(c);
|
|
124
139
|
}
|
|
125
140
|
uiSystem.uiObjects.forEach(o=> o.parent || renderObject(o));
|
|
141
|
+
context.restore();
|
|
126
142
|
}
|
|
127
143
|
}
|
|
128
144
|
|
|
@@ -132,8 +148,9 @@ class UISystemPlugin
|
|
|
132
148
|
* @param {Color} [color=uiSystem.defaultColor]
|
|
133
149
|
* @param {number} [lineWidth=uiSystem.defaultLineWidth]
|
|
134
150
|
* @param {Color} [lineColor=uiSystem.defaultLineColor]
|
|
135
|
-
* @param {number} [cornerRadius=uiSystem.defaultCornerRadius]
|
|
136
|
-
|
|
151
|
+
* @param {number} [cornerRadius=uiSystem.defaultCornerRadius]
|
|
152
|
+
* @param {Color} [gradientColor=uiSystem.defaultGradientColor] */
|
|
153
|
+
drawRect(pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, cornerRadius=uiSystem.defaultCornerRadius, gradientColor=uiSystem.defaultGradientColor)
|
|
137
154
|
{
|
|
138
155
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
139
156
|
ASSERT(isVector2(size), 'size must be a vec2');
|
|
@@ -143,7 +160,18 @@ class UISystemPlugin
|
|
|
143
160
|
ASSERT(isNumber(cornerRadius), 'cornerRadius must be a number');
|
|
144
161
|
|
|
145
162
|
const context = uiSystem.uiContext;
|
|
146
|
-
|
|
163
|
+
if (gradientColor)
|
|
164
|
+
{
|
|
165
|
+
const g = context.createLinearGradient(
|
|
166
|
+
pos.x, pos.y-size.y/2, pos.x, pos.y+size.y/2);
|
|
167
|
+
const c = color.toString();
|
|
168
|
+
g.addColorStop(0, c);
|
|
169
|
+
g.addColorStop(.5, gradientColor.toString());
|
|
170
|
+
g.addColorStop(1, c);
|
|
171
|
+
context.fillStyle = g;
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
context.fillStyle = color.toString();
|
|
147
175
|
context.beginPath();
|
|
148
176
|
if (cornerRadius && context['roundRect'])
|
|
149
177
|
context['roundRect'](pos.x-size.x/2, pos.y-size.y/2, size.x, size.y, cornerRadius);
|
|
@@ -200,10 +228,11 @@ class UISystemPlugin
|
|
|
200
228
|
* @param {Color} [lineColor=uiSystem.defaultLineColor]
|
|
201
229
|
* @param {string} [align]
|
|
202
230
|
* @param {string} [font=uiSystem.defaultFont]
|
|
231
|
+
* @param {string} [fontStyle]
|
|
203
232
|
* @param {boolean} [applyMaxWidth=true] */
|
|
204
|
-
drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, applyMaxWidth=true)
|
|
233
|
+
drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, fontStyle='', applyMaxWidth=true)
|
|
205
234
|
{
|
|
206
|
-
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
|
|
235
|
+
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, fontStyle, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
|
|
207
236
|
}
|
|
208
237
|
|
|
209
238
|
/**
|
|
@@ -264,17 +293,21 @@ class UIObject
|
|
|
264
293
|
/** @property {boolean} - Is this object disabled? */
|
|
265
294
|
this.disabled = false;
|
|
266
295
|
/** @property {Color} - Color for text */
|
|
267
|
-
this.textColor = uiSystem.defaultTextColor.copy()
|
|
296
|
+
this.textColor = uiSystem.defaultTextColor.copy();
|
|
268
297
|
/** @property {Color} - Color used when hovering over the object */
|
|
269
|
-
this.hoverColor = uiSystem.defaultHoverColor.copy()
|
|
298
|
+
this.hoverColor = uiSystem.defaultHoverColor.copy();
|
|
270
299
|
/** @property {Color} - Color for line drawing */
|
|
271
|
-
this.lineColor = uiSystem.defaultLineColor.copy()
|
|
300
|
+
this.lineColor = uiSystem.defaultLineColor.copy();
|
|
301
|
+
/** @property {Color} - Uses a gradient fill combined with color */
|
|
302
|
+
this.gradientColor = uiSystem.defaultGradientColor ? uiSystem.defaultGradientColor.copy() : undefined;
|
|
272
303
|
/** @property {number} - Width for line drawing */
|
|
273
304
|
this.lineWidth = uiSystem.defaultLineWidth;
|
|
274
305
|
/** @property {number} - Corner radius for rounded rects */
|
|
275
306
|
this.cornerRadius = uiSystem.defaultCornerRadius;
|
|
276
307
|
/** @property {string} - Font for this objecct */
|
|
277
308
|
this.font = uiSystem.defaultFont;
|
|
309
|
+
/** @property {string} - Font style for this object or undefined */
|
|
310
|
+
this.fontStyle = undefined;
|
|
278
311
|
/** @property {number} - Override for text width */
|
|
279
312
|
this.textWidth = undefined;
|
|
280
313
|
/** @property {number} - Override for text height */
|
|
@@ -299,6 +332,8 @@ class UIObject
|
|
|
299
332
|
this.interactive = false;
|
|
300
333
|
/** @property {boolean} - Activate when dragged over with mouse held down */
|
|
301
334
|
this.dragActivate = false;
|
|
335
|
+
/** @property {boolean} - True if this can be a hover object */
|
|
336
|
+
this.canBeHover = true;
|
|
302
337
|
uiSystem.uiObjects.push(this);
|
|
303
338
|
}
|
|
304
339
|
|
|
@@ -322,6 +357,26 @@ class UIObject
|
|
|
322
357
|
child.parent = undefined;
|
|
323
358
|
}
|
|
324
359
|
|
|
360
|
+
/** Check if the mouse is overlapping a box in screen space
|
|
361
|
+
* @return {boolean} - True if overlapping
|
|
362
|
+
*/
|
|
363
|
+
isMouseOverlapping()
|
|
364
|
+
{
|
|
365
|
+
const size = !isTouchDevice ? this.size :
|
|
366
|
+
this.size.add(vec2(this.extraTouchSize || 0));
|
|
367
|
+
if (!uiSystem.nativeHeight)
|
|
368
|
+
return isOverlapping(this.pos, size, mousePosScreen);
|
|
369
|
+
|
|
370
|
+
const s = mainCanvasSize.y / uiSystem.nativeHeight;
|
|
371
|
+
const sInv = 1/s;
|
|
372
|
+
let pos = mousePosScreen.copy();
|
|
373
|
+
pos.x += s*mainCanvasSize.x/2;
|
|
374
|
+
pos.x *= sInv;
|
|
375
|
+
pos.y *= sInv;
|
|
376
|
+
pos.x -= sInv*mainCanvasSize.x/2;
|
|
377
|
+
return isOverlapping(this.pos, size, pos);
|
|
378
|
+
}
|
|
379
|
+
|
|
325
380
|
/** Update the object, called automatically by plugin once each frame */
|
|
326
381
|
update()
|
|
327
382
|
{
|
|
@@ -329,13 +384,10 @@ class UIObject
|
|
|
329
384
|
const isActive = this.isActiveObject();
|
|
330
385
|
const mouseDown = mouseIsDown(0);
|
|
331
386
|
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
332
|
-
if (
|
|
387
|
+
if (this.canBeHover)
|
|
333
388
|
if (mousePress || isActive || (!mouseDown && !isTouchDevice))
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (isOverlapping(this.pos, size, mousePosScreen))
|
|
337
|
-
uiSystem.hoverObject = this;
|
|
338
|
-
}
|
|
389
|
+
if (!uiSystem.hoverObject && this.isMouseOverlapping())
|
|
390
|
+
uiSystem.hoverObject = this;
|
|
339
391
|
if (this.isHoverObject())
|
|
340
392
|
{
|
|
341
393
|
if (!this.disabled)
|
|
@@ -460,11 +512,13 @@ class UIText extends UIObject
|
|
|
460
512
|
|
|
461
513
|
// make text not outlined by default
|
|
462
514
|
this.lineWidth = 0;
|
|
515
|
+
// text can not be a hover object by default
|
|
516
|
+
this.canBeHover = false;
|
|
463
517
|
}
|
|
464
518
|
render()
|
|
465
519
|
{
|
|
466
520
|
const textSize = this.getTextSize();
|
|
467
|
-
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
|
|
521
|
+
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font, this.fontStyle);
|
|
468
522
|
}
|
|
469
523
|
}
|
|
470
524
|
|
|
@@ -530,7 +584,7 @@ class UIButton extends UIObject
|
|
|
530
584
|
|
|
531
585
|
// set properties
|
|
532
586
|
this.text = text;
|
|
533
|
-
this.color = color.copy()
|
|
587
|
+
this.color = color.copy();
|
|
534
588
|
this.interactive = true;
|
|
535
589
|
}
|
|
536
590
|
render()
|
|
@@ -540,7 +594,7 @@ class UIButton extends UIObject
|
|
|
540
594
|
// draw the text scaled to fit
|
|
541
595
|
const textSize = this.getTextSize();
|
|
542
596
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
543
|
-
this.textColor, 0, undefined, this.align, this.font);
|
|
597
|
+
this.textColor, 0, undefined, this.align, this.font, this.fontStyle);
|
|
544
598
|
}
|
|
545
599
|
}
|
|
546
600
|
|
|
@@ -594,7 +648,7 @@ class UICheckbox extends UIObject
|
|
|
594
648
|
const textSize = this.getTextSize();
|
|
595
649
|
const pos = this.pos.add(vec2(this.size.x,0));
|
|
596
650
|
uiSystem.drawText(this.text, pos, textSize,
|
|
597
|
-
this.textColor, 0, undefined, 'left', this.font, false);
|
|
651
|
+
this.textColor, 0, undefined, 'left', this.font, this.fontStyle, false);
|
|
598
652
|
}
|
|
599
653
|
}
|
|
600
654
|
|
|
@@ -672,13 +726,12 @@ class UIScrollbar extends UIObject
|
|
|
672
726
|
const handlePos = isHorizontal ?
|
|
673
727
|
vec2(lerp(p1, p2, this.value), this.pos.y) :
|
|
674
728
|
vec2(this.pos.x, lerp(p2, p1, this.value))
|
|
675
|
-
const handleColor = this.disabled ? this.disabledColor :
|
|
676
|
-
this.interactive && this.isActiveObject() ? this.color : this.handleColor;
|
|
729
|
+
const handleColor = this.disabled ? this.disabledColor : this.handleColor;
|
|
677
730
|
uiSystem.drawRect(handlePos, vec2(handleSize), handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
678
731
|
|
|
679
732
|
// draw the text scaled to fit on the scrollbar
|
|
680
733
|
const textSize = this.getTextSize();
|
|
681
734
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
682
|
-
this.textColor, 0, undefined, this.align, this.font);
|
|
735
|
+
this.textColor, 0, undefined, this.align, this.font, this.fontStyle);
|
|
683
736
|
}
|
|
684
737
|
}
|
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {string}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.14.
|
|
33
|
+
const engineVersion = '1.14.19';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -91,7 +91,17 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
|
|
|
91
91
|
///////////////////////////////////////////////////////////////////////////////
|
|
92
92
|
// plugin hooks
|
|
93
93
|
|
|
94
|
-
const
|
|
94
|
+
const pluginList = [];
|
|
95
|
+
class EnginePlugin
|
|
96
|
+
{
|
|
97
|
+
constructor(update, render, glContextLost, glContextRestored)
|
|
98
|
+
{
|
|
99
|
+
this.update = update;
|
|
100
|
+
this.render = render;
|
|
101
|
+
this.glContextLost = glContextLost;
|
|
102
|
+
this.glContextRestored = glContextRestored;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
95
105
|
|
|
96
106
|
/**
|
|
97
107
|
* @callback PluginCallback - Update or render function for a plugin
|
|
@@ -99,15 +109,21 @@ const pluginUpdateList = [], pluginRenderList = [];
|
|
|
99
109
|
*/
|
|
100
110
|
|
|
101
111
|
/** Add a new update function for a plugin
|
|
102
|
-
* @param {PluginCallback} [
|
|
103
|
-
* @param {PluginCallback} [
|
|
112
|
+
* @param {PluginCallback} [update]
|
|
113
|
+
* @param {PluginCallback} [render]
|
|
114
|
+
* @param {PluginCallback} [glContextLost]
|
|
115
|
+
* @param {PluginCallback} [glContextRestored]
|
|
104
116
|
* @memberof Engine */
|
|
105
|
-
function engineAddPlugin(
|
|
117
|
+
function engineAddPlugin(update, render, glContextLost, glContextRestored)
|
|
106
118
|
{
|
|
107
|
-
|
|
108
|
-
ASSERT(!
|
|
109
|
-
|
|
110
|
-
|
|
119
|
+
// make sure plugin functions are unique
|
|
120
|
+
ASSERT(!pluginList.find(p=>
|
|
121
|
+
p.update === update && p.render === render &&
|
|
122
|
+
p.glContextLost === glContextLost &&
|
|
123
|
+
p.glContextRestored === glContextRestored));
|
|
124
|
+
|
|
125
|
+
const plugin = new EnginePlugin(update, render, glContextLost, glContextRestored);
|
|
126
|
+
pluginList.push(plugin);
|
|
111
127
|
}
|
|
112
128
|
|
|
113
129
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -192,7 +208,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
192
208
|
wasUpdated = true;
|
|
193
209
|
updateCanvas();
|
|
194
210
|
inputUpdate();
|
|
195
|
-
|
|
211
|
+
pluginList.forEach(plugin=>plugin.update?.());
|
|
196
212
|
|
|
197
213
|
// update object transforms even when paused
|
|
198
214
|
for (const o of engineObjects)
|
|
@@ -225,7 +241,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
225
241
|
updateCanvas();
|
|
226
242
|
inputUpdate();
|
|
227
243
|
gameUpdate();
|
|
228
|
-
|
|
244
|
+
pluginList.forEach(plugin=>plugin.update?.());
|
|
229
245
|
engineObjectsUpdate();
|
|
230
246
|
|
|
231
247
|
// do post update
|
|
@@ -259,7 +275,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
259
275
|
for (const o of engineObjects)
|
|
260
276
|
o.destroyed || o.render();
|
|
261
277
|
gameRenderPost();
|
|
262
|
-
|
|
278
|
+
pluginList.forEach(plugin=>plugin.render?.());
|
|
263
279
|
touchGamepadRender();
|
|
264
280
|
debugRender();
|
|
265
281
|
glFlush();
|
|
@@ -386,7 +402,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
386
402
|
image.onerror = image.onload = ()=>
|
|
387
403
|
{
|
|
388
404
|
const textureInfo = new TextureInfo(image);
|
|
389
|
-
textureInfo.createWebGLTexture();
|
|
390
405
|
textureInfos[textureIndex] = textureInfo;
|
|
391
406
|
resolve();
|
|
392
407
|
}
|
|
@@ -402,7 +417,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
402
417
|
{
|
|
403
418
|
const textureInfo = new TextureInfo(new Image);
|
|
404
419
|
textureInfos[0] = textureInfo;
|
|
405
|
-
textureInfo.createWebGLTexture();
|
|
406
420
|
resolve();
|
|
407
421
|
}));
|
|
408
422
|
}
|
package/src/engineAudio.js
CHANGED
|
@@ -324,8 +324,16 @@ class SoundInstance
|
|
|
324
324
|
this.stop();
|
|
325
325
|
this.gainNode = audioContext.createGain();
|
|
326
326
|
this.source = playSamples(this.sound.sampleChannels, this.volume, this.rate, this.pan, this.loop, this.sound.sampleRate, this.gainNode, offset, this.onendedCallback);
|
|
327
|
-
this.
|
|
328
|
-
|
|
327
|
+
if (this.source)
|
|
328
|
+
{
|
|
329
|
+
this.startTime = audioContext.currentTime - offset;
|
|
330
|
+
this.pausedTime = undefined;
|
|
331
|
+
}
|
|
332
|
+
else
|
|
333
|
+
{
|
|
334
|
+
this.startTime = undefined;
|
|
335
|
+
this.pausedTime = 0;
|
|
336
|
+
}
|
|
329
337
|
}
|
|
330
338
|
|
|
331
339
|
/** Set the volume of this sound instance
|
|
@@ -474,12 +482,19 @@ function getNoteFrequency(semitoneOffset, rootFrequency=220)
|
|
|
474
482
|
* @param {GainNode} [gainNode] - Optional gain node for volume control while playing
|
|
475
483
|
* @param {number} [offset] - Offset in seconds to start playback from
|
|
476
484
|
* @param {AudioEndedCallback} [onended] - Callback for when the sound ends
|
|
477
|
-
* @return {AudioBufferSourceNode} - The
|
|
485
|
+
* @return {AudioBufferSourceNode} - The source node of the sound played, may be undefined if play fails
|
|
478
486
|
* @memberof Audio */
|
|
479
487
|
function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sampleRate=audioDefaultSampleRate, gainNode, offset=0, onended)
|
|
480
488
|
{
|
|
481
489
|
if (!soundEnable || headlessMode) return;
|
|
482
490
|
|
|
491
|
+
if (!audioIsRunning())
|
|
492
|
+
{
|
|
493
|
+
// fix stalled audio, this sound won't be able to play
|
|
494
|
+
audioContext.resume();
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
483
498
|
// create buffer and source
|
|
484
499
|
const channelCount = sampleChannels.length;
|
|
485
500
|
const sampleLength = sampleChannels[0].length;
|
|
@@ -505,14 +520,9 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
505
520
|
if (onended)
|
|
506
521
|
source.addEventListener('ended', ()=> onended(source));
|
|
507
522
|
|
|
523
|
+
// play and return sound
|
|
508
524
|
const startOffset = offset * rate;
|
|
509
|
-
|
|
510
|
-
{
|
|
511
|
-
// fix stalled audio and start
|
|
512
|
-
audioContext.resume().then(()=>source.start(0, startOffset));
|
|
513
|
-
}
|
|
514
|
-
else
|
|
515
|
-
source.start(0, startOffset);
|
|
525
|
+
source.start(0, startOffset);
|
|
516
526
|
return source;
|
|
517
527
|
}
|
|
518
528
|
|