littlejsengine 1.14.5 → 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 +53 -19
- package/dist/littlejs.esm.js +183 -106
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +179 -104
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +178 -103
- package/examples/box2d/game.js +1 -3
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +92 -51
- package/examples/puzzle/game.js +1 -2
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/box2d.js +1 -0
- package/examples/shorts/box2dCar.js +1 -0
- package/examples/shorts/flappyGame.js +2 -1
- package/examples/shorts/helloWorld.js +2 -2
- package/examples/shorts/hillGlideGame.js +6 -3
- package/examples/shorts/maze.js +1 -0
- package/examples/shorts/medals.js +3 -0
- package/examples/shorts/music.js +3 -5
- package/examples/shorts/piano.js +24 -25
- package/examples/shorts/platformer.js +1 -0
- package/examples/shorts/shapes.js +6 -6
- package/examples/shorts/sound.js +21 -32
- package/examples/shorts/spriteAtlas.js +1 -2
- package/examples/shorts/tileLayer.js +1 -0
- package/examples/shorts/tiltedView.js +1 -1
- package/examples/shorts/timers.js +34 -31
- package/examples/shorts/topDown.js +2 -1
- package/examples/shorts/uiSystem.js +15 -10
- package/examples/stress/index.html +1 -1
- package/examples/uiSystem/game.js +1 -1
- package/package.json +1 -1
- package/plugins/uiSystem.js +83 -58
- package/reference.md +1 -0
- package/src/engine.js +23 -6
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +19 -12
- package/src/engineExport.js +4 -2
- package/src/engineInput.js +7 -0
- package/src/engineObject.js +4 -4
- package/src/engineSettings.js +11 -1
- package/src/engineTileLayer.js +2 -2
- package/src/engineUtilities.js +9 -2
- package/src/engineWebGL.js +20 -18
|
@@ -1,40 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
{
|
|
3
|
-
constructor(pos, time)
|
|
4
|
-
{
|
|
5
|
-
super(pos, vec2(5.5));
|
|
6
|
-
this.time = time;
|
|
7
|
-
this.timer = new Timer;
|
|
8
|
-
}
|
|
1
|
+
let timerButton, timerSlider;
|
|
9
2
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
function gameInit()
|
|
4
|
+
{
|
|
5
|
+
// setup ui system plugin
|
|
6
|
+
new UISystemPlugin();
|
|
7
|
+
uiSystem.defaultCornerRadius = 10;
|
|
8
|
+
canvasClearColor = hsl(.3,.3,.2);
|
|
16
9
|
|
|
17
|
-
|
|
10
|
+
// create timer button
|
|
11
|
+
const pos = mainCanvasSize.scale(.5).add(vec2(0, -40));
|
|
12
|
+
timerButton = new UIButton(pos, vec2(200, 90), 'Start');
|
|
13
|
+
timerButton.timer = new Timer;
|
|
14
|
+
timerButton.onClick = ()=>
|
|
18
15
|
{
|
|
19
|
-
|
|
20
|
-
this.color = this.timer.isSet() ? this.timer.active() ? BLUE : RED : GRAY;
|
|
21
|
-
|
|
22
|
-
// draw the button and timer text
|
|
23
|
-
drawRect(this.pos, this.size, this.color);
|
|
24
|
-
if (this.timer.isSet())
|
|
16
|
+
if (timerButton.timer.isSet())
|
|
25
17
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
drawTextOverlay(percent+'%', this.pos.add(vec2(0,-1)), 2);
|
|
18
|
+
timerButton.timer.unset();
|
|
19
|
+
timerButton.text = 'Start';
|
|
29
20
|
}
|
|
30
21
|
else
|
|
31
|
-
|
|
22
|
+
{
|
|
23
|
+
timerButton.timer.set(3);
|
|
24
|
+
timerButton.text = 'Stop';
|
|
25
|
+
}
|
|
32
26
|
}
|
|
33
|
-
}
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
// create non-interactive slider to display timer
|
|
29
|
+
timerSlider = new UIScrollbar(vec2(0, 100), vec2(400, 50));
|
|
30
|
+
timerSlider.interactive = false;
|
|
31
|
+
timerSlider.update = ()=>
|
|
32
|
+
{
|
|
33
|
+
// update the timer display
|
|
34
|
+
const t = timerButton.timer.get();
|
|
35
|
+
const timeText = t.toFixed(2) + 's';
|
|
36
|
+
const isSet = timerButton.timer.isSet();
|
|
37
|
+
const setTime = timerButton.timer.getSetTime();
|
|
38
|
+
timerSlider.text = timeText;
|
|
39
|
+
timerSlider.value = setTime ? 1+t/setTime : 1;
|
|
40
|
+
timerSlider.color = isSet ? t < 0 ? CYAN : RED : GRAY;
|
|
41
|
+
}
|
|
42
|
+
timerButton.addChild(timerSlider);
|
|
40
43
|
}
|
|
@@ -23,13 +23,14 @@ class Player extends EngineObject
|
|
|
23
23
|
function gameInit()
|
|
24
24
|
{
|
|
25
25
|
// setup level
|
|
26
|
+
canvasClearColor = hsl(.3,.2,.6);
|
|
26
27
|
objectDefaultDamping = .7;
|
|
27
28
|
new Player;
|
|
28
29
|
|
|
29
30
|
// create collision objects
|
|
30
31
|
for (let i=300; i--;)
|
|
31
32
|
{
|
|
32
|
-
const o = new EngineObject(randInCircle(15+i,7), vec2(rand(4,9),rand(4,9)), 0, 0, hsl(0,0,rand(.
|
|
33
|
+
const o = new EngineObject(randInCircle(15+i,7), vec2(rand(4,9),rand(4,9)), 0, 0, hsl(0,0,rand(.1,.3)));
|
|
33
34
|
o.setCollision(); // make object collide
|
|
34
35
|
o.mass = 0; // make object have static physics
|
|
35
36
|
}
|
|
@@ -4,30 +4,35 @@ let uiMenu;
|
|
|
4
4
|
|
|
5
5
|
function gameInit()
|
|
6
6
|
{
|
|
7
|
-
//
|
|
7
|
+
// setup ui system plugin
|
|
8
8
|
new UISystemPlugin;
|
|
9
9
|
uiSystem.defaultSoundPress = new Sound([1,0,220]);
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
const uiMenu = new UIObject(vec2(), vec2(450));
|
|
17
|
-
uiBackground.addChild(uiMenu);
|
|
19
|
+
const uiMenu = new UIObject(mainCanvasSize.scale(.5), vec2(600,450));
|
|
20
|
+
canvasClearColor = hsl(0,0,.8);
|
|
18
21
|
|
|
19
22
|
// example text
|
|
20
|
-
|
|
21
|
-
|
|
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)));
|
|
22
27
|
|
|
23
28
|
// example button
|
|
24
|
-
const button1 = new UIButton(vec2(
|
|
29
|
+
const button1 = new UIButton(vec2(80,0), vec2(140, 80), 'Test');
|
|
25
30
|
button1.textHeight = 60;
|
|
26
31
|
uiMenu.addChild(button1);
|
|
27
|
-
button1.onClick = ()=>
|
|
32
|
+
button1.onClick = ()=> canvasClearColor = randColor();
|
|
28
33
|
|
|
29
34
|
// example checkbox
|
|
30
|
-
const checkbox = new UICheckbox(vec2(-
|
|
35
|
+
const checkbox = new UICheckbox(vec2(-80,0), vec2(50));
|
|
31
36
|
checkbox.onChange = ()=> button1.disabled = checkbox.checked;
|
|
32
37
|
uiMenu.addChild(checkbox);
|
|
33
38
|
|
|
@@ -47,7 +47,7 @@ function gameInit()
|
|
|
47
47
|
LJS.setCanvasFixedSize(vec2(1920, 1080)); // 1080p
|
|
48
48
|
LJS.setCameraScale(20);
|
|
49
49
|
LJS.setCameraPos(tileLayer.size.scale(.5));
|
|
50
|
-
LJS.
|
|
50
|
+
LJS.setCanvasClearColor(rgb(.4,.4,.4));
|
|
51
51
|
LJS.setGravity(vec2(0,-.005));
|
|
52
52
|
sprites = [];
|
|
53
53
|
|
|
@@ -85,6 +85,7 @@ function gameInit()
|
|
|
85
85
|
{
|
|
86
86
|
new LJS.UISystemPlugin;
|
|
87
87
|
createUI();
|
|
88
|
+
LJS.setCanvasClearColor(hsl(0,0,.2));
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -110,7 +111,6 @@ function gameUpdatePost()
|
|
|
110
111
|
function gameRender()
|
|
111
112
|
{
|
|
112
113
|
// test game rendering
|
|
113
|
-
LJS.drawRect(vec2(), vec2(1e3), hsl(0,0,.2));
|
|
114
114
|
for (let i=0; i<1e3; ++i)
|
|
115
115
|
{
|
|
116
116
|
const pos = vec2(30*Math.sin(i+LJS.time/9),20*Math.sin(i*i+LJS.time/9));
|
package/package.json
CHANGED
package/plugins/uiSystem.js
CHANGED
|
@@ -49,6 +49,8 @@ class UISystemPlugin
|
|
|
49
49
|
this.defaultLineWidth = 4;
|
|
50
50
|
/** @property {number} - Default rounded rect corner radius for UI elements */
|
|
51
51
|
this.defaultCornerRadius = 0;
|
|
52
|
+
/** @property {number} - Default scale to use for fitting text to object */
|
|
53
|
+
this.defaultTextScale = .8;
|
|
52
54
|
/** @property {string} - Default font for UI elements */
|
|
53
55
|
this.defaultFont = 'arial';
|
|
54
56
|
/** @property {Sound} - Default sound when interactive UI element is pressed */
|
|
@@ -61,10 +63,15 @@ class UISystemPlugin
|
|
|
61
63
|
this.uiObjects = [];
|
|
62
64
|
/** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
|
|
63
65
|
this.uiContext = context;
|
|
66
|
+
/** @property {UIObject} - Top most object user is over */
|
|
67
|
+
this.hoverObject = undefined;
|
|
68
|
+
/** @property {UIObject} - Object user is currently interacting with */
|
|
69
|
+
this.activeObject = undefined;
|
|
64
70
|
|
|
65
71
|
engineAddPlugin(uiUpdate, uiRender);
|
|
66
72
|
|
|
67
73
|
// setup recursive update and render
|
|
74
|
+
// update in reverse order to detect mouse enter/leave
|
|
68
75
|
function uiUpdate()
|
|
69
76
|
{
|
|
70
77
|
function updateInvisibleObject(o)
|
|
@@ -89,7 +96,13 @@ class UISystemPlugin
|
|
|
89
96
|
else
|
|
90
97
|
updateInvisibleObject(o);
|
|
91
98
|
}
|
|
92
|
-
|
|
99
|
+
// reset hover object at start of update
|
|
100
|
+
uiSystem.hoverObject = undefined;
|
|
101
|
+
for (let i = uiSystem.uiObjects.length; i--;)
|
|
102
|
+
{
|
|
103
|
+
const o = uiSystem.uiObjects[i];
|
|
104
|
+
o.parent || updateObject(o)
|
|
105
|
+
}
|
|
93
106
|
}
|
|
94
107
|
function uiRender()
|
|
95
108
|
{
|
|
@@ -168,10 +181,11 @@ class UISystemPlugin
|
|
|
168
181
|
* @param {number} [lineWidth=uiSystem.defaultLineWidth]
|
|
169
182
|
* @param {Color} [lineColor=uiSystem.defaultLineColor]
|
|
170
183
|
* @param {string} [align]
|
|
171
|
-
* @param {string} [font=uiSystem.defaultFont]
|
|
172
|
-
|
|
184
|
+
* @param {string} [font=uiSystem.defaultFont]
|
|
185
|
+
* @param {boolean} [applyMaxWidth=true] */
|
|
186
|
+
drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, applyMaxWidth=true)
|
|
173
187
|
{
|
|
174
|
-
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, size.x, uiSystem.uiContext);
|
|
188
|
+
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
|
|
175
189
|
}
|
|
176
190
|
}
|
|
177
191
|
|
|
@@ -195,6 +209,8 @@ class UIObject
|
|
|
195
209
|
this.size = size.copy();
|
|
196
210
|
/** @property {Color} - Color of the object */
|
|
197
211
|
this.color = uiSystem.defaultColor;
|
|
212
|
+
/** @property {Color} - Color of the object when active, uses color if undefined */
|
|
213
|
+
this.activeColor = undefined;
|
|
198
214
|
/** @property {string} - Text for this ui object */
|
|
199
215
|
this.text = undefined;
|
|
200
216
|
/** @property {Color} - Color when disabled */
|
|
@@ -213,15 +229,19 @@ class UIObject
|
|
|
213
229
|
this.cornerRadius = uiSystem.defaultCornerRadius;
|
|
214
230
|
/** @property {string} - Font for this objecct */
|
|
215
231
|
this.font = uiSystem.defaultFont;
|
|
232
|
+
/** @property {number} - Override for text width */
|
|
233
|
+
this.textWidth = undefined;
|
|
216
234
|
/** @property {number} - Override for text height */
|
|
217
235
|
this.textHeight = undefined;
|
|
236
|
+
/** @property {number} - Scale text to fit in the object */
|
|
237
|
+
this.textScale = uiSystem.defaultTextScale;
|
|
218
238
|
/** @property {boolean} - Should this object be drawn */
|
|
219
239
|
this.visible = true;
|
|
220
240
|
/** @property {Array<UIObject>} - A list of this object's children */
|
|
221
241
|
this.children = [];
|
|
222
242
|
/** @property {UIObject} - This object's parent, position is in parent space */
|
|
223
243
|
this.parent = undefined;
|
|
224
|
-
/** @property {number} -
|
|
244
|
+
/** @property {number} - Added size to make small buttons easier to touch on mobile devices */
|
|
225
245
|
this.extraTouchSize = 0;
|
|
226
246
|
/** @property {Sound} - Sound when interactive element is pressed */
|
|
227
247
|
this.soundPress = uiSystem.defaultSoundPress;
|
|
@@ -229,12 +249,10 @@ class UIObject
|
|
|
229
249
|
this.soundRelease = uiSystem.defaultSoundRelease;
|
|
230
250
|
/** @property {Sound} - Sound when interactive element is clicked */
|
|
231
251
|
this.soundClick = uiSystem.defaultSoundClick;
|
|
232
|
-
/** @property {boolean} - Is the mouse over this element */
|
|
233
|
-
this.mouseIsOver = false;
|
|
234
252
|
/** @property {boolean} - Is this element interactive */
|
|
235
253
|
this.interactive = false;
|
|
236
|
-
/** @property {boolean} -
|
|
237
|
-
this.
|
|
254
|
+
/** @property {boolean} - Activate when dragged over with mouse held down */
|
|
255
|
+
this.dragActivate = false;
|
|
238
256
|
uiSystem.uiObjects.push(this);
|
|
239
257
|
}
|
|
240
258
|
|
|
@@ -261,15 +279,18 @@ class UIObject
|
|
|
261
279
|
/** Update the object, called automatically by plugin once each frame */
|
|
262
280
|
update()
|
|
263
281
|
{
|
|
264
|
-
const
|
|
265
|
-
const
|
|
282
|
+
const wasHover = this.isHoverObject();
|
|
283
|
+
const isActive = this.isActiveObject();
|
|
266
284
|
const mouseDown = mouseIsDown(0);
|
|
267
|
-
|
|
285
|
+
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
286
|
+
if (!uiSystem.hoverObject)
|
|
287
|
+
if (mousePress || !mouseDown || isActive)
|
|
268
288
|
{
|
|
269
289
|
const size = this.size.add(vec2(isTouchDevice && this.extraTouchSize || 0));
|
|
270
|
-
|
|
290
|
+
if (isOverlapping(this.pos, size, mousePosScreen))
|
|
291
|
+
uiSystem.hoverObject = this;
|
|
271
292
|
}
|
|
272
|
-
if (this.
|
|
293
|
+
if (this.isHoverObject())
|
|
273
294
|
{
|
|
274
295
|
if (mousePress)
|
|
275
296
|
inputClearKey(0,0,0,1,0); // clear mouse was pressed state
|
|
@@ -282,10 +303,12 @@ class UIObject
|
|
|
282
303
|
this.onPress();
|
|
283
304
|
if (this.soundPress)
|
|
284
305
|
this.soundPress.play();
|
|
306
|
+
if (uiSystem.activeObject && !isActive)
|
|
307
|
+
uiSystem.activeObject.onRelease();
|
|
308
|
+
uiSystem.activeObject = this;
|
|
285
309
|
}
|
|
286
|
-
this.mouseIsHeld = true;
|
|
287
310
|
}
|
|
288
|
-
if (!mouseDown &&
|
|
311
|
+
if (!mouseDown && uiSystem.activeObject === this && this.interactive)
|
|
289
312
|
{
|
|
290
313
|
this.onClick();
|
|
291
314
|
if (this.soundClick)
|
|
@@ -293,37 +316,52 @@ class UIObject
|
|
|
293
316
|
}
|
|
294
317
|
}
|
|
295
318
|
}
|
|
296
|
-
if (!mouseDown)
|
|
319
|
+
if (isActive && (!mouseDown || !this.isHoverObject()))
|
|
297
320
|
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.
|
|
301
|
-
|
|
302
|
-
this.soundRelease.play();
|
|
303
|
-
}
|
|
304
|
-
if (isTouchDevice)
|
|
305
|
-
this.mouseIsOver = false;
|
|
306
|
-
this.mouseIsHeld = false;
|
|
321
|
+
this.onRelease();
|
|
322
|
+
if (this.soundRelease)
|
|
323
|
+
this.soundRelease.play();
|
|
324
|
+
uiSystem.activeObject = undefined;
|
|
307
325
|
}
|
|
308
326
|
|
|
309
|
-
if (this.
|
|
310
|
-
this.
|
|
327
|
+
if (this.isHoverObject() !== wasHover)
|
|
328
|
+
this.isHoverObject() ? this.onEnter() : this.onLeave();
|
|
311
329
|
}
|
|
312
330
|
|
|
313
331
|
/** Render the object, called automatically by plugin once each frame */
|
|
314
332
|
render()
|
|
315
333
|
{
|
|
316
|
-
if (this.size.x
|
|
317
|
-
|
|
334
|
+
if (!this.size.x || !this.size.y) return;
|
|
335
|
+
|
|
336
|
+
const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
|
|
337
|
+
const color = this.interactive ? this.disabled ? this.disabledColor : this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
|
|
338
|
+
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
318
339
|
}
|
|
319
340
|
|
|
320
341
|
/** Special update when object is not visible */
|
|
321
342
|
updateInvisible()
|
|
322
343
|
{
|
|
323
344
|
// reset input state when not visible
|
|
324
|
-
|
|
345
|
+
if (this.isActiveObject())
|
|
346
|
+
uiSystem.activeObject = undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Get the size for text with overrides and scale
|
|
350
|
+
* @return {Vector2}
|
|
351
|
+
*/
|
|
352
|
+
getTextSize()
|
|
353
|
+
{
|
|
354
|
+
return vec2(
|
|
355
|
+
this.textWidth || this.textScale * this.size.x,
|
|
356
|
+
this.textHeight || this.textScale * this.size.y);
|
|
325
357
|
}
|
|
326
358
|
|
|
359
|
+
/** @return {boolean} - Is the mouse hovering over this element */
|
|
360
|
+
isHoverObject() { return uiSystem.hoverObject === this; }
|
|
361
|
+
|
|
362
|
+
/** @return {boolean} - Is the mouse held onto this element */
|
|
363
|
+
isActiveObject() { return uiSystem.activeObject === this; }
|
|
364
|
+
|
|
327
365
|
/** Called when the mouse enters the object */
|
|
328
366
|
onEnter() {}
|
|
329
367
|
|
|
@@ -371,7 +409,7 @@ class UIText extends UIObject
|
|
|
371
409
|
}
|
|
372
410
|
render()
|
|
373
411
|
{
|
|
374
|
-
const textSize =
|
|
412
|
+
const textSize = this.getTextSize();
|
|
375
413
|
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
|
|
376
414
|
}
|
|
377
415
|
}
|
|
@@ -434,14 +472,10 @@ class UIButton extends UIObject
|
|
|
434
472
|
}
|
|
435
473
|
render()
|
|
436
474
|
{
|
|
437
|
-
|
|
438
|
-
const lineColor = this.mouseIsHeld && !this.disabled ? this.color : this.lineColor;
|
|
439
|
-
const color = this.disabled ? this.disabledColor : this.mouseIsOver ? this.hoverColor : this.color;
|
|
440
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
475
|
+
super.render();
|
|
441
476
|
|
|
442
|
-
// draw the text
|
|
443
|
-
const
|
|
444
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
477
|
+
// draw the text scaled to fit
|
|
478
|
+
const textSize = this.getTextSize();
|
|
445
479
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
446
480
|
this.textColor, 0, undefined, this.align, this.font);
|
|
447
481
|
}
|
|
@@ -479,8 +513,7 @@ class UICheckbox extends UIObject
|
|
|
479
513
|
}
|
|
480
514
|
render()
|
|
481
515
|
{
|
|
482
|
-
|
|
483
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
516
|
+
super.render();
|
|
484
517
|
if (this.checked)
|
|
485
518
|
{
|
|
486
519
|
const p = this.cornerRadius / min(this.size.x, this.size.y) * 2;
|
|
@@ -490,13 +523,11 @@ class UICheckbox extends UIObject
|
|
|
490
523
|
uiSystem.drawLine(this.pos.add(s.multiply(vec2(-1,1))), this.pos.add(s.multiply(vec2(1,-1))), this.lineWidth, this.lineColor);
|
|
491
524
|
}
|
|
492
525
|
|
|
493
|
-
// draw the text to the
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
497
|
-
const pos = this.pos.add(vec2(this.size.x*gapScale,0));
|
|
526
|
+
// draw the text next to the checkbox
|
|
527
|
+
const textSize = this.getTextSize();
|
|
528
|
+
const pos = this.pos.add(vec2(this.size.x,0));
|
|
498
529
|
uiSystem.drawText(this.text, pos, textSize,
|
|
499
|
-
this.textColor, 0, undefined, 'left', this.font);
|
|
530
|
+
this.textColor, 0, undefined, 'left', this.font, false);
|
|
500
531
|
}
|
|
501
532
|
}
|
|
502
533
|
|
|
@@ -532,7 +563,7 @@ class UIScrollbar extends UIObject
|
|
|
532
563
|
update()
|
|
533
564
|
{
|
|
534
565
|
super.update();
|
|
535
|
-
if (this.
|
|
566
|
+
if (this.isActiveObject() && this.interactive)
|
|
536
567
|
{
|
|
537
568
|
// check if value changed
|
|
538
569
|
const handleSize = vec2(this.size.y);
|
|
@@ -546,12 +577,7 @@ class UIScrollbar extends UIObject
|
|
|
546
577
|
}
|
|
547
578
|
render()
|
|
548
579
|
{
|
|
549
|
-
|
|
550
|
-
const lineColor = this.interactive && this.mouseIsHeld && !this.disabled ?
|
|
551
|
-
this.color : this.lineColor;
|
|
552
|
-
const color = this.disabled ? this.disabledColor :
|
|
553
|
-
this.interactive && this.mouseIsHeld ? this.hoverColor : this.color;
|
|
554
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
580
|
+
super.render();
|
|
555
581
|
|
|
556
582
|
// draw the scrollbar handle
|
|
557
583
|
const handleSize = vec2(this.size.y);
|
|
@@ -560,12 +586,11 @@ class UIScrollbar extends UIObject
|
|
|
560
586
|
const p2 = this.pos.x + handleWidth/2;
|
|
561
587
|
const handlePos = vec2(lerp(p1, p2, this.value), this.pos.y);
|
|
562
588
|
const handleColor = this.disabled ? this.disabledColor :
|
|
563
|
-
this.interactive && this.
|
|
589
|
+
this.interactive && this.isActiveObject() ? this.color : this.handleColor;
|
|
564
590
|
uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
565
591
|
|
|
566
|
-
// draw the text on the scrollbar
|
|
567
|
-
const
|
|
568
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
592
|
+
// draw the text scaled to fit on the scrollbar
|
|
593
|
+
const textSize = this.getTextSize();
|
|
569
594
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
570
595
|
this.textColor, 0, undefined, this.align, this.font);
|
|
571
596
|
}
|
package/reference.md
CHANGED
|
@@ -186,6 +186,7 @@ getCameraSize() // Get the camera's visible area in world space
|
|
|
186
186
|
// Display settings
|
|
187
187
|
canvasMaxSize = (1920, 1200) // The max size of the canvas
|
|
188
188
|
canvasFixedSize = (0, 0) // Fixed size of the canvas
|
|
189
|
+
canvasClearColor = BLACK // Color used to clear the canvas at start of frame
|
|
189
190
|
fontDefault = 'arial' // Default font used for text rendering
|
|
190
191
|
canvasPixelated = true // Use nearest neighbor canvas scaling for more pixelated look
|
|
191
192
|
tilesPixelated = true // Disable filtering for crisper pixel art
|
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.8';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -169,15 +169,15 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
169
169
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
170
170
|
if (!debugSpeedUp)
|
|
171
171
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp min framerate
|
|
172
|
-
if (debugVideoCaptureIsActive())
|
|
173
|
-
frameTimeBufferMS = 0; // no time smoothing when capturing video
|
|
174
|
-
updateCanvas();
|
|
175
172
|
|
|
176
173
|
if (paused)
|
|
177
174
|
{
|
|
175
|
+
updateCanvas();
|
|
176
|
+
|
|
178
177
|
// update object transforms even when paused
|
|
179
178
|
for (const o of engineObjects)
|
|
180
179
|
o.parent || o.updateTransforms();
|
|
180
|
+
|
|
181
181
|
inputUpdate();
|
|
182
182
|
pluginUpdateList.forEach(f=>f());
|
|
183
183
|
debugUpdate();
|
|
@@ -202,6 +202,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
202
202
|
time = frame++ / frameRate;
|
|
203
203
|
|
|
204
204
|
// update game and objects
|
|
205
|
+
updateCanvas();
|
|
205
206
|
inputUpdate();
|
|
206
207
|
gameUpdate();
|
|
207
208
|
pluginUpdateList.forEach(f=>f());
|
|
@@ -211,14 +212,23 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
211
212
|
debugUpdate();
|
|
212
213
|
gameUpdatePost();
|
|
213
214
|
inputUpdatePost();
|
|
215
|
+
|
|
216
|
+
if (debugVideoCaptureIsActive())
|
|
217
|
+
renderFrame();
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
// add the time smoothing back in
|
|
217
221
|
frameTimeBufferMS += deltaSmooth;
|
|
218
222
|
}
|
|
219
223
|
|
|
220
|
-
if (!
|
|
224
|
+
if (!debugVideoCaptureIsActive())
|
|
225
|
+
renderFrame();
|
|
226
|
+
requestAnimationFrame(engineUpdate);
|
|
227
|
+
|
|
228
|
+
function renderFrame()
|
|
221
229
|
{
|
|
230
|
+
if (headlessMode) return;
|
|
231
|
+
|
|
222
232
|
// render sort then render while removing destroyed objects
|
|
223
233
|
enginePreRender();
|
|
224
234
|
gameRender();
|
|
@@ -248,7 +258,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
248
258
|
}
|
|
249
259
|
drawCount = 0;
|
|
250
260
|
}
|
|
251
|
-
requestAnimationFrame(engineUpdate);
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
function updateCanvas()
|
|
@@ -274,6 +283,14 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
274
283
|
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
275
284
|
}
|
|
276
285
|
|
|
286
|
+
// apply the clear color to main canvas
|
|
287
|
+
if (canvasClearColor.a > 0)
|
|
288
|
+
{
|
|
289
|
+
mainContext.fillStyle = canvasClearColor.toString();
|
|
290
|
+
mainContext.fillRect(0, 0, mainCanvasSize.x, mainCanvasSize.y);
|
|
291
|
+
mainContext.fillStyle = BLACK.toString();
|
|
292
|
+
}
|
|
293
|
+
|
|
277
294
|
// clear overlay canvas and set size
|
|
278
295
|
overlayCanvas.width = mainCanvas.width;
|
|
279
296
|
overlayCanvas.height = mainCanvas.height;
|
package/src/engineDebug.js
CHANGED
|
@@ -524,7 +524,7 @@ function debugVideoCaptureStart()
|
|
|
524
524
|
const chunks = [];
|
|
525
525
|
debugVideoCaptureTrack = stream.getVideoTracks()[0];
|
|
526
526
|
if (debugVideoCaptureTrack.applyConstraints)
|
|
527
|
-
debugVideoCaptureTrack.applyConstraints({frameRate:
|
|
527
|
+
debugVideoCaptureTrack.applyConstraints({frameRate:60}); // force 60 fps
|
|
528
528
|
debugVideoCapture = new MediaRecorder(stream, {mimeType:'video/webm;codecs=vp8'});
|
|
529
529
|
debugVideoCapture.ondataavailable = (e)=> chunks.push(e.data);
|
|
530
530
|
debugVideoCapture.onstop = ()=>
|