littlejsengine 1.14.5 → 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 (40) hide show
  1. package/dist/littlejs.d.ts +38 -12
  2. package/dist/littlejs.esm.js +113 -53
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +109 -51
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +108 -50
  7. package/examples/box2d/game.js +1 -3
  8. package/examples/box2d/gameObjects.js +2 -2
  9. package/examples/htmlMenu/game.js +1 -1
  10. package/examples/index.html +85 -49
  11. package/examples/puzzle/game.js +1 -2
  12. package/examples/shorts/animation.js +2 -2
  13. package/examples/shorts/box2d.js +1 -0
  14. package/examples/shorts/box2dCar.js +1 -0
  15. package/examples/shorts/flappyGame.js +2 -1
  16. package/examples/shorts/helloWorld.js +2 -2
  17. package/examples/shorts/hillGlideGame.js +6 -3
  18. package/examples/shorts/maze.js +1 -0
  19. package/examples/shorts/medals.js +3 -0
  20. package/examples/shorts/music.js +3 -5
  21. package/examples/shorts/platformer.js +1 -0
  22. package/examples/shorts/shapes.js +6 -6
  23. package/examples/shorts/sound.js +1 -0
  24. package/examples/shorts/spriteAtlas.js +1 -2
  25. package/examples/shorts/tileLayer.js +1 -0
  26. package/examples/shorts/tiltedView.js +1 -1
  27. package/examples/shorts/timers.js +34 -31
  28. package/examples/shorts/topDown.js +2 -1
  29. package/examples/shorts/uiSystem.js +3 -5
  30. package/examples/stress/index.html +1 -1
  31. package/examples/uiSystem/game.js +1 -1
  32. package/package.json +1 -1
  33. package/plugins/uiSystem.js +35 -17
  34. package/src/engine.js +23 -6
  35. package/src/engineDebug.js +1 -1
  36. package/src/engineDraw.js +18 -11
  37. package/src/engineExport.js +4 -2
  38. package/src/engineSettings.js +10 -0
  39. package/src/engineUtilities.js +4 -0
  40. package/src/engineWebGL.js +18 -16
package/dist/littlejs.js CHANGED
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
33
33
  * @type {string}
34
34
  * @default
35
35
  * @memberof Engine */
36
- const engineVersion = '1.14.5';
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;
@@ -1179,7 +1196,7 @@ function debugVideoCaptureStart()
1179
1196
  const chunks = [];
1180
1197
  debugVideoCaptureTrack = stream.getVideoTracks()[0];
1181
1198
  if (debugVideoCaptureTrack.applyConstraints)
1182
- debugVideoCaptureTrack.applyConstraints({frameRate:frameRate}); // force 60 fps
1199
+ debugVideoCaptureTrack.applyConstraints({frameRate:60}); // force 60 fps
1183
1200
  debugVideoCapture = new MediaRecorder(stream, {mimeType:'video/webm;codecs=vp8'});
1184
1201
  debugVideoCapture.ondataavailable = (e)=> chunks.push(e.data);
1185
1202
  debugVideoCapture.onstop = ()=>
@@ -2231,6 +2248,10 @@ class Timer
2231
2248
  * @return {number} */
2232
2249
  getPercent() { return this.isSet()? 1-percent(this.time - time, 0, this.setTime) : 0; }
2233
2250
 
2251
+ /** Get the time this timer was set to, returns 0 if not set
2252
+ * @return {number} */
2253
+ getSetTime() { return this.isSet() ? this.setTime : 0; }
2254
+
2234
2255
  /** Returns this timer expressed as a string
2235
2256
  * @return {string} */
2236
2257
  toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
@@ -2276,6 +2297,11 @@ let cameraScale = 32;
2276
2297
  * @memberof Settings */
2277
2298
  let canvasColorTiles = true;
2278
2299
 
2300
+ /** Color to clear the canvas to before render
2301
+ * @type {Color}
2302
+ * @memberof Draw */
2303
+ let canvasClearColor = CLEAR_BLACK;
2304
+
2279
2305
  /** The max size of the canvas, centered if window is larger
2280
2306
  * @type {Vector2}
2281
2307
  * @default Vector2(1920,1080)
@@ -2554,6 +2580,11 @@ function setCameraScale(scale) { cameraScale = scale; }
2554
2580
  * @memberof Settings */
2555
2581
  function setCanvasColorTiles(colorTiles) { canvasColorTiles = colorTiles; }
2556
2582
 
2583
+ /** Set color to clear the canvas to before render
2584
+ * @param {Color} color
2585
+ * @memberof Settings */
2586
+ function setCanvasClearColor(color) { canvasClearColor = color; }
2587
+
2557
2588
  /** Set max size of the canvas
2558
2589
  * @param {Vector2} size
2559
2590
  * @memberof Settings */
@@ -3382,8 +3413,9 @@ class TileInfo
3382
3413
  * @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
3383
3414
  * @param {number} [textureIndex] - Texture index to use
3384
3415
  * @param {number} [padding] - How many pixels padding around tiles
3416
+ * @param {number} [bleedScale] - How many pixels smaller to draw tiles
3385
3417
  */
3386
- constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
3418
+ constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0, bleedScale=tileFixBleedScale)
3387
3419
  {
3388
3420
  /** @property {Vector2} - Top left corner of tile in pixels */
3389
3421
  this.pos = pos.copy();
@@ -3395,6 +3427,8 @@ class TileInfo
3395
3427
  this.padding = padding;
3396
3428
  /** @property {TextureInfo} - The texture info for this tile */
3397
3429
  this.textureInfo = textureInfos[this.textureIndex];
3430
+ /** @property {float} - Shrinks tile by this many pixels to prevent neighbors bleeding */
3431
+ this.bleedScale = bleedScale;
3398
3432
  }
3399
3433
 
3400
3434
  /** Returns a copy of this tile offset by a vector
@@ -3402,7 +3436,7 @@ class TileInfo
3402
3436
  * @return {TileInfo}
3403
3437
  */
3404
3438
  offset(offset)
3405
- { return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
3439
+ { return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.bleedScale); }
3406
3440
 
3407
3441
  /** Returns a copy of this tile offset by a number of animation frames
3408
3442
  * @param {number} frame - Offset to apply in animation frames
@@ -3425,6 +3459,8 @@ class TileInfo
3425
3459
  this.pos = new Vector2;
3426
3460
  this.size = new Vector2(image.width, image.height);
3427
3461
  this.textureInfo = new TextureInfo(image, glTexture);
3462
+ // do not use padding or bleed
3463
+ this.bleedScale = this.padding = 0;
3428
3464
  return this;
3429
3465
  }
3430
3466
  }
@@ -3482,6 +3518,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
3482
3518
  ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
3483
3519
 
3484
3520
  const textureInfo = tileInfo && tileInfo.textureInfo;
3521
+ const bleedScale = tileInfo ? tileInfo.bleedScale : 0;
3485
3522
  if (useWebGL)
3486
3523
  {
3487
3524
  if (screenSpace)
@@ -3499,10 +3536,10 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
3499
3536
  const w = tileInfo.size.x * sizeInverse.x;
3500
3537
  const h = tileInfo.size.y * sizeInverse.y;
3501
3538
  glSetTexture(textureInfo.glTexture);
3502
- if (tileFixBleedScale)
3539
+ if (bleedScale)
3503
3540
  {
3504
- const tileImageFixBleedX = sizeInverse.x*tileFixBleedScale;
3505
- const tileImageFixBleedY = sizeInverse.y*tileFixBleedScale;
3541
+ const tileImageFixBleedX = sizeInverse.x*bleedScale;
3542
+ const tileImageFixBleedY = sizeInverse.y*bleedScale;
3506
3543
  glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
3507
3544
  x + tileImageFixBleedX, y + tileImageFixBleedY,
3508
3545
  x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
@@ -3533,7 +3570,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
3533
3570
  // calculate uvs and render
3534
3571
  const x = tileInfo.pos.x, y = tileInfo.pos.y;
3535
3572
  const w = tileInfo.size.x, h = tileInfo.size.y;
3536
- drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor);
3573
+ drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor, bleedScale);
3537
3574
  }
3538
3575
  else
3539
3576
  {
@@ -4021,15 +4058,16 @@ function combineCanvases()
4021
4058
  * @param {number} dHeight
4022
4059
  * @param {Color} color
4023
4060
  * @param {Color} [additiveColor]
4061
+ * @param {number} [bleedScale] - How much to shrink the source, used to fix bleeding
4024
4062
  * @memberof Draw */
4025
- function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor)
4063
+ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor, bleedScale=0)
4026
4064
  {
4027
4065
  function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
4028
4066
  function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
4029
- const sx2 = tileFixBleedScale;
4030
- const sy2 = tileFixBleedScale;
4031
- const sWidth2 = sWidth - 2*tileFixBleedScale;
4032
- const sHeight2 = sHeight - 2*tileFixBleedScale;
4067
+ const sx2 = bleedScale;
4068
+ const sy2 = bleedScale;
4069
+ const sWidth2 = sWidth - 2*bleedScale;
4070
+ const sHeight2 = sHeight - 2*bleedScale;
4033
4071
  if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
4034
4072
  {
4035
4073
  // white texture with no additive alpha, no need to tint
@@ -6869,7 +6907,8 @@ function glSetTexture(texture, wrap=false)
6869
6907
  return;
6870
6908
 
6871
6909
  glFlush();
6872
- glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = texture);
6910
+ glActiveTexture = texture;
6911
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
6873
6912
 
6874
6913
  // set wrap mode
6875
6914
  const wrapMode = wrap ? glContext.REPEAT : glContext.CLAMP_TO_EDGE;
@@ -6919,6 +6958,7 @@ function glCreateProgram(vsSource, fsSource)
6919
6958
  }
6920
6959
 
6921
6960
  /** Create WebGL texture from an image and init the texture settings
6961
+ * Restores the active texture when done
6922
6962
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} [image]
6923
6963
  * @return {WebGLTexture}
6924
6964
  * @memberof WebGL */
@@ -6928,30 +6968,29 @@ function glCreateTexture(image)
6928
6968
 
6929
6969
  // build the texture
6930
6970
  const texture = glContext.createTexture();
6931
- glContext.bindTexture(glContext.TEXTURE_2D, texture);
6971
+ let mipMap = false;
6932
6972
  if (image && image.width)
6933
6973
  {
6934
6974
  glSetTextureData(texture, image);
6935
- if (!tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height))
6936
- {
6937
- // use mipmap filtering
6938
- glContext.generateMipmap(glContext.TEXTURE_2D);
6939
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, glContext.LINEAR_MIPMAP_LINEAR);
6940
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, glContext.LINEAR);
6941
- return texture;
6942
- }
6975
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
6976
+ mipMap = !tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height);
6943
6977
  }
6944
6978
  else
6945
6979
  {
6946
6980
  // create a white texture
6947
6981
  const whitePixel = new Uint8Array([255, 255, 255, 255]);
6982
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
6948
6983
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
6949
6984
  }
6950
6985
 
6951
6986
  // set texture filtering
6952
- const filter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
6953
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, filter);
6954
- glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, filter);
6987
+ const magFilter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
6988
+ const minFilter = mipMap ? glContext.LINEAR_MIPMAP_LINEAR : magFilter;
6989
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, magFilter);
6990
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
6991
+ if (mipMap)
6992
+ glContext.generateMipmap(glContext.TEXTURE_2D);
6993
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
6955
6994
  return texture;
6956
6995
  }
6957
6996
 
@@ -6964,7 +7003,7 @@ function glDeleteTexture(texture)
6964
7003
  glContext.deleteTexture(texture);
6965
7004
  }
6966
7005
 
6967
- /** Set WebGL texture data from an image
7006
+ /** Set WebGL texture data from an image, restores the active texture when done
6968
7007
  * @param {WebGLTexture} texture
6969
7008
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} image
6970
7009
  * @memberof WebGL */
@@ -6976,6 +7015,7 @@ function glSetTextureData(texture, image)
6976
7015
  ASSERT(!!image && image.width > 0, 'Invalid image data.');
6977
7016
  glContext.bindTexture(glContext.TEXTURE_2D, texture);
6978
7017
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
7018
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
6979
7019
  }
6980
7020
 
6981
7021
  /** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
@@ -7121,7 +7161,7 @@ function glDrawPoints(points, rgba)
7121
7161
 
7122
7162
  // setup triangle strip with degenerate verts at start and end
7123
7163
  let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
7124
- for(let i = vertCount; i--;)
7164
+ for (let i = vertCount; i--;)
7125
7165
  {
7126
7166
  const j = clamp(i-1, 0, vertCount-3);
7127
7167
  const point = points[j];
@@ -7149,7 +7189,7 @@ function glDrawColoredPoints(points, pointColors)
7149
7189
 
7150
7190
  // setup triangle strip with degenerate verts at start and end
7151
7191
  let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
7152
- for(let i = vertCount; i--;)
7192
+ for (let i = vertCount; i--;)
7153
7193
  {
7154
7194
  const j = clamp(i-1, 0, vertCount-3);
7155
7195
  const point = points[j];
@@ -7872,6 +7912,8 @@ class UISystemPlugin
7872
7912
  this.defaultLineWidth = 4;
7873
7913
  /** @property {number} - Default rounded rect corner radius for UI elements */
7874
7914
  this.defaultCornerRadius = 0;
7915
+ /** @property {number} - Default scale to use for fitting text to object */
7916
+ this.defaultTextScale = .8;
7875
7917
  /** @property {string} - Default font for UI elements */
7876
7918
  this.defaultFont = 'arial';
7877
7919
  /** @property {Sound} - Default sound when interactive UI element is pressed */
@@ -7888,6 +7930,7 @@ class UISystemPlugin
7888
7930
  engineAddPlugin(uiUpdate, uiRender);
7889
7931
 
7890
7932
  // setup recursive update and render
7933
+ // update in reverse order to detect mouse enter/leave
7891
7934
  function uiUpdate()
7892
7935
  {
7893
7936
  function updateInvisibleObject(o)
@@ -7912,7 +7955,11 @@ class UISystemPlugin
7912
7955
  else
7913
7956
  updateInvisibleObject(o);
7914
7957
  }
7915
- uiSystem.uiObjects.forEach(o=> o.parent || updateObject(o));
7958
+ for (let i = uiSystem.uiObjects.length; i--;)
7959
+ {
7960
+ const o = uiSystem.uiObjects[i];
7961
+ o.parent || updateObject(o)
7962
+ }
7916
7963
  }
7917
7964
  function uiRender()
7918
7965
  {
@@ -7991,10 +8038,11 @@ class UISystemPlugin
7991
8038
  * @param {number} [lineWidth=uiSystem.defaultLineWidth]
7992
8039
  * @param {Color} [lineColor=uiSystem.defaultLineColor]
7993
8040
  * @param {string} [align]
7994
- * @param {string} [font=uiSystem.defaultFont] */
7995
- drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont)
8041
+ * @param {string} [font=uiSystem.defaultFont]
8042
+ * @param {boolean} [applyMaxWidth=true] */
8043
+ drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, applyMaxWidth=true)
7996
8044
  {
7997
- drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, size.x, uiSystem.uiContext);
8045
+ drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
7998
8046
  }
7999
8047
  }
8000
8048
 
@@ -8036,8 +8084,12 @@ class UIObject
8036
8084
  this.cornerRadius = uiSystem.defaultCornerRadius;
8037
8085
  /** @property {string} - Font for this objecct */
8038
8086
  this.font = uiSystem.defaultFont;
8087
+ /** @property {number} - Override for text width */
8088
+ this.textWidth = undefined;
8039
8089
  /** @property {number} - Override for text height */
8040
8090
  this.textHeight = undefined;
8091
+ /** @property {number} - Scale text to fit in the object */
8092
+ this.textScale = uiSystem.defaultTextScale;
8041
8093
  /** @property {boolean} - Should this object be drawn */
8042
8094
  this.visible = true;
8043
8095
  /** @property {Array<UIObject>} - A list of this object's children */
@@ -8147,6 +8199,16 @@ class UIObject
8147
8199
  this.mouseIsOver = this.mouseIsHeld = false;
8148
8200
  }
8149
8201
 
8202
+ /** Get the size for text with overrides and scale
8203
+ * @return {Vector2}
8204
+ */
8205
+ getTextSize()
8206
+ {
8207
+ return vec2(
8208
+ this.textWidth || this.textScale * this.size.x,
8209
+ this.textHeight || this.textScale * this.size.y);
8210
+ }
8211
+
8150
8212
  /** Called when the mouse enters the object */
8151
8213
  onEnter() {}
8152
8214
 
@@ -8194,7 +8256,7 @@ class UIText extends UIObject
8194
8256
  }
8195
8257
  render()
8196
8258
  {
8197
- const textSize = vec2(this.size.x, this.textHeight || this.size.y);
8259
+ const textSize = this.getTextSize();
8198
8260
  uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
8199
8261
  }
8200
8262
  }
@@ -8262,9 +8324,8 @@ class UIButton extends UIObject
8262
8324
  const color = this.disabled ? this.disabledColor : this.mouseIsOver ? this.hoverColor : this.color;
8263
8325
  uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
8264
8326
 
8265
- // draw the text
8266
- const textScale = .8; // scale text to fit
8267
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
8327
+ // draw the text scaled to fit
8328
+ const textSize = this.getTextSize();
8268
8329
  uiSystem.drawText(this.text, this.pos, textSize,
8269
8330
  this.textColor, 0, undefined, this.align, this.font);
8270
8331
  }
@@ -8313,13 +8374,11 @@ class UICheckbox extends UIObject
8313
8374
  uiSystem.drawLine(this.pos.add(s.multiply(vec2(-1,1))), this.pos.add(s.multiply(vec2(1,-1))), this.lineWidth, this.lineColor);
8314
8375
  }
8315
8376
 
8316
- // draw the text to the right side of the checkbox
8317
- const textScale = .8; // scale text to fit
8318
- const gapScale = .55;
8319
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
8320
- const pos = this.pos.add(vec2(this.size.x*gapScale,0));
8377
+ // draw the text next to the checkbox
8378
+ const textSize = this.getTextSize();
8379
+ const pos = this.pos.add(vec2(this.size.x,0));
8321
8380
  uiSystem.drawText(this.text, pos, textSize,
8322
- this.textColor, 0, undefined, 'left', this.font);
8381
+ this.textColor, 0, undefined, 'left', this.font, false);
8323
8382
  }
8324
8383
  }
8325
8384
 
@@ -8386,9 +8445,8 @@ class UIScrollbar extends UIObject
8386
8445
  this.interactive && this.mouseIsHeld ? this.color : this.handleColor;
8387
8446
  uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
8388
8447
 
8389
- // draw the text on the scrollbar
8390
- const textScale = .8; // scale text to fit in scrollbar
8391
- const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
8448
+ // draw the text scaled to fit on the scrollbar
8449
+ const textSize = this.getTextSize();
8392
8450
  uiSystem.drawText(this.text, this.pos, textSize,
8393
8451
  this.textColor, 0, undefined, this.align, this.font);
8394
8452
  }