littlejsengine 1.14.11 → 1.14.16

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 (74) hide show
  1. package/dist/littlejs.d.ts +252 -109
  2. package/dist/littlejs.esm.js +559 -252
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +557 -251
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +482 -206
  7. package/examples/box2d/gameObjects.js +2 -2
  8. package/examples/breakout/gameObjects.js +2 -2
  9. package/examples/breakoutTutorial/README.md +32 -32
  10. package/examples/breakoutTutorial/game.js +1 -1
  11. package/examples/electron/game.js +3 -3
  12. package/examples/electron/index.html +2 -2
  13. package/examples/electron/package.json +1 -8
  14. package/examples/index.html +10 -7
  15. package/examples/module/game.js +3 -3
  16. package/examples/platformer/gameEffects.js +4 -4
  17. package/examples/platformer/gameLevel.js +1 -1
  18. package/examples/platformer/gameObjects.js +4 -4
  19. package/examples/puzzle/game.js +1 -1
  20. package/examples/shorts/animation.js +1 -1
  21. package/examples/shorts/base.html +1 -1
  22. package/examples/shorts/blending.js +8 -14
  23. package/examples/shorts/box2d.js +7 -3
  24. package/examples/shorts/box2dCar.js +2 -1
  25. package/examples/shorts/empty.js +30 -0
  26. package/examples/shorts/helloWorld.js +1 -1
  27. package/examples/shorts/hillGlideGame.js +10 -4
  28. package/examples/shorts/landerGame.js +11 -8
  29. package/examples/shorts/medals.js +4 -4
  30. package/examples/shorts/music.js +29 -56
  31. package/examples/shorts/musicPlayer.js +134 -0
  32. package/examples/shorts/nineSlice.js +34 -15
  33. package/examples/shorts/parallax.js +4 -3
  34. package/examples/shorts/particles.js +15 -15
  35. package/examples/shorts/piano.js +15 -21
  36. package/examples/shorts/pongGame.js +6 -4
  37. package/examples/shorts/raycasting.js +9 -4
  38. package/examples/shorts/sequencer.js +122 -0
  39. package/examples/shorts/shapes.js +7 -4
  40. package/examples/shorts/slidingPuzzle.js +4 -2
  41. package/examples/shorts/sound.js +18 -9
  42. package/examples/shorts/spaceGame.js +12 -8
  43. package/examples/shorts/spriteAtlas.js +7 -7
  44. package/examples/shorts/starfield.js +1 -1
  45. package/examples/shorts/systemFont.js +2 -2
  46. package/examples/shorts/texture.js +2 -2
  47. package/examples/shorts/tileLayer.js +10 -10
  48. package/examples/shorts/tiltedView.js +14 -3
  49. package/examples/shorts/timers.js +10 -0
  50. package/examples/shorts/topDown.js +4 -1
  51. package/examples/shorts/uiSystem.js +8 -5
  52. package/examples/starter/game.js +3 -3
  53. package/examples/starter/index.html +2 -2
  54. package/examples/typescript/game.js +3 -3
  55. package/examples/typescript/game.ts +3 -3
  56. package/examples/uiSystem/game.js +3 -3
  57. package/package.json +4 -2
  58. package/plugins/box2d.js +17 -2
  59. package/plugins/newgrounds.js +7 -5
  60. package/plugins/postProcess.js +5 -2
  61. package/plugins/uiSystem.js +120 -34
  62. package/plugins/zzfxm.js +5 -1
  63. package/reference.md +1 -1
  64. package/src/engine.js +35 -12
  65. package/src/engineAudio.js +31 -14
  66. package/src/engineDebug.js +75 -45
  67. package/src/engineDraw.js +60 -31
  68. package/src/engineExport.js +2 -1
  69. package/src/engineMedals.js +10 -2
  70. package/src/engineObject.js +14 -10
  71. package/src/engineParticles.js +59 -46
  72. package/src/engineSettings.js +7 -7
  73. package/src/engineTileLayer.js +45 -20
  74. package/src/engineUtilities.js +67 -20
package/plugins/box2d.js CHANGED
@@ -39,6 +39,7 @@ function box2dSetDebug(enable) { box2dDebug = enable; }
39
39
  * - Each object has a Box2D body which can have multiple fixtures and joints
40
40
  * - Provides interface for Box2D body and fixture functions
41
41
  * @extends EngineObject
42
+ * @memberof Box2D
42
43
  */
43
44
  class Box2dObject extends EngineObject
44
45
  {
@@ -50,7 +51,7 @@ class Box2dObject extends EngineObject
50
51
  * @param {Color} [color]
51
52
  * @param {number} [bodyType]
52
53
  * @param {number} [renderOrder] */
53
- constructor(pos=vec2(), size, tileInfo, angle=0, color, bodyType=box2d.bodyTypeDynamic, renderOrder=0)
54
+ constructor(pos, size, tileInfo, angle=0, color, bodyType=box2d.bodyTypeDynamic, renderOrder=0)
54
55
  {
55
56
  super(pos, size, tileInfo, angle, color, renderOrder);
56
57
 
@@ -64,7 +65,7 @@ class Box2dObject extends EngineObject
64
65
  this.lineColor = BLACK;
65
66
  }
66
67
 
67
- /** Destroy this object and it's physics body */
68
+ /** Destroy this object and its physics body */
68
69
  destroy()
69
70
  {
70
71
  // destroy physics body, fixtures, and joints
@@ -548,6 +549,7 @@ class Box2dRaycastResult
548
549
  * Box2D Joint
549
550
  * - Base class for Box2D joints
550
551
  * - A joint is used to connect objects together
552
+ * @memberof Box2D
551
553
  */
552
554
  class Box2dJoint
553
555
  {
@@ -603,6 +605,7 @@ class Box2dJoint
603
605
  * - This a soft constraint with a max force
604
606
  * - This allows the constraint to stretch and without applying huge forces
605
607
  * @extends Box2dJoint
608
+ * @memberof Box2D
606
609
  */
607
610
  class Box2dTargetJoint extends Box2dJoint
608
611
  {
@@ -652,6 +655,7 @@ class Box2dTargetJoint extends Box2dJoint
652
655
  * - Constrains two points on two objects to remain at a fixed distance
653
656
  * - You can view this as a massless, rigid rod
654
657
  * @extends Box2dJoint
658
+ * @memberof Box2D
655
659
  */
656
660
  class Box2dDistanceJoint extends Box2dJoint
657
661
  {
@@ -715,6 +719,7 @@ class Box2dDistanceJoint extends Box2dJoint
715
719
  * Box2D Pin Joint
716
720
  * - Pins two objects together at a point
717
721
  * @extends Box2dDistanceJoint
722
+ * @memberof Box2D
718
723
  */
719
724
  class Box2dPinJoint extends Box2dDistanceJoint
720
725
  {
@@ -734,6 +739,7 @@ class Box2dPinJoint extends Box2dDistanceJoint
734
739
  * Box2D Rope Joint
735
740
  * - Enforces a maximum distance between two points on two objects
736
741
  * @extends Box2dJoint
742
+ * @memberof Box2D
737
743
  */
738
744
  class Box2dRopeJoint extends Box2dJoint
739
745
  {
@@ -786,6 +792,7 @@ class Box2dRopeJoint extends Box2dJoint
786
792
  * - You can use a motor to drive the relative rotation about the shared point
787
793
  * - A maximum motor torque is provided so that infinite forces are not generated
788
794
  * @extends Box2dJoint
795
+ * @memberof Box2D
789
796
  */
790
797
  class Box2dRevoluteJoint extends Box2dJoint
791
798
  {
@@ -887,6 +894,7 @@ class Box2dRevoluteJoint extends Box2dJoint
887
894
  * - Either joint can be a revolute or prismatic joint
888
895
  * - You specify a gear ratio to bind the motions together
889
896
  * @extends Box2dJoint
897
+ * @memberof Box2D
890
898
  */
891
899
  class Box2dGearJoint extends Box2dJoint
892
900
  {
@@ -935,6 +943,7 @@ class Box2dGearJoint extends Box2dJoint
935
943
  * - You can use a joint limit to restrict the range of motion
936
944
  * - You can use a joint motor to drive the motion or to model joint friction
937
945
  * @extends Box2dJoint
946
+ * @memberof Box2D
938
947
  */
939
948
  class Box2dPrismaticJoint extends Box2dJoint
940
949
  {
@@ -1044,6 +1053,7 @@ class Box2dPrismaticJoint extends Box2dJoint
1044
1053
  * - You can use a joint motor to drive the motion or to model joint friction
1045
1054
  * - This joint is designed for vehicle suspensions
1046
1055
  * @extends Box2dJoint
1056
+ * @memberof Box2D
1047
1057
  */
1048
1058
  class Box2dWheelJoint extends Box2dJoint
1049
1059
  {
@@ -1139,6 +1149,7 @@ class Box2dWheelJoint extends Box2dJoint
1139
1149
  * Box2D Weld Joint
1140
1150
  * - Glues two objects together
1141
1151
  * @extends Box2dJoint
1152
+ * @memberof Box2D
1142
1153
  */
1143
1154
  class Box2dWeldJoint extends Box2dJoint
1144
1155
  {
@@ -1197,6 +1208,7 @@ class Box2dWeldJoint extends Box2dJoint
1197
1208
  * - Used to apply top-down friction
1198
1209
  * - Provides 2D translational friction and angular friction
1199
1210
  * @extends Box2dJoint
1211
+ * @memberof Box2D
1200
1212
  */
1201
1213
  class Box2dFrictionJoint extends Box2dJoint
1202
1214
  {
@@ -1251,6 +1263,7 @@ class Box2dFrictionJoint extends Box2dJoint
1251
1263
  * - The pulley supports a ratio such that: length1 + ratio * length2 <= constant
1252
1264
  * - The force transmitted is scaled by the ratio
1253
1265
  * @extends Box2dJoint
1266
+ * @memberof Box2D
1254
1267
  */
1255
1268
  class Box2dPulleyJoint extends Box2dJoint
1256
1269
  {
@@ -1318,6 +1331,7 @@ class Box2dPulleyJoint extends Box2dJoint
1318
1331
  * - Controls the relative motion between two objects
1319
1332
  * - Typical usage is to control the movement of a object with respect to the ground
1320
1333
  * @extends Box2dJoint
1334
+ * @memberof Box2D
1321
1335
  */
1322
1336
  class Box2dMotorJoint extends Box2dJoint
1323
1337
  {
@@ -1381,6 +1395,7 @@ class Box2dMotorJoint extends Box2dJoint
1381
1395
  /**
1382
1396
  * Box2D Global Object
1383
1397
  * - Wraps Box2d world and provides global functions
1398
+ * @memberof Box2D
1384
1399
  */
1385
1400
  class Box2dPlugin
1386
1401
  {
@@ -1,24 +1,25 @@
1
1
  /**
2
- * LittleJS Newgrounds API
2
+ * LittleJS Newgrounds Plugin
3
3
  * - NewgroundsMedal extends Medal with Newgrounds API functionality
4
- * - Call new NewgroundsPlugin() to setup Newgrounds
4
+ * - Call new NewgroundsPlugin(app_id) to setup Newgrounds
5
5
  * - Uses CryptoJS for encryption if optional cipher is provided
6
+ * - provides functions to interact with medals scoreboards
6
7
  * - Keeps connection alive and logs views
7
- * - Functions to interact with scoreboards
8
- * - Functions to unlock medals
8
+ * @namespace Newgrounds
9
9
  */
10
10
 
11
11
  'use strict';
12
12
 
13
13
  /** Global Newgrounds object
14
14
  * @type {NewgroundsPlugin}
15
- * @memberof Medal */
15
+ * @memberof Newgrounds */
16
16
  let newgrounds;
17
17
 
18
18
  ///////////////////////////////////////////////////////////////////////////////
19
19
  /**
20
20
  * Newgrounds medal auto unlocks in newgrounds API
21
21
  * @extends Medal
22
+ * @memberof Newgrounds
22
23
  */
23
24
  class NewgroundsMedal extends Medal
24
25
  {
@@ -43,6 +44,7 @@ class NewgroundsMedal extends Medal
43
44
  ///////////////////////////////////////////////////////////////////////////////
44
45
  /**
45
46
  * Newgrounds API object
47
+ * @memberof Newgrounds
46
48
  */
47
49
  class NewgroundsPlugin
48
50
  {
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * LittleJS Post Processing Plugin
3
3
  * - Supports shadertoy style post processing shaders
4
- * - call new new PostProcessPlugin() to setup post processing
4
+ * - call new PostProcessPlugin() to setup post processing
5
5
  * - can be enabled to pass other canvases through a final shader
6
+ * @namespace PostProcess
6
7
  */
7
8
 
8
9
  'use strict';
@@ -10,12 +11,14 @@
10
11
  ///////////////////////////////////////////////////////////////////////////////
11
12
 
12
13
  /** Global Post Process plugin object
13
- * @type {PostProcessPlugin} */
14
+ * @type {PostProcessPlugin}
15
+ * @memberof PostProcess */
14
16
  let postProcess;
15
17
 
16
18
  /////////////////////////////////////////////////////////////////////////
17
19
  /**
18
20
  * UI System Global Object
21
+ * @memberof PostProcess
19
22
  */
20
23
  class PostProcessPlugin
21
24
  {
@@ -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
  {
@@ -63,10 +66,12 @@ class UISystemPlugin
63
66
  this.uiObjects = [];
64
67
  /** @property {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} - Context to render UI elements to */
65
68
  this.uiContext = context;
66
- /** @property {UIObject} - Top most object user is over */
67
- this.hoverObject = undefined;
68
69
  /** @property {UIObject} - Object user is currently interacting with */
69
70
  this.activeObject = undefined;
71
+ /** @property {UIObject} - Top most object user is over */
72
+ this.hoverObject = undefined;
73
+ /** @property {UIObject} - Hover object at start of update */
74
+ this.lastHoverObject = undefined;
70
75
 
71
76
  engineAddPlugin(uiUpdate, uiRender);
72
77
 
@@ -97,6 +102,7 @@ class UISystemPlugin
97
102
  updateInvisibleObject(o);
98
103
  }
99
104
  // reset hover object at start of update
105
+ uiSystem.lastHoverObject = uiSystem.hoverObject;
100
106
  uiSystem.hoverObject = undefined;
101
107
  for (let i = uiSystem.uiObjects.length; i--;)
102
108
  {
@@ -129,6 +135,13 @@ class UISystemPlugin
129
135
  * @param {number} [cornerRadius=uiSystem.defaultCornerRadius] */
130
136
  drawRect(pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, cornerRadius=uiSystem.defaultCornerRadius)
131
137
  {
138
+ ASSERT(isVector2(pos), 'pos must be a vec2');
139
+ ASSERT(isVector2(size), 'size must be a vec2');
140
+ ASSERT(isColor(color), 'color must be a color');
141
+ ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
142
+ ASSERT(isColor(lineColor), 'lineColor must be a color');
143
+ ASSERT(isNumber(cornerRadius), 'cornerRadius must be a number');
144
+
132
145
  const context = uiSystem.uiContext;
133
146
  context.fillStyle = color.toString();
134
147
  context.beginPath();
@@ -152,6 +165,11 @@ class UISystemPlugin
152
165
  * @param {Color} [lineColor=uiSystem.defaultLineColor] */
153
166
  drawLine(posA, posB, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor)
154
167
  {
168
+ ASSERT(isVector2(posA), 'posA must be a vec2');
169
+ ASSERT(isVector2(posB), 'posB must be a vec2');
170
+ ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
171
+ ASSERT(isColor(lineColor), 'lineColor must be a color');
172
+
155
173
  const context = uiSystem.uiContext;
156
174
  context.strokeStyle = lineColor.toString();
157
175
  context.lineWidth = lineWidth;
@@ -187,12 +205,37 @@ class UISystemPlugin
187
205
  {
188
206
  drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
189
207
  }
208
+
209
+ /**
210
+ * @callback DragAndDropCallback - Callback for drag and drop events
211
+ * @param {DragEvent} event - The drag event
212
+ * @memberof UISystem
213
+ */
214
+
215
+ /** Setup drag and drop event handlers
216
+ * Automatically prevents defaults and calls the given functions
217
+ * @param {DragAndDropCallback} [onDrop] - when a file is dropped
218
+ * @param {DragAndDropCallback} [onDragEnter] - when a file is dragged onto the window
219
+ * @param {DragAndDropCallback} [onDragLeave] - when a file is dragged off the window
220
+ * @param {DragAndDropCallback} [onDragOver] - continously when dragging over */
221
+ setupDragAndDrop(onDrop, onDragEnter, onDragLeave, onDragOver)
222
+ {
223
+ function setCallback(callback, listenerType)
224
+ {
225
+ function listener(e) { e.preventDefault(); callback && callback(e); }
226
+ document.addEventListener(listenerType, listener);
227
+ }
228
+ setCallback(onDrop, 'drop');
229
+ setCallback(onDragEnter, 'dragenter');
230
+ setCallback(onDragLeave, 'dragleave');
231
+ setCallback(onDragOver, 'dragover');
232
+ }
190
233
  }
191
234
 
192
235
  ///////////////////////////////////////////////////////////////////////////////
193
236
  /**
194
237
  * UI Object - Base level object for all UI elements
195
- */
238
+ * @memberof UISystem */
196
239
  class UIObject
197
240
  {
198
241
  /** Create a UIObject
@@ -201,6 +244,9 @@ class UIObject
201
244
  */
202
245
  constructor(pos=vec2(), size=vec2())
203
246
  {
247
+ ASSERT(isVector2(pos), 'ui object pos must be a vec2');
248
+ ASSERT(isVector2(size), 'ui object size must be a vec2');
249
+
204
250
  /** @property {Vector2} - Local position of the object */
205
251
  this.localPos = pos.copy();
206
252
  /** @property {Vector2} - Screen space position of the object */
@@ -208,21 +254,21 @@ class UIObject
208
254
  /** @property {Vector2} - Screen space size of the object */
209
255
  this.size = size.copy();
210
256
  /** @property {Color} - Color of the object */
211
- this.color = uiSystem.defaultColor;
257
+ this.color = uiSystem.defaultColor.copy();
212
258
  /** @property {Color} - Color of the object when active, uses color if undefined */
213
259
  this.activeColor = undefined;
214
260
  /** @property {string} - Text for this ui object */
215
261
  this.text = undefined;
216
262
  /** @property {Color} - Color when disabled */
217
- this.disabledColor = uiSystem.defaultDisabledColor;
263
+ this.disabledColor = uiSystem.defaultDisabledColor.copy();
218
264
  /** @property {boolean} - Is this object disabled? */
219
265
  this.disabled = false;
220
266
  /** @property {Color} - Color for text */
221
- this.textColor = uiSystem.defaultTextColor;
267
+ this.textColor = uiSystem.defaultTextColor.copy()
222
268
  /** @property {Color} - Color used when hovering over the object */
223
- this.hoverColor = uiSystem.defaultHoverColor;
269
+ this.hoverColor = uiSystem.defaultHoverColor.copy()
224
270
  /** @property {Color} - Color for line drawing */
225
- this.lineColor = uiSystem.defaultLineColor;
271
+ this.lineColor = uiSystem.defaultLineColor.copy()
226
272
  /** @property {number} - Width for line drawing */
227
273
  this.lineWidth = uiSystem.defaultLineWidth;
228
274
  /** @property {number} - Corner radius for rounded rects */
@@ -279,7 +325,7 @@ class UIObject
279
325
  /** Update the object, called automatically by plugin once each frame */
280
326
  update()
281
327
  {
282
- const wasHover = this.isHoverObject();
328
+ const wasHover = uiSystem.lastHoverObject === this;
283
329
  const isActive = this.isActiveObject();
284
330
  const mouseDown = mouseIsDown(0);
285
331
  const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
@@ -292,15 +338,14 @@ class UIObject
292
338
  }
293
339
  if (this.isHoverObject())
294
340
  {
295
- if (mousePress)
296
- inputClearKey(0,0,0,1,0); // clear mouse was pressed state
297
341
  if (!this.disabled)
298
342
  {
299
343
  if (mousePress)
300
344
  {
301
345
  if (this.interactive)
302
346
  {
303
- this.onPress();
347
+ if (!this.dragActivate || (!wasHover || mouseWasPressed(0)))
348
+ this.onPress();
304
349
  if (this.soundPress)
305
350
  this.soundPress.play();
306
351
  if (uiSystem.activeObject && !isActive)
@@ -308,13 +353,15 @@ class UIObject
308
353
  uiSystem.activeObject = this;
309
354
  }
310
355
  }
311
- if (!mouseDown && uiSystem.activeObject === this && this.interactive)
356
+ if (!mouseDown && this.isActiveObject() && this.interactive)
312
357
  {
313
358
  this.onClick();
314
359
  if (this.soundClick)
315
360
  this.soundClick.play();
316
361
  }
317
362
  }
363
+ // clear mouse was pressed state even when disabled
364
+ mousePress && inputClearKey(0,0,0,1,0);
318
365
  }
319
366
  if (isActive)
320
367
  if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
@@ -325,6 +372,7 @@ class UIObject
325
372
  uiSystem.activeObject = undefined;
326
373
  }
327
374
 
375
+ // call enter/leave events
328
376
  if (this.isHoverObject() !== wasHover)
329
377
  this.isHoverObject() ? this.onEnter() : this.onLeave();
330
378
  }
@@ -335,7 +383,7 @@ class UIObject
335
383
  if (!this.size.x || !this.size.y) return;
336
384
 
337
385
  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;
386
+ const color = this.disabled ? this.disabledColor : this.interactive ? this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
339
387
  uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
340
388
  }
341
389
 
@@ -386,6 +434,7 @@ class UIObject
386
434
  /**
387
435
  * UIText - A UI object that displays text
388
436
  * @extends UIObject
437
+ * @memberof UISystem
389
438
  */
390
439
  class UIText extends UIObject
391
440
  {
@@ -400,6 +449,10 @@ class UIText extends UIObject
400
449
  {
401
450
  super(pos, size);
402
451
 
452
+ ASSERT(isString(text), 'ui text must be a string');
453
+ ASSERT(['left','center','right'].includes(align), 'ui text align must be left, center, or right');
454
+ ASSERT(isString(font), 'ui text font must be a string');
455
+
403
456
  // set properties
404
457
  this.text = text;
405
458
  this.align = align;
@@ -419,6 +472,7 @@ class UIText extends UIObject
419
472
  /**
420
473
  * UITile - A UI object that displays a tile image
421
474
  * @extends UIObject
475
+ * @memberof UISystem
422
476
  */
423
477
  class UITile extends UIObject
424
478
  {
@@ -433,15 +487,19 @@ class UITile extends UIObject
433
487
  constructor(pos, size, tileInfo, color=WHITE, angle=0, mirror=false)
434
488
  {
435
489
  super(pos, size);
490
+
491
+ ASSERT(tileInfo instanceof TileInfo, 'ui tile tileInfo must be a TileInfo');
492
+ ASSERT(isColor(color), 'ui tile color must be a color');
493
+ ASSERT(isNumber(angle), 'ui tile angle must be a number');
494
+
436
495
  /** @property {TileInfo} - Tile image to use */
437
496
  this.tileInfo = tileInfo;
438
497
  /** @property {number} - Angle to rotate in radians */
439
498
  this.angle = angle;
440
499
  /** @property {boolean} - Should it be mirrored? */
441
500
  this.mirror = mirror;
442
-
443
501
  // set properties
444
- this.color = color;
502
+ this.color = color.copy();
445
503
  }
446
504
  render()
447
505
  {
@@ -453,6 +511,7 @@ class UITile extends UIObject
453
511
  /**
454
512
  * UIButton - A UI object that acts as a button
455
513
  * @extends UIObject
514
+ * @memberof UISystem
456
515
  */
457
516
  class UIButton extends UIObject
458
517
  {
@@ -466,9 +525,12 @@ class UIButton extends UIObject
466
525
  {
467
526
  super(pos, size);
468
527
 
528
+ ASSERT(isString(text), 'ui button must be a string');
529
+ ASSERT(isColor(color), 'ui button color must be a color');
530
+
469
531
  // set properties
470
532
  this.text = text;
471
- this.color = color;
533
+ this.color = color.copy()
472
534
  this.interactive = true;
473
535
  }
474
536
  render()
@@ -486,6 +548,7 @@ class UIButton extends UIObject
486
548
  /**
487
549
  * UICheckbox - A UI object that acts as a checkbox
488
550
  * @extends UIObject
551
+ * @memberof UISystem
489
552
  */
490
553
  class UICheckbox extends UIObject
491
554
  {
@@ -499,12 +562,15 @@ class UICheckbox extends UIObject
499
562
  constructor(pos, size, checked=false, text='', color=uiSystem.defaultButtonColor)
500
563
  {
501
564
  super(pos, size);
565
+
566
+ ASSERT(isString(text), 'ui checkbox must be a string');
567
+ ASSERT(isColor(color), 'ui checkbox color must be a color');
568
+
502
569
  /** @property {boolean} - Current percentage value of this scrollbar 0-1 */
503
570
  this.checked = checked;
504
-
505
571
  // set properties
506
572
  this.text = text;
507
- this.color = color;
573
+ this.color = color.copy();
508
574
  this.interactive = true;
509
575
  }
510
576
  onClick()
@@ -536,6 +602,7 @@ class UICheckbox extends UIObject
536
602
  /**
537
603
  * UIScrollbar - A UI object that acts as a scrollbar
538
604
  * @extends UIObject
605
+ * @memberof UISystem
539
606
  */
540
607
  class UIScrollbar extends UIObject
541
608
  {
@@ -551,14 +618,19 @@ class UIScrollbar extends UIObject
551
618
  {
552
619
  super(pos, size);
553
620
 
621
+ ASSERT(isNumber(value), 'ui scrollbar value must be a number');
622
+ ASSERT(isString(text), 'ui scrollbar must be a string');
623
+ ASSERT(isColor(color), 'ui scrollbar color must be a color');
624
+ ASSERT(isColor(handleColor), 'ui scrollbar handleColor must be a color');
625
+
554
626
  /** @property {number} - Current percentage value of this scrollbar 0-1 */
555
627
  this.value = value;
556
628
  /** @property {Color} - Color for the handle part of the scrollbar */
557
- this.handleColor = handleColor;
629
+ this.handleColor = handleColor.copy();
558
630
 
559
631
  // set properties
560
632
  this.text = text;
561
- this.color = color;
633
+ this.color = color.copy();
562
634
  this.interactive = true;
563
635
  }
564
636
  update()
@@ -566,29 +638,43 @@ class UIScrollbar extends UIObject
566
638
  super.update();
567
639
  if (this.isActiveObject() && this.interactive)
568
640
  {
641
+ // handle horizontal or vertical scrollbar
642
+ const isHorizontal = this.size.x > this.size.y;
643
+ const handleSize = isHorizontal ? this.size.y : this.size.x;
644
+ const barSize = isHorizontal ? this.size.x : this.size.y;
645
+ const centerPos = isHorizontal ? this.pos.x : this.pos.y;
646
+
569
647
  // 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;
648
+ const handleWidth = barSize - handleSize;
649
+ const p1 = centerPos - handleWidth/2;
650
+ const p2 = centerPos + handleWidth/2;
574
651
  const oldValue = this.value;
575
- this.value = percent(mousePosScreen.x, p1, p2);
652
+ this.value = isHorizontal ?
653
+ percent(mousePosScreen.x, p1, p2) :
654
+ percent(mousePosScreen.y, p2, p1);
576
655
  this.value === oldValue || this.onChange();
577
656
  }
578
657
  }
579
658
  render()
580
659
  {
581
660
  super.render();
582
-
661
+
662
+ // handle horizontal or vertical scrollbar
663
+ const isHorizontal = this.size.x > this.size.y;
664
+ const handleSize = isHorizontal ? this.size.y : this.size.x;
665
+ const barSize = isHorizontal ? this.size.x : this.size.y;
666
+ const centerPos = isHorizontal ? this.pos.x : this.pos.y;
667
+
583
668
  // 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);
669
+ const handleWidth = barSize - handleSize;
670
+ const p1 = centerPos - handleWidth/2;
671
+ const p2 = centerPos + handleWidth/2;
672
+ const handlePos = isHorizontal ?
673
+ vec2(lerp(p1, p2, this.value), this.pos.y) :
674
+ vec2(this.pos.x, lerp(p2, p1, this.value))
589
675
  const handleColor = this.disabled ? this.disabledColor :
590
676
  this.interactive && this.isActiveObject() ? this.color : this.handleColor;
591
- uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
677
+ uiSystem.drawRect(handlePos, vec2(handleSize), handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
592
678
 
593
679
  // draw the text scaled to fit on the scrollbar
594
680
  const textSize = this.getTextSize();
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