littlejsengine 1.3.5 → 1.4.0

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.
@@ -8,9 +8,9 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ let showWatermark = 0;
12
+ let godMode = 0;
11
13
  const debug = 0;
12
- const showWatermark = 0;
13
- const godMode = 0;
14
14
  const debugOverlay = 0;
15
15
  const debugPhysics = 0;
16
16
  const debugParticles = 0;
@@ -355,6 +355,28 @@ class Vector2
355
355
 
356
356
  ///////////////////////////////////////////////////////////////////////////////
357
357
 
358
+ /**
359
+ * Create a color object with RGBA values
360
+ * @param {Number} [r=1]
361
+ * @param {Number} [g=1]
362
+ * @param {Number} [b=1]
363
+ * @param {Number} [a=1]
364
+ * @return {Color}
365
+ * @memberof Utilities
366
+ */
367
+ const colorRGBA = (r, g, b, a)=> new Color(r, g, b, a);
368
+
369
+ /**
370
+ * Create a color object with HSLA values
371
+ * @param {Number} [h=0]
372
+ * @param {Number} [s=0]
373
+ * @param {Number} [l=1]
374
+ * @param {Number} [a=1]
375
+ * @return {Color}
376
+ * @memberof Utilities
377
+ */
378
+ const colorHSLA = (h, s, l, a)=> new Color().setHSLA(h, s, l, a);
379
+
358
380
  /**
359
381
  * Color object (red, green, blue, alpha) with some helpful functions
360
382
  * @example
@@ -442,6 +464,34 @@ class Color
442
464
  return this;
443
465
  }
444
466
 
467
+ /** Returns this color expressed in hsla format
468
+ * @return {Array} */
469
+ getHSLA()
470
+ {
471
+ const r = this.r;
472
+ const g = this.g;
473
+ const b = this.b;
474
+ const a = this.a;
475
+ const max = Math.max(r, g, b);
476
+ const min = Math.min(r, g, b);
477
+ const l = (max + min) / 2;
478
+
479
+ let h = 0, s = 0;
480
+ if (max != min)
481
+ {
482
+ let d = max - min;
483
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
484
+ if (r == max)
485
+ h = (g - b) / d + (g < b ? 6 : 0);
486
+ else if (g == max)
487
+ h = (b - r) / d + 2;
488
+ else if (b == max)
489
+ h = (r - g) / d + 4;
490
+ }
491
+
492
+ return [h / 6, s, l, a];
493
+ }
494
+
445
495
  /** Returns a new color that has each component randomly adjusted
446
496
  * @param {Number} [amount=.05]
447
497
  * @param {Number} [alphaAmount=0]
@@ -473,42 +523,6 @@ class Color
473
523
  return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
474
524
  }
475
525
 
476
- /** Returns this color expressed as a hex code
477
- * @return {String} */
478
- hex()
479
- {
480
- const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
481
- return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
482
- }
483
-
484
- /** Returns this color expressed in hsla format
485
- * @return {Array} */
486
- getHSLA()
487
- {
488
- const r = this.r;
489
- const g = this.g;
490
- const b = this.b;
491
- const a = this.a;
492
- const max = Math.max(r, g, b);
493
- const min = Math.min(r, g, b);
494
- const l = (max + min) / 2;
495
-
496
- let h = 0, s = 0;
497
- if (max != min)
498
- {
499
- let d = max - min;
500
- s = l > .5 ? d / (2 - max - min) : d / (max + min);
501
- if (r == max)
502
- h = (g - b) / d + (g < b ? 6 : 0);
503
- else if (g == max)
504
- h = (b - r) / d + 2;
505
- else if (b == max)
506
- h = (r - g) / d + 4;
507
- }
508
-
509
- return [h / 6, s, l, a];
510
- }
511
-
512
526
  /** Set this color from a hex code
513
527
  * @param {String} hex - html hex code
514
528
  * @return {Color} */
@@ -522,6 +536,14 @@ class Color
522
536
  ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
523
537
  return this;
524
538
  }
539
+
540
+ /** Returns this color expressed as a hex code
541
+ * @return {String} */
542
+ getHex()
543
+ {
544
+ const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
545
+ return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
546
+ }
525
547
  }
526
548
 
527
549
  ///////////////////////////////////////////////////////////////////////////////
@@ -571,6 +593,10 @@ class Timer
571
593
  /** Returns this timer expressed as a string
572
594
  * @return {String} */
573
595
  toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
596
+
597
+ /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
598
+ * @return {Number} */
599
+ valueOf() { return this.get(); }
574
600
  }
575
601
  /**
576
602
  * LittleJS Engine Settings
@@ -588,7 +614,8 @@ class Timer
588
614
  * @memberof Settings */
589
615
  let canvasMaxSize = vec2(1920, 1200);
590
616
 
591
- /** Fixed size of the canvas, if enabled cavnvas size never changes
617
+ /** Fixed size of the canvas, if enabled canvas size never changes
618
+ * - you may also need to set mainCanvasSize if using screen space coords in startup
592
619
  * @type {Vector2}
593
620
  * @default
594
621
  * @memberof Settings */
@@ -818,7 +845,7 @@ let medalDisplayIconSize = 50;
818
845
  const engineName = 'LittleJS';
819
846
 
820
847
  /** Version of engine */
821
- const engineVersion = '1.3.5';
848
+ const engineVersion = '1.4.0';
822
849
 
823
850
  /** Frames per second to update objects
824
851
  * @default */
@@ -909,6 +936,33 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
909
936
  timeReal += frameTimeDeltaMS / 1e3;
910
937
  frameTimeBufferMS = min(frameTimeBufferMS + !paused * frameTimeDeltaMS, 50); // clamp incase of slow framerate
911
938
 
939
+ if (canvasFixedSize.x)
940
+ {
941
+ // clear set fixed size
942
+ overlayCanvas.width = mainCanvas.width = canvasFixedSize.x;
943
+ overlayCanvas.height = mainCanvas.height = canvasFixedSize.y;
944
+
945
+ // fit to window by adding space on top or bottom if necessary
946
+ const aspect = innerWidth / innerHeight;
947
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
948
+ mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
949
+ mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
950
+ if (glCanvas)
951
+ {
952
+ glCanvas.style.width = mainCanvas.style.width;
953
+ glCanvas.style.height = mainCanvas.style.height;
954
+ }
955
+ }
956
+ else
957
+ {
958
+ // clear and set size to same as window
959
+ overlayCanvas.width = mainCanvas.width = min(innerWidth, canvasMaxSize.x);
960
+ overlayCanvas.height = mainCanvas.height = min(innerHeight, canvasMaxSize.y);
961
+ }
962
+
963
+ // save canvas size
964
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
965
+
912
966
  if (paused)
913
967
  {
914
968
  // do post update even when paused
@@ -945,30 +999,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
945
999
  // add the time smoothing back in
946
1000
  frameTimeBufferMS += deltaSmooth;
947
1001
  }
948
-
949
- if (canvasFixedSize.x)
950
- {
951
- // clear set fixed size
952
- mainCanvas.width = canvasFixedSize.x;
953
- mainCanvas.height = canvasFixedSize.y;
954
-
955
- // fit to window by adding space on top or bottom if necessary
956
- const aspect = innerWidth / innerHeight;
957
- const fixedAspect = mainCanvas.width / mainCanvas.height;
958
- mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
959
- mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
960
- if (glCanvas)
961
- {
962
- glCanvas.style.width = mainCanvas.style.width;
963
- glCanvas.style.height = mainCanvas.style.height;
964
- }
965
- }
966
- else
967
- {
968
- // clear and set size to same as window
969
- mainCanvas.width = min(innerWidth, canvasMaxSize.x);
970
- mainCanvas.height = min(innerHeight, canvasMaxSize.y);
971
- }
972
1002
 
973
1003
  // render sort then render while removing destroyed objects
974
1004
  enginePreRender();
@@ -1008,8 +1038,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
1008
1038
  // called by engine to setup render system
1009
1039
  function enginePreRender()
1010
1040
  {
1011
- // save canvas size and clear canvases
1012
- mainCanvasSize = vec2(overlayCanvas.width = mainCanvas.width, overlayCanvas.height = mainCanvas.height);
1041
+ // save canvas size
1042
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
1013
1043
 
1014
1044
  // disable smoothing for pixel art
1015
1045
  mainContext.imageSmoothingEnabled = !cavasPixelated;
@@ -1507,18 +1537,26 @@ let overlayContext;
1507
1537
  let mainCanvasSize = vec2();
1508
1538
 
1509
1539
  /** Convert from screen to world space coordinates
1540
+ * - if calling outside of render, you may need to manually set mainCanvasSize
1510
1541
  * @param {Vector2} screenPos
1511
1542
  * @return {Vector2}
1512
1543
  * @memberof Draw */
1513
1544
  const screenToWorld = (screenPos)=>
1514
- screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
1545
+ {
1546
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1547
+ return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
1548
+ }
1515
1549
 
1516
1550
  /** Convert from world to screen space coordinates
1551
+ * - if calling outside of render, you may need to manually set mainCanvasSize
1517
1552
  * @param {Vector2} worldPos
1518
1553
  * @return {Vector2}
1519
1554
  * @memberof Draw */
1520
1555
  const worldToScreen = (worldPos)=>
1521
- worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
1556
+ {
1557
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
1558
+ return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
1559
+ }
1522
1560
 
1523
1561
  /** Draw textured tile centered in world space, with color applied if using WebGL
1524
1562
  * @param {Vector2} pos - Center of the tile in world space
@@ -1633,7 +1671,7 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL)
1633
1671
  {
1634
1672
  const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
1635
1673
  const size = vec2(thickness, halfDelta.length()*2);
1636
- drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), 0, 0, useWebGL);
1674
+ drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL);
1637
1675
  }
1638
1676
 
1639
1677
  /** Draw directly to a 2d canvas context in world space
@@ -1650,7 +1688,7 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
1650
1688
  pos = worldToScreen(pos);
1651
1689
  size = size.scale(cameraScale);
1652
1690
  context.save();
1653
- context.translate(pos.x+.5|0, pos.y-.5|0);
1691
+ context.translate(pos.x+.5|0, pos.y+.5|0);
1654
1692
  context.rotate(angle);
1655
1693
  context.scale(mirror ? -size.x : size.x, size.y);
1656
1694
  drawFunction(context);
@@ -1770,7 +1808,7 @@ class FontImage
1770
1808
  const size = this.tileSize;
1771
1809
  const drawSize = size.add(this.paddingSize).scale(scale);
1772
1810
  const cols = this.image.width / this.tileSize.x |0;
1773
- text.split('\n').forEach((line, i)=>
1811
+ (text+'').split('\n').forEach((line, i)=>
1774
1812
  {
1775
1813
  const centerOffset = center ? line.length * size.x * scale / 2 |0 : 0;
1776
1814
  for(let j=line.length; j--;)
@@ -1996,7 +2034,7 @@ const mouseToScreen = (mousePos)=>
1996
2034
  return vec2(); // fix bug that can occur if user clicks before page loads
1997
2035
 
1998
2036
  const rect = mainCanvas.getBoundingClientRect();
1999
- return mainCanvasSize.multiply(
2037
+ return vec2(mainCanvas.width, mainCanvas.height).multiply(
2000
2038
  vec2(percent(mousePos.x, rect.left, rect.right), percent(mousePos.y, rect.top, rect.bottom)));
2001
2039
  }
2002
2040
 
@@ -2196,7 +2234,7 @@ function touchGamepadRender()
2196
2234
  return;
2197
2235
 
2198
2236
  // fade off when not touching or paused
2199
- const alpha = percent(touchGamepadTimer.get(), 4, 3);
2237
+ const alpha = percent(touchGamepadTimer, 4, 3);
2200
2238
  if (!alpha || paused)
2201
2239
  return;
2202
2240
 
@@ -3042,7 +3080,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
3042
3080
  const cols = tileImage.width/tileSize.x;
3043
3081
  context.globalAlpha = color.a; // only alpha, no color, is supported in this mode
3044
3082
  context.drawImage(tileImage,
3045
- (tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.x,
3083
+ (tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.y,
3046
3084
  tileSize.x, tileSize.y, -.5, -.5, 1, 1);
3047
3085
  }
3048
3086
  });
@@ -3887,7 +3925,7 @@ function glFlush()
3887
3925
  * @memberof WebGL */
3888
3926
  function glCopyToContext(context, forceDraw)
3889
3927
  {
3890
- if ((!glEnable || !glBatchCount) && !forceDraw) return;
3928
+ if (!glEnable || !glBatchCount && !forceDraw) return;
3891
3929
 
3892
3930
  glFlush();
3893
3931
 
package/engine/engine.js CHANGED
@@ -22,7 +22,7 @@
22
22
  const engineName = 'LittleJS';
23
23
 
24
24
  /** Version of engine */
25
- const engineVersion = '1.3.5';
25
+ const engineVersion = '1.4.0';
26
26
 
27
27
  /** Frames per second to update objects
28
28
  * @default */
@@ -113,6 +113,33 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
113
113
  timeReal += frameTimeDeltaMS / 1e3;
114
114
  frameTimeBufferMS = min(frameTimeBufferMS + !paused * frameTimeDeltaMS, 50); // clamp incase of slow framerate
115
115
 
116
+ if (canvasFixedSize.x)
117
+ {
118
+ // clear set fixed size
119
+ overlayCanvas.width = mainCanvas.width = canvasFixedSize.x;
120
+ overlayCanvas.height = mainCanvas.height = canvasFixedSize.y;
121
+
122
+ // fit to window by adding space on top or bottom if necessary
123
+ const aspect = innerWidth / innerHeight;
124
+ const fixedAspect = mainCanvas.width / mainCanvas.height;
125
+ mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
126
+ mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
127
+ if (glCanvas)
128
+ {
129
+ glCanvas.style.width = mainCanvas.style.width;
130
+ glCanvas.style.height = mainCanvas.style.height;
131
+ }
132
+ }
133
+ else
134
+ {
135
+ // clear and set size to same as window
136
+ overlayCanvas.width = mainCanvas.width = min(innerWidth, canvasMaxSize.x);
137
+ overlayCanvas.height = mainCanvas.height = min(innerHeight, canvasMaxSize.y);
138
+ }
139
+
140
+ // save canvas size
141
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
142
+
116
143
  if (paused)
117
144
  {
118
145
  // do post update even when paused
@@ -149,30 +176,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
149
176
  // add the time smoothing back in
150
177
  frameTimeBufferMS += deltaSmooth;
151
178
  }
152
-
153
- if (canvasFixedSize.x)
154
- {
155
- // clear set fixed size
156
- mainCanvas.width = canvasFixedSize.x;
157
- mainCanvas.height = canvasFixedSize.y;
158
-
159
- // fit to window by adding space on top or bottom if necessary
160
- const aspect = innerWidth / innerHeight;
161
- const fixedAspect = mainCanvas.width / mainCanvas.height;
162
- mainCanvas.style.width = overlayCanvas.style.width = aspect < fixedAspect ? '100%' : '';
163
- mainCanvas.style.height = overlayCanvas.style.height = aspect < fixedAspect ? '' : '100%';
164
- if (glCanvas)
165
- {
166
- glCanvas.style.width = mainCanvas.style.width;
167
- glCanvas.style.height = mainCanvas.style.height;
168
- }
169
- }
170
- else
171
- {
172
- // clear and set size to same as window
173
- mainCanvas.width = min(innerWidth, canvasMaxSize.x);
174
- mainCanvas.height = min(innerHeight, canvasMaxSize.y);
175
- }
176
179
 
177
180
  // render sort then render while removing destroyed objects
178
181
  enginePreRender();
@@ -212,8 +215,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
212
215
  // called by engine to setup render system
213
216
  function enginePreRender()
214
217
  {
215
- // save canvas size and clear canvases
216
- mainCanvasSize = vec2(overlayCanvas.width = mainCanvas.width, overlayCanvas.height = mainCanvas.height);
218
+ // save canvas size
219
+ mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
217
220
 
218
221
  // disable smoothing for pixel art
219
222
  mainContext.imageSmoothingEnabled = !cavasPixelated;
@@ -332,7 +332,7 @@ const debugRender = ()=>
332
332
  });
333
333
 
334
334
  // remove expired pritives
335
- debugPrimitives = debugPrimitives.filter(r=>r.time.get()<0);
335
+ debugPrimitives = debugPrimitives.filter(r=>r.time<0);
336
336
  }
337
337
 
338
338
  {
@@ -53,18 +53,26 @@ let overlayContext;
53
53
  let mainCanvasSize = vec2();
54
54
 
55
55
  /** Convert from screen to world space coordinates
56
+ * - if calling outside of render, you may need to manually set mainCanvasSize
56
57
  * @param {Vector2} screenPos
57
58
  * @return {Vector2}
58
59
  * @memberof Draw */
59
60
  const screenToWorld = (screenPos)=>
60
- screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
61
+ {
62
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
63
+ return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
64
+ }
61
65
 
62
66
  /** Convert from world to screen space coordinates
67
+ * - if calling outside of render, you may need to manually set mainCanvasSize
63
68
  * @param {Vector2} worldPos
64
69
  * @return {Vector2}
65
70
  * @memberof Draw */
66
71
  const worldToScreen = (worldPos)=>
67
- worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
72
+ {
73
+ ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
74
+ return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
75
+ }
68
76
 
69
77
  /** Draw textured tile centered in world space, with color applied if using WebGL
70
78
  * @param {Vector2} pos - Center of the tile in world space
@@ -179,7 +187,7 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL)
179
187
  {
180
188
  const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
181
189
  const size = vec2(thickness, halfDelta.length()*2);
182
- drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), 0, 0, useWebGL);
190
+ drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL);
183
191
  }
184
192
 
185
193
  /** Draw directly to a 2d canvas context in world space
@@ -196,7 +204,7 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
196
204
  pos = worldToScreen(pos);
197
205
  size = size.scale(cameraScale);
198
206
  context.save();
199
- context.translate(pos.x+.5|0, pos.y-.5|0);
207
+ context.translate(pos.x+.5|0, pos.y+.5|0);
200
208
  context.rotate(angle);
201
209
  context.scale(mirror ? -size.x : size.x, size.y);
202
210
  drawFunction(context);
@@ -316,7 +324,7 @@ class FontImage
316
324
  const size = this.tileSize;
317
325
  const drawSize = size.add(this.paddingSize).scale(scale);
318
326
  const cols = this.image.width / this.tileSize.x |0;
319
- text.split('\n').forEach((line, i)=>
327
+ (text+'').split('\n').forEach((line, i)=>
320
328
  {
321
329
  const centerOffset = center ? line.length * size.x * scale / 2 |0 : 0;
322
330
  for(let j=line.length; j--;)
@@ -162,7 +162,7 @@ const mouseToScreen = (mousePos)=>
162
162
  return vec2(); // fix bug that can occur if user clicks before page loads
163
163
 
164
164
  const rect = mainCanvas.getBoundingClientRect();
165
- return mainCanvasSize.multiply(
165
+ return vec2(mainCanvas.width, mainCanvas.height).multiply(
166
166
  vec2(percent(mousePos.x, rect.left, rect.right), percent(mousePos.y, rect.top, rect.bottom)));
167
167
  }
168
168
 
@@ -362,7 +362,7 @@ function touchGamepadRender()
362
362
  return;
363
363
 
364
364
  // fade off when not touching or paused
365
- const alpha = percent(touchGamepadTimer.get(), 4, 3);
365
+ const alpha = percent(touchGamepadTimer, 4, 3);
366
366
  if (!alpha || paused)
367
367
  return;
368
368
 
@@ -8,9 +8,9 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ let showWatermark = 0;
12
+ let godMode = 0;
11
13
  const debug = 0;
12
- const showWatermark = 0;
13
- const godMode = 0;
14
14
  const debugOverlay = 0;
15
15
  const debugPhysics = 0;
16
16
  const debugParticles = 0;
@@ -14,7 +14,8 @@
14
14
  * @memberof Settings */
15
15
  let canvasMaxSize = vec2(1920, 1200);
16
16
 
17
- /** Fixed size of the canvas, if enabled cavnvas size never changes
17
+ /** Fixed size of the canvas, if enabled canvas size never changes
18
+ * - you may also need to set mainCanvasSize if using screen space coords in startup
18
19
  * @type {Vector2}
19
20
  * @default
20
21
  * @memberof Settings */
@@ -328,7 +328,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
328
328
  const cols = tileImage.width/tileSize.x;
329
329
  context.globalAlpha = color.a; // only alpha, no color, is supported in this mode
330
330
  context.drawImage(tileImage,
331
- (tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.x,
331
+ (tileIndex%cols)*tileSize.x, (tileIndex/cols|0)*tileSize.y,
332
332
  tileSize.x, tileSize.y, -.5, -.5, 1, 1);
333
333
  }
334
334
  });
@@ -322,6 +322,28 @@ class Vector2
322
322
 
323
323
  ///////////////////////////////////////////////////////////////////////////////
324
324
 
325
+ /**
326
+ * Create a color object with RGBA values
327
+ * @param {Number} [r=1]
328
+ * @param {Number} [g=1]
329
+ * @param {Number} [b=1]
330
+ * @param {Number} [a=1]
331
+ * @return {Color}
332
+ * @memberof Utilities
333
+ */
334
+ const colorRGBA = (r, g, b, a)=> new Color(r, g, b, a);
335
+
336
+ /**
337
+ * Create a color object with HSLA values
338
+ * @param {Number} [h=0]
339
+ * @param {Number} [s=0]
340
+ * @param {Number} [l=1]
341
+ * @param {Number} [a=1]
342
+ * @return {Color}
343
+ * @memberof Utilities
344
+ */
345
+ const colorHSLA = (h, s, l, a)=> new Color().setHSLA(h, s, l, a);
346
+
325
347
  /**
326
348
  * Color object (red, green, blue, alpha) with some helpful functions
327
349
  * @example
@@ -409,6 +431,34 @@ class Color
409
431
  return this;
410
432
  }
411
433
 
434
+ /** Returns this color expressed in hsla format
435
+ * @return {Array} */
436
+ getHSLA()
437
+ {
438
+ const r = this.r;
439
+ const g = this.g;
440
+ const b = this.b;
441
+ const a = this.a;
442
+ const max = Math.max(r, g, b);
443
+ const min = Math.min(r, g, b);
444
+ const l = (max + min) / 2;
445
+
446
+ let h = 0, s = 0;
447
+ if (max != min)
448
+ {
449
+ let d = max - min;
450
+ s = l > .5 ? d / (2 - max - min) : d / (max + min);
451
+ if (r == max)
452
+ h = (g - b) / d + (g < b ? 6 : 0);
453
+ else if (g == max)
454
+ h = (b - r) / d + 2;
455
+ else if (b == max)
456
+ h = (r - g) / d + 4;
457
+ }
458
+
459
+ return [h / 6, s, l, a];
460
+ }
461
+
412
462
  /** Returns a new color that has each component randomly adjusted
413
463
  * @param {Number} [amount=.05]
414
464
  * @param {Number} [alphaAmount=0]
@@ -440,42 +490,6 @@ class Color
440
490
  return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
441
491
  }
442
492
 
443
- /** Returns this color expressed as a hex code
444
- * @return {String} */
445
- hex()
446
- {
447
- const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
448
- return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
449
- }
450
-
451
- /** Returns this color expressed in hsla format
452
- * @return {Array} */
453
- getHSLA()
454
- {
455
- const r = this.r;
456
- const g = this.g;
457
- const b = this.b;
458
- const a = this.a;
459
- const max = Math.max(r, g, b);
460
- const min = Math.min(r, g, b);
461
- const l = (max + min) / 2;
462
-
463
- let h = 0, s = 0;
464
- if (max != min)
465
- {
466
- let d = max - min;
467
- s = l > .5 ? d / (2 - max - min) : d / (max + min);
468
- if (r == max)
469
- h = (g - b) / d + (g < b ? 6 : 0);
470
- else if (g == max)
471
- h = (b - r) / d + 2;
472
- else if (b == max)
473
- h = (r - g) / d + 4;
474
- }
475
-
476
- return [h / 6, s, l, a];
477
- }
478
-
479
493
  /** Set this color from a hex code
480
494
  * @param {String} hex - html hex code
481
495
  * @return {Color} */
@@ -489,6 +503,14 @@ class Color
489
503
  ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
490
504
  return this;
491
505
  }
506
+
507
+ /** Returns this color expressed as a hex code
508
+ * @return {String} */
509
+ getHex()
510
+ {
511
+ const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
512
+ return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b);
513
+ }
492
514
  }
493
515
 
494
516
  ///////////////////////////////////////////////////////////////////////////////
@@ -538,4 +560,8 @@ class Timer
538
560
  /** Returns this timer expressed as a string
539
561
  * @return {String} */
540
562
  toString() { if (debug) { return this.unset() ? 'unset' : Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ); } }
563
+
564
+ /** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
565
+ * @return {Number} */
566
+ valueOf() { return this.get(); }
541
567
  }
@@ -244,7 +244,7 @@ function glFlush()
244
244
  * @memberof WebGL */
245
245
  function glCopyToContext(context, forceDraw)
246
246
  {
247
- if ((!glEnable || !glBatchCount) && !forceDraw) return;
247
+ if (!glEnable || !glBatchCount && !forceDraw) return;
248
248
 
249
249
  glFlush();
250
250