littlejsengine 1.14.4 → 1.14.7

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 (42) hide show
  1. package/README.md +3 -3
  2. package/dist/littlejs.d.ts +40 -14
  3. package/dist/littlejs.esm.js +119 -59
  4. package/dist/littlejs.esm.min.js +1 -1
  5. package/dist/littlejs.js +115 -57
  6. package/dist/littlejs.min.js +1 -1
  7. package/dist/littlejs.release.js +108 -50
  8. package/examples/box2d/game.js +1 -3
  9. package/examples/box2d/gameObjects.js +2 -2
  10. package/examples/htmlMenu/game.js +1 -1
  11. package/examples/index.html +85 -49
  12. package/examples/puzzle/game.js +1 -2
  13. package/examples/shorts/animation.js +2 -2
  14. package/examples/shorts/box2d.js +1 -0
  15. package/examples/shorts/box2dCar.js +1 -0
  16. package/examples/shorts/flappyGame.js +2 -1
  17. package/examples/shorts/helloWorld.js +2 -2
  18. package/examples/shorts/hillGlideGame.js +6 -3
  19. package/examples/shorts/maze.js +1 -0
  20. package/examples/shorts/medals.js +3 -0
  21. package/examples/shorts/music.js +6 -8
  22. package/examples/shorts/platformer.js +1 -0
  23. package/examples/shorts/shapes.js +6 -6
  24. package/examples/shorts/sound.js +1 -0
  25. package/examples/shorts/spriteAtlas.js +1 -2
  26. package/examples/shorts/tileLayer.js +1 -0
  27. package/examples/shorts/tiltedView.js +1 -1
  28. package/examples/shorts/timers.js +34 -31
  29. package/examples/shorts/topDown.js +2 -1
  30. package/examples/shorts/uiSystem.js +3 -5
  31. package/examples/stress/index.html +1 -1
  32. package/examples/uiSystem/game.js +1 -1
  33. package/package.json +1 -1
  34. package/plugins/uiSystem.js +35 -17
  35. package/reference.md +1 -1
  36. package/src/engine.js +23 -6
  37. package/src/engineDebug.js +7 -7
  38. package/src/engineDraw.js +18 -11
  39. package/src/engineExport.js +4 -2
  40. package/src/engineSettings.js +10 -0
  41. package/src/engineUtilities.js +4 -0
  42. package/src/engineWebGL.js +18 -16
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
33
33
  * @type {string}
34
34
  * @default
35
35
  * @memberof Engine */
36
- const engineVersion = '1.14.4';
36
+ const engineVersion = '1.14.7';
37
37
 
38
38
  /** Frames per second to update
39
39
  * @type {number}
@@ -172,15 +172,15 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
172
172
  frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
173
173
  if (!debugSpeedUp)
174
174
  frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp min framerate
175
- if (debugVideoCaptureIsActive())
176
- frameTimeBufferMS = 0; // no time smoothing when capturing video
177
- updateCanvas();
178
175
 
179
176
  if (paused)
180
177
  {
178
+ updateCanvas();
179
+
181
180
  // update object transforms even when paused
182
181
  for (const o of engineObjects)
183
182
  o.parent || o.updateTransforms();
183
+
184
184
  inputUpdate();
185
185
  pluginUpdateList.forEach(f=>f());
186
186
  debugUpdate();
@@ -205,6 +205,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
205
205
  time = frame++ / frameRate;
206
206
 
207
207
  // update game and objects
208
+ updateCanvas();
208
209
  inputUpdate();
209
210
  gameUpdate();
210
211
  pluginUpdateList.forEach(f=>f());
@@ -214,14 +215,23 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
214
215
  debugUpdate();
215
216
  gameUpdatePost();
216
217
  inputUpdatePost();
218
+
219
+ if (debugVideoCaptureIsActive())
220
+ renderFrame();
217
221
  }
218
222
 
219
223
  // add the time smoothing back in
220
224
  frameTimeBufferMS += deltaSmooth;
221
225
  }
222
226
 
223
- if (!headlessMode)
227
+ if (!debugVideoCaptureIsActive())
228
+ renderFrame();
229
+ requestAnimationFrame(engineUpdate);
230
+
231
+ function renderFrame()
224
232
  {
233
+ if (headlessMode) return;
234
+
225
235
  // render sort then render while removing destroyed objects
226
236
  enginePreRender();
227
237
  gameRender();
@@ -251,7 +261,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
251
261
  }
252
262
  drawCount = 0;
253
263
  }
254
- requestAnimationFrame(engineUpdate);
255
264
  }
256
265
 
257
266
  function updateCanvas()
@@ -277,6 +286,14 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
277
286
  mainCanvas.height = min(innerHeight, canvasMaxSize.y);
278
287
  }
279
288
 
289
+ // apply the clear color to main canvas
290
+ if (canvasClearColor.a > 0)
291
+ {
292
+ mainContext.fillStyle = canvasClearColor.toString();
293
+ mainContext.fillRect(0, 0, mainCanvasSize.x, mainCanvasSize.y);
294
+ mainContext.fillStyle = BLACK.toString();
295
+ }
296
+
280
297
  // clear overlay canvas and set size
281
298
  overlayCanvas.width = mainCanvas.width;
282
299
  overlayCanvas.height = mainCanvas.height;
@@ -1678,6 +1695,10 @@ class Timer
1678
1695
  * @return {number} */
1679
1696
  getPercent() { return this.isSet()? 1-percent(this.time - time, 0, this.setTime) : 0; }
1680
1697
 
1698
+ /** Get the time this timer was set to, returns 0 if not set
1699
+ * @return {number} */
1700
+ getSetTime() { return this.isSet() ? this.setTime : 0; }
1701
+
1681
1702
  /** Returns this timer expressed as a string
1682
1703
  * @return {string} */
1683
1704
  toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
@@ -1723,6 +1744,11 @@ let cameraScale = 32;
1723
1744
  * @memberof Settings */
1724
1745
  let canvasColorTiles = true;
1725
1746
 
1747
+ /** Color to clear the canvas to before render
1748
+ * @type {Color}
1749
+ * @memberof Draw */
1750
+ let canvasClearColor = CLEAR_BLACK;
1751
+
1726
1752
  /** The max size of the canvas, centered if window is larger
1727
1753
  * @type {Vector2}
1728
1754
  * @default Vector2(1920,1080)
@@ -2001,6 +2027,11 @@ function setCameraScale(scale) { cameraScale = scale; }
2001
2027
  * @memberof Settings */
2002
2028
  function setCanvasColorTiles(colorTiles) { canvasColorTiles = colorTiles; }
2003
2029
 
2030
+ /** Set color to clear the canvas to before render
2031
+ * @param {Color} color
2032
+ * @memberof Settings */
2033
+ function setCanvasClearColor(color) { canvasClearColor = color; }
2034
+
2004
2035
  /** Set max size of the canvas
2005
2036
  * @param {Vector2} size
2006
2037
  * @memberof Settings */
@@ -2829,8 +2860,9 @@ class TileInfo
2829
2860
  * @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
2830
2861
  * @param {number} [textureIndex] - Texture index to use
2831
2862
  * @param {number} [padding] - How many pixels padding around tiles
2863
+ * @param {number} [bleedScale] - How many pixels smaller to draw tiles
2832
2864
  */
2833
- constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
2865
+ constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0, bleedScale=tileFixBleedScale)
2834
2866
  {
2835
2867
  /** @property {Vector2} - Top left corner of tile in pixels */
2836
2868
  this.pos = pos.copy();
@@ -2842,6 +2874,8 @@ class TileInfo
2842
2874
  this.padding = padding;
2843
2875
  /** @property {TextureInfo} - The texture info for this tile */
2844
2876
  this.textureInfo = textureInfos[this.textureIndex];
2877
+ /** @property {float} - Shrinks tile by this many pixels to prevent neighbors bleeding */
2878
+ this.bleedScale = bleedScale;
2845
2879
  }
2846
2880
 
2847
2881
  /** Returns a copy of this tile offset by a vector
@@ -2849,7 +2883,7 @@ class TileInfo
2849
2883
  * @return {TileInfo}
2850
2884
  */
2851
2885
  offset(offset)
2852
- { return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
2886
+ { return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.bleedScale); }
2853
2887
 
2854
2888
  /** Returns a copy of this tile offset by a number of animation frames
2855
2889
  * @param {number} frame - Offset to apply in animation frames
@@ -2872,6 +2906,8 @@ class TileInfo
2872
2906
  this.pos = new Vector2;
2873
2907
  this.size = new Vector2(image.width, image.height);
2874
2908
  this.textureInfo = new TextureInfo(image, glTexture);
2909
+ // do not use padding or bleed
2910
+ this.bleedScale = this.padding = 0;
2875
2911
  return this;
2876
2912
  }
2877
2913
  }
@@ -2929,6 +2965,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
2929
2965
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
2930
2966
 
2931
2967
  const textureInfo = tileInfo && tileInfo.textureInfo;
2968
+ const bleedScale = tileInfo ? tileInfo.bleedScale : 0;
2932
2969
  if (useWebGL)
2933
2970
  {
2934
2971
  if (screenSpace)
@@ -2946,10 +2983,10 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
2946
2983
  const w = tileInfo.size.x * sizeInverse.x;
2947
2984
  const h = tileInfo.size.y * sizeInverse.y;
2948
2985
  glSetTexture(textureInfo.glTexture);
2949
- if (tileFixBleedScale)
2986
+ if (bleedScale)
2950
2987
  {
2951
- const tileImageFixBleedX = sizeInverse.x*tileFixBleedScale;
2952
- const tileImageFixBleedY = sizeInverse.y*tileFixBleedScale;
2988
+ const tileImageFixBleedX = sizeInverse.x*bleedScale;
2989
+ const tileImageFixBleedY = sizeInverse.y*bleedScale;
2953
2990
  glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
2954
2991
  x + tileImageFixBleedX, y + tileImageFixBleedY,
2955
2992
  x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
@@ -2980,7 +3017,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
2980
3017
  // calculate uvs and render
2981
3018
  const x = tileInfo.pos.x, y = tileInfo.pos.y;
2982
3019
  const w = tileInfo.size.x, h = tileInfo.size.y;
2983
- drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor);
3020
+ drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor, bleedScale);
2984
3021
  }
2985
3022
  else
2986
3023
  {
@@ -3468,15 +3505,16 @@ function combineCanvases()
3468
3505
  * @param {number} dHeight
3469
3506
  * @param {Color} color
3470
3507
  * @param {Color} [additiveColor]
3508
+ * @param {number} [bleedScale] - How much to shrink the source, used to fix bleeding
3471
3509
  * @memberof Draw */
3472
- function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor)
3510
+ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor, bleedScale=0)
3473
3511
  {
3474
3512
  function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
3475
3513
  function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
3476
- const sx2 = tileFixBleedScale;
3477
- const sy2 = tileFixBleedScale;
3478
- const sWidth2 = sWidth - 2*tileFixBleedScale;
3479
- const sHeight2 = sHeight - 2*tileFixBleedScale;
3514
+ const sx2 = bleedScale;
3515
+ const sy2 = bleedScale;
3516
+ const sWidth2 = sWidth - 2*bleedScale;
3517
+ const sHeight2 = sHeight - 2*bleedScale;
3480
3518
  if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
3481
3519
  {
3482
3520
  // white texture with no additive alpha, no need to tint
@@ -6316,7 +6354,8 @@ function glSetTexture(texture, wrap=false)
6316
6354
  return;
6317
6355
 
6318
6356
  glFlush();
6319
- glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = texture);
6357
+ glActiveTexture = texture;
6358
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
6320
6359
 
6321
6360
  // set wrap mode
6322
6361
  const wrapMode = wrap ? glContext.REPEAT : glContext.CLAMP_TO_EDGE;
@@ -6366,6 +6405,7 @@ function glCreateProgram(vsSource, fsSource)
6366
6405
  }
6367
6406
 
6368
6407
  /** Create WebGL texture from an image and init the texture settings
6408
+ * Restores the active texture when done
6369
6409
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} [image]
6370
6410
  * @return {WebGLTexture}
6371
6411
  * @memberof WebGL */
@@ -6375,30 +6415,29 @@ function glCreateTexture(image)
6375
6415
 
6376
6416
  // build the texture
6377
6417
  const texture = glContext.createTexture();
6378
- glContext.bindTexture(glContext.TEXTURE_2D, texture);
6418
+ let mipMap = false;
6379
6419
  if (image && image.width)
6380
6420
  {
6381
6421
  glSetTextureData(texture, image);
6382
- if (!tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height))
6383
- {
6384
- // use mipmap filtering
6385
- glContext.generateMipmap(glContext.TEXTURE_2D);
6386
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, glContext.LINEAR_MIPMAP_LINEAR);
6387
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, glContext.LINEAR);
6388
- return texture;
6389
- }
6422
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
6423
+ mipMap = !tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height);
6390
6424
  }
6391
6425
  else
6392
6426
  {
6393
6427
  // create a white texture
6394
6428
  const whitePixel = new Uint8Array([255, 255, 255, 255]);
6429
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
6395
6430
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
6396
6431
  }
6397
6432
 
6398
6433
  // set texture filtering
6399
- const filter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
6400
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, filter);
6401
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, filter);
6434
+ const magFilter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
6435
+ const minFilter = mipMap ? glContext.LINEAR_MIPMAP_LINEAR : magFilter;
6436
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, magFilter);
6437
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
6438
+ if (mipMap)
6439
+ glContext.generateMipmap(glContext.TEXTURE_2D);
6440
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
6402
6441
  return texture;
6403
6442
  }
6404
6443
 
@@ -6411,7 +6450,7 @@ function glDeleteTexture(texture)
6411
6450
  glContext.deleteTexture(texture);
6412
6451
  }
6413
6452
 
6414
- /** Set WebGL texture data from an image
6453
+ /** Set WebGL texture data from an image, restores the active texture when done
6415
6454
  * @param {WebGLTexture} texture
6416
6455
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} image
6417
6456
  * @memberof WebGL */
@@ -6423,6 +6462,7 @@ function glSetTextureData(texture, image)
6423
6462
  ASSERT(!!image && image.width > 0, 'Invalid image data.');
6424
6463
  glContext.bindTexture(glContext.TEXTURE_2D, texture);
6425
6464
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
6465
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
6426
6466
  }
6427
6467
 
6428
6468
  /** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
@@ -6568,7 +6608,7 @@ function glDrawPoints(points, rgba)
6568
6608
 
6569
6609
  // setup triangle strip with degenerate verts at start and end
6570
6610
  let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
6571
- for(let i = vertCount; i--;)
6611
+ for (let i = vertCount; i--;)
6572
6612
  {
6573
6613
  const j = clamp(i-1, 0, vertCount-3);
6574
6614
  const point = points[j];
@@ -6596,7 +6636,7 @@ function glDrawColoredPoints(points, pointColors)
6596
6636
 
6597
6637
  // setup triangle strip with degenerate verts at start and end
6598
6638
  let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
6599
- for(let i = vertCount; i--;)
6639
+ for (let i = vertCount; i--;)
6600
6640
  {
6601
6641
  const j = clamp(i-1, 0, vertCount-3);
6602
6642
  const point = points[j];
@@ -7319,6 +7359,8 @@ class UISystemPlugin
7319
7359
  this.defaultLineWidth = 4;
7320
7360
  /** @property {number} - Default rounded rect corner radius for UI elements */
7321
7361
  this.defaultCornerRadius = 0;
7362
+ /** @property {number} - Default scale to use for fitting text to object */
7363
+ this.defaultTextScale = .8;
7322
7364
  /** @property {string} - Default font for UI elements */
7323
7365
  this.defaultFont = 'arial';
7324
7366
  /** @property {Sound} - Default sound when interactive UI element is pressed */
@@ -7335,6 +7377,7 @@ class UISystemPlugin
7335
7377
  engineAddPlugin(uiUpdate, uiRender);
7336
7378
 
7337
7379
  // setup recursive update and render
7380
+ // update in reverse order to detect mouse enter/leave
7338
7381
  function uiUpdate()
7339
7382
  {
7340
7383
  function updateInvisibleObject(o)
@@ -7359,7 +7402,11 @@ class UISystemPlugin
7359
7402
  else
7360
7403
  updateInvisibleObject(o);
7361
7404
  }
7362
- uiSystem.uiObjects.forEach(o=> o.parent || updateObject(o));
7405
+ for (let i = uiSystem.uiObjects.length; i--;)
7406
+ {
7407
+ const o = uiSystem.uiObjects[i];
7408
+ o.parent || updateObject(o)
7409
+ }
7363
7410
  }
7364
7411
  function uiRender()
7365
7412
  {
@@ -7438,10 +7485,11 @@ class UISystemPlugin
7438
7485
  * @param {number} [lineWidth=uiSystem.defaultLineWidth]
7439
7486
  * @param {Color} [lineColor=uiSystem.defaultLineColor]
7440
7487
  * @param {string} [align]
7441
- * @param {string} [font=uiSystem.defaultFont] */
7442
- drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont)
7488
+ * @param {string} [font=uiSystem.defaultFont]
7489
+ * @param {boolean} [applyMaxWidth=true] */
7490
+ drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, applyMaxWidth=true)
7443
7491
  {
7444
- drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, size.x, uiSystem.uiContext);
7492
+ drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
7445
7493
  }
7446
7494
  }
7447
7495
 
@@ -7483,8 +7531,12 @@ class UIObject
7483
7531
  this.cornerRadius = uiSystem.defaultCornerRadius;
7484
7532
  /** @property {string} - Font for this objecct */
7485
7533
  this.font = uiSystem.defaultFont;
7534
+ /** @property {number} - Override for text width */
7535
+ this.textWidth = undefined;
7486
7536
  /** @property {number} - Override for text height */
7487
7537
  this.textHeight = undefined;
7538
+ /** @property {number} - Scale text to fit in the object */
7539
+ this.textScale = uiSystem.defaultTextScale;
7488
7540
  /** @property {boolean} - Should this object be drawn */
7489
7541
  this.visible = true;
7490
7542
  /** @property {Array<UIObject>} - A list of this object's children */
@@ -7594,6 +7646,16 @@ class UIObject
7594
7646
  this.mouseIsOver = this.mouseIsHeld = false;
7595
7647
  }
7596
7648
 
7649
+ /** Get the size for text with overrides and scale
7650
+ * @return {Vector2}
7651
+ */
7652
+ getTextSize()
7653
+ {
7654
+ return vec2(
7655
+ this.textWidth || this.textScale * this.size.x,
7656
+ this.textHeight || this.textScale * this.size.y);
7657
+ }
7658
+
7597
7659
  /** Called when the mouse enters the object */
7598
7660
  onEnter() {}
7599
7661
 
@@ -7641,7 +7703,7 @@ class UIText extends UIObject
7641
7703
  }
7642
7704
  render()
7643
7705
  {
7644
- const textSize = vec2(this.size.x, this.textHeight || this.size.y);
7706
+ const textSize = this.getTextSize();
7645
7707
  uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
7646
7708
  }
7647
7709
  }
@@ -7709,9 +7771,8 @@ class UIButton extends UIObject
7709
7771
  const color = this.disabled ? this.disabledColor : this.mouseIsOver ? this.hoverColor : this.color;
7710
7772
  uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
7711
7773
 
7712
- // draw the text
7713
- const textScale = .8; // scale text to fit
7714
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
7774
+ // draw the text scaled to fit
7775
+ const textSize = this.getTextSize();
7715
7776
  uiSystem.drawText(this.text, this.pos, textSize,
7716
7777
  this.textColor, 0, undefined, this.align, this.font);
7717
7778
  }
@@ -7760,13 +7821,11 @@ class UICheckbox extends UIObject
7760
7821
  uiSystem.drawLine(this.pos.add(s.multiply(vec2(-1,1))), this.pos.add(s.multiply(vec2(1,-1))), this.lineWidth, this.lineColor);
7761
7822
  }
7762
7823
 
7763
- // draw the text to the right side of the checkbox
7764
- const textScale = .8; // scale text to fit
7765
- const gapScale = .55;
7766
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
7767
- const pos = this.pos.add(vec2(this.size.x*gapScale,0));
7824
+ // draw the text next to the checkbox
7825
+ const textSize = this.getTextSize();
7826
+ const pos = this.pos.add(vec2(this.size.x,0));
7768
7827
  uiSystem.drawText(this.text, pos, textSize,
7769
- this.textColor, 0, undefined, 'left', this.font);
7828
+ this.textColor, 0, undefined, 'left', this.font, false);
7770
7829
  }
7771
7830
  }
7772
7831
 
@@ -7833,9 +7892,8 @@ class UIScrollbar extends UIObject
7833
7892
  this.interactive && this.mouseIsHeld ? this.color : this.handleColor;
7834
7893
  uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
7835
7894
 
7836
- // draw the text on the scrollbar
7837
- const textScale = .8; // scale text to fit in scrollbar
7838
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
7895
+ // draw the text scaled to fit on the scrollbar
7896
+ const textSize = this.getTextSize();
7839
7897
  uiSystem.drawText(this.text, this.pos, textSize,
7840
7898
  this.textColor, 0, undefined, this.align, this.font);
7841
7899
  }
@@ -56,6 +56,7 @@ async function gameInit()
56
56
  // start up LittleJS Box2D plugin
57
57
  await LJS.box2dInit();
58
58
  //LJS.box2dSetDebug(true); // enable box2d debug draw
59
+ LJS.setCanvasClearColor(hsl(0,0,.8));
59
60
 
60
61
  // create a table of all sprites
61
62
  const gameTile = (i)=> LJS.tile(i, 496, 0, 8);
@@ -136,9 +137,6 @@ function gameUpdatePost()
136
137
  ///////////////////////////////////////////////////////////////////////////////
137
138
  function gameRender()
138
139
  {
139
- // draw a grey square in the background
140
- LJS.drawRect(vec2(20,8), vec2(100), hsl(0,0,.8));
141
-
142
140
  if (Scenes.scene == 5)
143
141
  {
144
142
  // raycast test
@@ -18,7 +18,7 @@ const density = 1;
18
18
  const friction = .5;
19
19
  const restitution = .2;
20
20
 
21
- export function spawnBox(pos, size=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=true, angle=0)
21
+ export function spawnBox(pos, size=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=false, angle=0)
22
22
  {
23
23
  size = typeof size === 'number' ? vec2(size) : size; // square
24
24
  const o = new LJS.Box2dObject(pos, size, applyTexture && Game.spriteAtlas.squareOutline, angle, color, type);
@@ -27,7 +27,7 @@ export function spawnBox(pos, size=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDy
27
27
  return o;
28
28
  }
29
29
 
30
- export function spawnCircle(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=true, angle=0)
30
+ export function spawnCircle(pos, diameter=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=false, angle=0)
31
31
  {
32
32
  const size = vec2(diameter);
33
33
  const o = new LJS.Box2dObject(pos, size, applyTexture && Game.spriteAtlas.circleOutline, angle, color, type);
@@ -32,6 +32,7 @@ function gameInit()
32
32
  button_exitMenu.onclick = function() { setMenuVisible(false); }
33
33
  input_test.onchange = function() { alert('New text: ' + this.value); }
34
34
  input_rangeTest.onchange = function() { alert('New value: ' + this.value); }
35
+ LJS.setCanvasClearColor(hsl(0,0,.2));
35
36
 
36
37
  // show menu for demo
37
38
  setMenuVisible(true);
@@ -60,7 +61,6 @@ function gameUpdatePost()
60
61
  function gameRender()
61
62
  {
62
63
  // test game rendering
63
- LJS.drawRect(vec2(), vec2(1e3), hsl(0,0,.2));
64
64
  for (let i=0; i<1e3; ++i)
65
65
  {
66
66
  const time = LJS.time;