littlejsengine 1.14.11 → 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.
Files changed (80) hide show
  1. package/dist/littlejs.d.ts +303 -137
  2. package/dist/littlejs.esm.js +936 -463
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +934 -462
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +859 -417
  7. package/examples/box2d/game.js +3 -2
  8. package/examples/box2d/gameObjects.js +2 -2
  9. package/examples/box2d/tiles.png +0 -0
  10. package/examples/breakout/game.js +5 -5
  11. package/examples/breakout/gameObjects.js +2 -2
  12. package/examples/breakoutTutorial/README.md +32 -32
  13. package/examples/breakoutTutorial/game.js +1 -1
  14. package/examples/electron/game.js +4 -4
  15. package/examples/electron/index.html +2 -2
  16. package/examples/electron/package.json +1 -8
  17. package/examples/index.html +67 -56
  18. package/examples/module/game.js +4 -4
  19. package/examples/platformer/gameEffects.js +5 -5
  20. package/examples/platformer/gameLevel.js +1 -1
  21. package/examples/platformer/gameObjects.js +4 -4
  22. package/examples/puzzle/game.js +1 -1
  23. package/examples/shorts/animation.js +1 -1
  24. package/examples/shorts/base.html +1 -1
  25. package/examples/shorts/blending.js +8 -14
  26. package/examples/shorts/box2d.js +7 -3
  27. package/examples/shorts/box2dCar.js +2 -1
  28. package/examples/shorts/empty.js +30 -0
  29. package/examples/shorts/helloWorld.js +1 -1
  30. package/examples/shorts/hillGlideGame.js +10 -4
  31. package/examples/shorts/landerGame.js +11 -8
  32. package/examples/shorts/medals.js +4 -4
  33. package/examples/shorts/music.js +29 -56
  34. package/examples/shorts/musicPlayer.js +135 -0
  35. package/examples/shorts/nineSlice.js +34 -15
  36. package/examples/shorts/parallax.js +5 -4
  37. package/examples/shorts/particles.js +15 -15
  38. package/examples/shorts/piano.js +15 -21
  39. package/examples/shorts/pongGame.js +6 -4
  40. package/examples/shorts/raycasting.js +9 -4
  41. package/examples/shorts/sequencer.js +122 -0
  42. package/examples/shorts/shader.js +29 -0
  43. package/examples/shorts/shapes.js +7 -4
  44. package/examples/shorts/slidingPuzzle.js +4 -2
  45. package/examples/shorts/sound.js +18 -9
  46. package/examples/shorts/spaceGame.js +12 -8
  47. package/examples/shorts/spriteAtlas.js +7 -7
  48. package/examples/shorts/starfield.js +1 -1
  49. package/examples/shorts/systemFont.js +2 -2
  50. package/examples/shorts/texture.js +2 -2
  51. package/examples/shorts/tileLayer.js +10 -10
  52. package/examples/shorts/tiltedView.js +24 -5
  53. package/examples/shorts/timers.js +10 -0
  54. package/examples/shorts/topDown.js +4 -1
  55. package/examples/shorts/uiSystem.js +8 -5
  56. package/examples/starter/game.js +4 -4
  57. package/examples/starter/index.html +2 -2
  58. package/examples/style.css +1 -0
  59. package/examples/typescript/game.js +4 -4
  60. package/examples/typescript/game.ts +4 -4
  61. package/examples/uiSystem/game.js +4 -3
  62. package/package.json +4 -2
  63. package/plugins/box2d.js +17 -2
  64. package/plugins/newgrounds.js +7 -5
  65. package/plugins/postProcess.js +76 -53
  66. package/plugins/uiSystem.js +192 -53
  67. package/plugins/zzfxm.js +5 -1
  68. package/reference.md +1 -1
  69. package/src/engine.js +60 -23
  70. package/src/engineAudio.js +44 -17
  71. package/src/engineDebug.js +75 -45
  72. package/src/engineDraw.js +94 -59
  73. package/src/engineExport.js +2 -1
  74. package/src/engineMedals.js +10 -2
  75. package/src/engineObject.js +14 -10
  76. package/src/engineParticles.js +60 -47
  77. package/src/engineSettings.js +7 -7
  78. package/src/engineTileLayer.js +73 -56
  79. package/src/engineUtilities.js +67 -20
  80. package/src/engineWebGL.js +134 -63
@@ -6,6 +6,7 @@
6
6
  * - Buttons
7
7
  * - Checkboxes
8
8
  * - Images
9
+ * @namespace UISystem
9
10
  */
10
11
 
11
12
  'use strict';
@@ -13,12 +14,14 @@
13
14
  ///////////////////////////////////////////////////////////////////////////////
14
15
 
15
16
  /** Global UI system plugin object
16
- * @type {UISystemPlugin} */
17
+ * @type {UISystemPlugin}
18
+ * @memberof UISystem */
17
19
  let uiSystem;
18
20
 
19
21
  ///////////////////////////////////////////////////////////////////////////////
20
22
  /**
21
23
  * UI System Global Object
24
+ * @memberof UISystem
22
25
  */
23
26
  class UISystemPlugin
24
27
  {
@@ -45,6 +48,8 @@ class UISystemPlugin
45
48
  this.defaultHoverColor = hsl(0,0,.9);
46
49
  /** @property {Color} - Default color for disabled UI elements */
47
50
  this.defaultDisabledColor = hsl(0,0,.3);
51
+ /** @property {Color} - Uses a gradient fill combined with color */
52
+ this.defaultGradientColor = undefined;
48
53
  /** @property {number} - Default line width for UI elements */
49
54
  this.defaultLineWidth = 4;
50
55
  /** @property {number} - Default rounded rect corner radius for UI elements */
@@ -52,7 +57,7 @@ class UISystemPlugin
52
57
  /** @property {number} - Default scale to use for fitting text to object */
53
58
  this.defaultTextScale = .8;
54
59
  /** @property {string} - Default font for UI elements */
55
- this.defaultFont = 'arial';
60
+ this.defaultFont = fontDefault;
56
61
  /** @property {Sound} - Default sound when interactive UI element is pressed */
57
62
  this.defaultSoundPress = undefined;
58
63
  /** @property {Sound} - Default sound when interactive UI element is released */
@@ -63,11 +68,15 @@ class UISystemPlugin
63
68
  this.uiObjects = [];
64
69
  /** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
65
70
  this.uiContext = context;
66
- /** @property {UIObject} - Top most object user is over */
67
- this.hoverObject = undefined;
68
71
  /** @property {UIObject} - Object user is currently interacting with */
69
72
  this.activeObject = undefined;
70
-
73
+ /** @property {UIObject} - Top most object user is over */
74
+ this.hoverObject = undefined;
75
+ /** @property {UIObject} - Hover object at start of update */
76
+ this.lastHoverObject = undefined;
77
+ /** @property {number} - If set ui coords will be renormalized to this canvas height */
78
+ this.nativeHeight = 0;
79
+
71
80
  engineAddPlugin(uiUpdate, uiRender);
72
81
 
73
82
  // setup recursive update and render
@@ -97,6 +106,7 @@ class UISystemPlugin
97
106
  updateInvisibleObject(o);
98
107
  }
99
108
  // reset hover object at start of update
109
+ uiSystem.lastHoverObject = uiSystem.hoverObject;
100
110
  uiSystem.hoverObject = undefined;
101
111
  for (let i = uiSystem.uiObjects.length; i--;)
102
112
  {
@@ -106,6 +116,17 @@ class UISystemPlugin
106
116
  }
107
117
  function uiRender()
108
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
+
109
130
  function renderObject(o)
110
131
  {
111
132
  if (!o.visible)
@@ -117,6 +138,7 @@ class UISystemPlugin
117
138
  renderObject(c);
118
139
  }
119
140
  uiSystem.uiObjects.forEach(o=> o.parent || renderObject(o));
141
+ context.restore();
120
142
  }
121
143
  }
122
144
 
@@ -126,11 +148,30 @@ class UISystemPlugin
126
148
  * @param {Color} [color=uiSystem.defaultColor]
127
149
  * @param {number} [lineWidth=uiSystem.defaultLineWidth]
128
150
  * @param {Color} [lineColor=uiSystem.defaultLineColor]
129
- * @param {number} [cornerRadius=uiSystem.defaultCornerRadius] */
130
- drawRect(pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, cornerRadius=uiSystem.defaultCornerRadius)
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)
131
154
  {
155
+ ASSERT(isVector2(pos), 'pos must be a vec2');
156
+ ASSERT(isVector2(size), 'size must be a vec2');
157
+ ASSERT(isColor(color), 'color must be a color');
158
+ ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
159
+ ASSERT(isColor(lineColor), 'lineColor must be a color');
160
+ ASSERT(isNumber(cornerRadius), 'cornerRadius must be a number');
161
+
132
162
  const context = uiSystem.uiContext;
133
- context.fillStyle = color.toString();
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();
134
175
  context.beginPath();
135
176
  if (cornerRadius && context['roundRect'])
136
177
  context['roundRect'](pos.x-size.x/2, pos.y-size.y/2, size.x, size.y, cornerRadius);
@@ -152,6 +193,11 @@ class UISystemPlugin
152
193
  * @param {Color} [lineColor=uiSystem.defaultLineColor] */
153
194
  drawLine(posA, posB, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor)
154
195
  {
196
+ ASSERT(isVector2(posA), 'posA must be a vec2');
197
+ ASSERT(isVector2(posB), 'posB must be a vec2');
198
+ ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
199
+ ASSERT(isColor(lineColor), 'lineColor must be a color');
200
+
155
201
  const context = uiSystem.uiContext;
156
202
  context.strokeStyle = lineColor.toString();
157
203
  context.lineWidth = lineWidth;
@@ -182,17 +228,43 @@ class UISystemPlugin
182
228
  * @param {Color} [lineColor=uiSystem.defaultLineColor]
183
229
  * @param {string} [align]
184
230
  * @param {string} [font=uiSystem.defaultFont]
231
+ * @param {string} [fontStyle]
185
232
  * @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)
233
+ drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, fontStyle='', applyMaxWidth=true)
234
+ {
235
+ drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, fontStyle, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
236
+ }
237
+
238
+ /**
239
+ * @callback DragAndDropCallback - Callback for drag and drop events
240
+ * @param {DragEvent} event - The drag event
241
+ * @memberof UISystem
242
+ */
243
+
244
+ /** Setup drag and drop event handlers
245
+ * Automatically prevents defaults and calls the given functions
246
+ * @param {DragAndDropCallback} [onDrop] - when a file is dropped
247
+ * @param {DragAndDropCallback} [onDragEnter] - when a file is dragged onto the window
248
+ * @param {DragAndDropCallback} [onDragLeave] - when a file is dragged off the window
249
+ * @param {DragAndDropCallback} [onDragOver] - continously when dragging over */
250
+ setupDragAndDrop(onDrop, onDragEnter, onDragLeave, onDragOver)
187
251
  {
188
- drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
252
+ function setCallback(callback, listenerType)
253
+ {
254
+ function listener(e) { e.preventDefault(); callback && callback(e); }
255
+ document.addEventListener(listenerType, listener);
256
+ }
257
+ setCallback(onDrop, 'drop');
258
+ setCallback(onDragEnter, 'dragenter');
259
+ setCallback(onDragLeave, 'dragleave');
260
+ setCallback(onDragOver, 'dragover');
189
261
  }
190
262
  }
191
263
 
192
264
  ///////////////////////////////////////////////////////////////////////////////
193
265
  /**
194
266
  * UI Object - Base level object for all UI elements
195
- */
267
+ * @memberof UISystem */
196
268
  class UIObject
197
269
  {
198
270
  /** Create a UIObject
@@ -201,6 +273,9 @@ class UIObject
201
273
  */
202
274
  constructor(pos=vec2(), size=vec2())
203
275
  {
276
+ ASSERT(isVector2(pos), 'ui object pos must be a vec2');
277
+ ASSERT(isVector2(size), 'ui object size must be a vec2');
278
+
204
279
  /** @property {Vector2} - Local position of the object */
205
280
  this.localPos = pos.copy();
206
281
  /** @property {Vector2} - Screen space position of the object */
@@ -208,27 +283,31 @@ class UIObject
208
283
  /** @property {Vector2} - Screen space size of the object */
209
284
  this.size = size.copy();
210
285
  /** @property {Color} - Color of the object */
211
- this.color = uiSystem.defaultColor;
286
+ this.color = uiSystem.defaultColor.copy();
212
287
  /** @property {Color} - Color of the object when active, uses color if undefined */
213
288
  this.activeColor = undefined;
214
289
  /** @property {string} - Text for this ui object */
215
290
  this.text = undefined;
216
291
  /** @property {Color} - Color when disabled */
217
- this.disabledColor = uiSystem.defaultDisabledColor;
292
+ this.disabledColor = uiSystem.defaultDisabledColor.copy();
218
293
  /** @property {boolean} - Is this object disabled? */
219
294
  this.disabled = false;
220
295
  /** @property {Color} - Color for text */
221
- this.textColor = uiSystem.defaultTextColor;
296
+ this.textColor = uiSystem.defaultTextColor.copy();
222
297
  /** @property {Color} - Color used when hovering over the object */
223
- this.hoverColor = uiSystem.defaultHoverColor;
298
+ this.hoverColor = uiSystem.defaultHoverColor.copy();
224
299
  /** @property {Color} - Color for line drawing */
225
- this.lineColor = uiSystem.defaultLineColor;
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;
226
303
  /** @property {number} - Width for line drawing */
227
304
  this.lineWidth = uiSystem.defaultLineWidth;
228
305
  /** @property {number} - Corner radius for rounded rects */
229
306
  this.cornerRadius = uiSystem.defaultCornerRadius;
230
307
  /** @property {string} - Font for this objecct */
231
308
  this.font = uiSystem.defaultFont;
309
+ /** @property {string} - Font style for this object or undefined */
310
+ this.fontStyle = undefined;
232
311
  /** @property {number} - Override for text width */
233
312
  this.textWidth = undefined;
234
313
  /** @property {number} - Override for text height */
@@ -253,6 +332,8 @@ class UIObject
253
332
  this.interactive = false;
254
333
  /** @property {boolean} - Activate when dragged over with mouse held down */
255
334
  this.dragActivate = false;
335
+ /** @property {boolean} - True if this can be a hover object */
336
+ this.canBeHover = true;
256
337
  uiSystem.uiObjects.push(this);
257
338
  }
258
339
 
@@ -276,31 +357,47 @@ class UIObject
276
357
  child.parent = undefined;
277
358
  }
278
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
+
279
380
  /** Update the object, called automatically by plugin once each frame */
280
381
  update()
281
382
  {
282
- const wasHover = this.isHoverObject();
383
+ const wasHover = uiSystem.lastHoverObject === this;
283
384
  const isActive = this.isActiveObject();
284
385
  const mouseDown = mouseIsDown(0);
285
386
  const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
286
- if (!uiSystem.hoverObject)
387
+ if (this.canBeHover)
287
388
  if (mousePress || isActive || (!mouseDown && !isTouchDevice))
288
- {
289
- const size = this.size.add(vec2(isTouchDevice && this.extraTouchSize || 0));
290
- if (isOverlapping(this.pos, size, mousePosScreen))
291
- uiSystem.hoverObject = this;
292
- }
389
+ if (!uiSystem.hoverObject && this.isMouseOverlapping())
390
+ uiSystem.hoverObject = this;
293
391
  if (this.isHoverObject())
294
392
  {
295
- if (mousePress)
296
- inputClearKey(0,0,0,1,0); // clear mouse was pressed state
297
393
  if (!this.disabled)
298
394
  {
299
395
  if (mousePress)
300
396
  {
301
397
  if (this.interactive)
302
398
  {
303
- this.onPress();
399
+ if (!this.dragActivate || (!wasHover || mouseWasPressed(0)))
400
+ this.onPress();
304
401
  if (this.soundPress)
305
402
  this.soundPress.play();
306
403
  if (uiSystem.activeObject && !isActive)
@@ -308,13 +405,15 @@ class UIObject
308
405
  uiSystem.activeObject = this;
309
406
  }
310
407
  }
311
- if (!mouseDown && uiSystem.activeObject === this && this.interactive)
408
+ if (!mouseDown && this.isActiveObject() && this.interactive)
312
409
  {
313
410
  this.onClick();
314
411
  if (this.soundClick)
315
412
  this.soundClick.play();
316
413
  }
317
414
  }
415
+ // clear mouse was pressed state even when disabled
416
+ mousePress && inputClearKey(0,0,0,1,0);
318
417
  }
319
418
  if (isActive)
320
419
  if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
@@ -325,6 +424,7 @@ class UIObject
325
424
  uiSystem.activeObject = undefined;
326
425
  }
327
426
 
427
+ // call enter/leave events
328
428
  if (this.isHoverObject() !== wasHover)
329
429
  this.isHoverObject() ? this.onEnter() : this.onLeave();
330
430
  }
@@ -335,7 +435,7 @@ class UIObject
335
435
  if (!this.size.x || !this.size.y) return;
336
436
 
337
437
  const lineColor = this.interactive && this.isActiveObject() && !this.disabled ? this.color : this.lineColor;
338
- const color = this.interactive ? this.disabled ? this.disabledColor : this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
438
+ const color = this.disabled ? this.disabledColor : this.interactive ? this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
339
439
  uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
340
440
  }
341
441
 
@@ -386,6 +486,7 @@ class UIObject
386
486
  /**
387
487
  * UIText - A UI object that displays text
388
488
  * @extends UIObject
489
+ * @memberof UISystem
389
490
  */
390
491
  class UIText extends UIObject
391
492
  {
@@ -400,6 +501,10 @@ class UIText extends UIObject
400
501
  {
401
502
  super(pos, size);
402
503
 
504
+ ASSERT(isString(text), 'ui text must be a string');
505
+ ASSERT(['left','center','right'].includes(align), 'ui text align must be left, center, or right');
506
+ ASSERT(isString(font), 'ui text font must be a string');
507
+
403
508
  // set properties
404
509
  this.text = text;
405
510
  this.align = align;
@@ -407,11 +512,13 @@ class UIText extends UIObject
407
512
 
408
513
  // make text not outlined by default
409
514
  this.lineWidth = 0;
515
+ // text can not be a hover object by default
516
+ this.canBeHover = false;
410
517
  }
411
518
  render()
412
519
  {
413
520
  const textSize = this.getTextSize();
414
- 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);
415
522
  }
416
523
  }
417
524
 
@@ -419,6 +526,7 @@ class UIText extends UIObject
419
526
  /**
420
527
  * UITile - A UI object that displays a tile image
421
528
  * @extends UIObject
529
+ * @memberof UISystem
422
530
  */
423
531
  class UITile extends UIObject
424
532
  {
@@ -433,15 +541,19 @@ class UITile extends UIObject
433
541
  constructor(pos, size, tileInfo, color=WHITE, angle=0, mirror=false)
434
542
  {
435
543
  super(pos, size);
544
+
545
+ ASSERT(tileInfo instanceof TileInfo, 'ui tile tileInfo must be a TileInfo');
546
+ ASSERT(isColor(color), 'ui tile color must be a color');
547
+ ASSERT(isNumber(angle), 'ui tile angle must be a number');
548
+
436
549
  /** @property {TileInfo} - Tile image to use */
437
550
  this.tileInfo = tileInfo;
438
551
  /** @property {number} - Angle to rotate in radians */
439
552
  this.angle = angle;
440
553
  /** @property {boolean} - Should it be mirrored? */
441
554
  this.mirror = mirror;
442
-
443
555
  // set properties
444
- this.color = color;
556
+ this.color = color.copy();
445
557
  }
446
558
  render()
447
559
  {
@@ -453,6 +565,7 @@ class UITile extends UIObject
453
565
  /**
454
566
  * UIButton - A UI object that acts as a button
455
567
  * @extends UIObject
568
+ * @memberof UISystem
456
569
  */
457
570
  class UIButton extends UIObject
458
571
  {
@@ -466,9 +579,12 @@ class UIButton extends UIObject
466
579
  {
467
580
  super(pos, size);
468
581
 
582
+ ASSERT(isString(text), 'ui button must be a string');
583
+ ASSERT(isColor(color), 'ui button color must be a color');
584
+
469
585
  // set properties
470
586
  this.text = text;
471
- this.color = color;
587
+ this.color = color.copy();
472
588
  this.interactive = true;
473
589
  }
474
590
  render()
@@ -478,7 +594,7 @@ class UIButton extends UIObject
478
594
  // draw the text scaled to fit
479
595
  const textSize = this.getTextSize();
480
596
  uiSystem.drawText(this.text, this.pos, textSize,
481
- this.textColor, 0, undefined, this.align, this.font);
597
+ this.textColor, 0, undefined, this.align, this.font, this.fontStyle);
482
598
  }
483
599
  }
484
600
 
@@ -486,6 +602,7 @@ class UIButton extends UIObject
486
602
  /**
487
603
  * UICheckbox - A UI object that acts as a checkbox
488
604
  * @extends UIObject
605
+ * @memberof UISystem
489
606
  */
490
607
  class UICheckbox extends UIObject
491
608
  {
@@ -499,12 +616,15 @@ class UICheckbox extends UIObject
499
616
  constructor(pos, size, checked=false, text='', color=uiSystem.defaultButtonColor)
500
617
  {
501
618
  super(pos, size);
619
+
620
+ ASSERT(isString(text), 'ui checkbox must be a string');
621
+ ASSERT(isColor(color), 'ui checkbox color must be a color');
622
+
502
623
  /** @property {boolean} - Current percentage value of this scrollbar 0-1 */
503
624
  this.checked = checked;
504
-
505
625
  // set properties
506
626
  this.text = text;
507
- this.color = color;
627
+ this.color = color.copy();
508
628
  this.interactive = true;
509
629
  }
510
630
  onClick()
@@ -528,7 +648,7 @@ class UICheckbox extends UIObject
528
648
  const textSize = this.getTextSize();
529
649
  const pos = this.pos.add(vec2(this.size.x,0));
530
650
  uiSystem.drawText(this.text, pos, textSize,
531
- this.textColor, 0, undefined, 'left', this.font, false);
651
+ this.textColor, 0, undefined, 'left', this.font, this.fontStyle, false);
532
652
  }
533
653
  }
534
654
 
@@ -536,6 +656,7 @@ class UICheckbox extends UIObject
536
656
  /**
537
657
  * UIScrollbar - A UI object that acts as a scrollbar
538
658
  * @extends UIObject
659
+ * @memberof UISystem
539
660
  */
540
661
  class UIScrollbar extends UIObject
541
662
  {
@@ -551,14 +672,19 @@ class UIScrollbar extends UIObject
551
672
  {
552
673
  super(pos, size);
553
674
 
675
+ ASSERT(isNumber(value), 'ui scrollbar value must be a number');
676
+ ASSERT(isString(text), 'ui scrollbar must be a string');
677
+ ASSERT(isColor(color), 'ui scrollbar color must be a color');
678
+ ASSERT(isColor(handleColor), 'ui scrollbar handleColor must be a color');
679
+
554
680
  /** @property {number} - Current percentage value of this scrollbar 0-1 */
555
681
  this.value = value;
556
682
  /** @property {Color} - Color for the handle part of the scrollbar */
557
- this.handleColor = handleColor;
683
+ this.handleColor = handleColor.copy();
558
684
 
559
685
  // set properties
560
686
  this.text = text;
561
- this.color = color;
687
+ this.color = color.copy();
562
688
  this.interactive = true;
563
689
  }
564
690
  update()
@@ -566,33 +692,46 @@ class UIScrollbar extends UIObject
566
692
  super.update();
567
693
  if (this.isActiveObject() && this.interactive)
568
694
  {
695
+ // handle horizontal or vertical scrollbar
696
+ const isHorizontal = this.size.x > this.size.y;
697
+ const handleSize = isHorizontal ? this.size.y : this.size.x;
698
+ const barSize = isHorizontal ? this.size.x : this.size.y;
699
+ const centerPos = isHorizontal ? this.pos.x : this.pos.y;
700
+
569
701
  // check if value changed
570
- const handleSize = vec2(this.size.y);
571
- const handleWidth = this.size.x - handleSize.x;
572
- const p1 = this.pos.x - handleWidth/2;
573
- const p2 = this.pos.x + handleWidth/2;
702
+ const handleWidth = barSize - handleSize;
703
+ const p1 = centerPos - handleWidth/2;
704
+ const p2 = centerPos + handleWidth/2;
574
705
  const oldValue = this.value;
575
- this.value = percent(mousePosScreen.x, p1, p2);
706
+ this.value = isHorizontal ?
707
+ percent(mousePosScreen.x, p1, p2) :
708
+ percent(mousePosScreen.y, p2, p1);
576
709
  this.value === oldValue || this.onChange();
577
710
  }
578
711
  }
579
712
  render()
580
713
  {
581
714
  super.render();
582
-
715
+
716
+ // handle horizontal or vertical scrollbar
717
+ const isHorizontal = this.size.x > this.size.y;
718
+ const handleSize = isHorizontal ? this.size.y : this.size.x;
719
+ const barSize = isHorizontal ? this.size.x : this.size.y;
720
+ const centerPos = isHorizontal ? this.pos.x : this.pos.y;
721
+
583
722
  // draw the scrollbar handle
584
- const handleSize = vec2(this.size.y);
585
- const handleWidth = this.size.x - handleSize.x;
586
- const p1 = this.pos.x - handleWidth/2;
587
- const p2 = this.pos.x + handleWidth/2;
588
- const handlePos = vec2(lerp(p1, p2, this.value), this.pos.y);
589
- const handleColor = this.disabled ? this.disabledColor :
590
- this.interactive && this.isActiveObject() ? this.color : this.handleColor;
591
- uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
723
+ const handleWidth = barSize - handleSize;
724
+ const p1 = centerPos - handleWidth/2;
725
+ const p2 = centerPos + handleWidth/2;
726
+ const handlePos = isHorizontal ?
727
+ vec2(lerp(p1, p2, this.value), this.pos.y) :
728
+ vec2(this.pos.x, lerp(p2, p1, this.value))
729
+ const handleColor = this.disabled ? this.disabledColor : this.handleColor;
730
+ uiSystem.drawRect(handlePos, vec2(handleSize), handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
592
731
 
593
732
  // draw the text scaled to fit on the scrollbar
594
733
  const textSize = this.getTextSize();
595
734
  uiSystem.drawText(this.text, this.pos, textSize,
596
- this.textColor, 0, undefined, this.align, this.font);
735
+ this.textColor, 0, undefined, this.align, this.font, this.fontStyle);
597
736
  }
598
737
  }
package/plugins/zzfxm.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * LittleJS ZzFXM Plugin
3
+ * @namespace ZzFXM
3
4
  */
4
5
 
5
6
  'use strict';
@@ -8,6 +9,8 @@
8
9
  * Music Object - Stores a zzfx music track for later use
9
10
  *
10
11
  * <a href=https://keithclark.github.io/ZzFXM/>Create music with the ZzFXM tracker.</a>
12
+ * @extends Sound
13
+ * @memberof ZzFXM
11
14
  * @example
12
15
  * // create some music
13
16
  * const music_example = new Music(
@@ -66,7 +69,8 @@ class ZzFXMusic extends Sound
66
69
  * @param {Array} patterns - Array of pattern data
67
70
  * @param {Array} sequence - Array of pattern indexes
68
71
  * @param {number} [BPM] - Playback speed of the song in BPM
69
- * @return {Array} - Left and right channel sample data */
72
+ * @return {Array} - Left and right channel sample data
73
+ * @memberof ZzFXM */
70
74
  function zzfxM(instruments, patterns, sequence, BPM = 125)
71
75
  {
72
76
  let i, j, k;
package/reference.md CHANGED
@@ -399,7 +399,7 @@ TileCollisionLayer.setCollisionData(pos, data=1) // Set tile collision data a
399
399
  tileCollisionGetData(pos) // Get tile collision data at pos
400
400
  tileCollisionTest(pos, size=(0,0), object) // Check if collision should occur
401
401
  tileCollisionRaycast(posStart, posEnd, object) // Return the center of tile if hit
402
- tileCollisionLoad(tileMapData, tileInfo) // Load tile layers from exported data
402
+ tileLayersLoad(tileMapData, tileInfo) // Load tile layers from exported data
403
403
 
404
404
  ```
405
405