littlejsengine 1.17.15 → 1.18.1

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.
package/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ See @AI.md for instructions.
package/README.md CHANGED
@@ -18,6 +18,10 @@ LittleJS is a fast, lightweight, and fully open source HTML5 game engine designe
18
18
  Its small footprint is packed with a comprehensive feature set including rendering, physics, particles, sound, and input handling.
19
19
  The code is very clean and well documented with many examples to get you started quickly.
20
20
 
21
+ ### 🚀 Join the LittleJS Game Jam
22
+
23
+ *The Third Annual LittleJS Game Jam will take place From Oct 2 to Nov 2! Unleash your creativity and develop amazing games using the LittleJS game engine. đŸ•šī¸đŸŽŽ [Sign up today and get more info about the jam on itch.io!](https://itch.io/jam/littlejs-jam)*
24
+
21
25
  <div align='center'>
22
26
 
23
27
  ## [Demos](https://killedbyapixel.github.io/LittleJS/examples) | [Docs](https://killedbyapixel.github.io/LittleJS/docs) | [Trailer](https://youtu.be/chuBzGjv7Ms) | [Discord](https://discord.gg/zb7hcGkyZe) | [FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md)
@@ -30,14 +34,15 @@ The code is very clean and well documented with many examples to get you started
30
34
 
31
35
  ### ✨ Graphics
32
36
 
33
- - Super fast WebGL2 + Canvas2D hybrid rendering system
37
+ - Blazing fast WebGL2 + Canvas2D hybrid rendering system
34
38
  - Apply [Shadertoy](https://www.shadertoy.com) style shaders for post-processing effects
35
39
  - Robust particle effect system and [effect design tool](https://killedbyapixel.github.io/LittleJS/examples/particles/)
36
40
 
37
41
  ### 🔊 Audio
38
42
 
39
43
  - Sound and music with mp3, ogg, or wave files
40
- - Use [ZzFX](https://killedbyapixel.github.io/ZzFX/) sound effect generator to play sounds without asset files
44
+ - Use [ZzFX](https://killedbyapixel.github.io/ZzFX/) sound generator to play sounds without asset files
45
+ - Spatial audio stereo panning
41
46
 
42
47
  ### 🎮 Input
43
48
 
@@ -53,13 +58,14 @@ The code is very clean and well documented with many examples to get you started
53
58
  ### 🚀 Flexibility
54
59
 
55
60
  - Compatible with all modern web browsers and mobile devices
56
- - TypeScript and Module support with example projects for both
61
+ - Full TypeScript and Module support with example projects for both
57
62
  - Great for size coding competitions like [Js13kGames](https://js13kgames.com/)
58
63
  - Open Source and [MIT licensed](https://github.com/KilledByAPixel/LittleJS/blob/main/LICENSE)
59
64
 
60
65
  ### đŸ› ī¸ Developer Tools
61
66
 
62
67
  - Live example browser with code editor
68
+ - Import level editor data from [Tiled](https://github.com/mapeditor/tiled) or other JSON
63
69
  - Debug overlay and primitive rendering system
64
70
  - Medal tracking system with [Newgrounds](https://www.newgrounds.com/) support
65
71
  - Node.js build system
@@ -74,6 +80,8 @@ To get started download the latest LittleJS package from GitHub or install via n
74
80
  - [LittleJS Quick Reference Sheet](https://github.com/KilledByAPixel/LittleJS/blob/main/reference.md) - A reference sheet to help you get started.
75
81
  - [Little JS FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) - Answers to common questions about LittleJS.
76
82
  - [JS13k Branch](https://github.com/KilledByAPixel/LittleJS/tree/js13k) - For size coding events like JS13k there is a special branch that builds to a 7KB zip.
83
+ - [LittleJS GPT AI](https://chatgpt.com/g/g-67c7c080b5bc81919736bc8815836be6-make-games-with-littlejs) - Use AI to make games without writing any code!
84
+ - [LittleJS AI Info](https://github.com/KilledByAPixel/LittleJS-AI) - Experiments, games, and templates to improve LittleJS + AI workflows.
77
85
 
78
86
  ## Examples
79
87
 
@@ -82,7 +90,7 @@ LittleJS comes with a several demos both for learning and using as starter proje
82
90
  - [Example Browser](https://killedbyapixel.github.io/LittleJS/examples/) - Live example browser with all examples
83
91
  - [Breakout](https://killedbyapixel.github.io/LittleJS/examples/breakout/) - Block breaking game with post-processing effects
84
92
  - [Puzzle Game](https://killedbyapixel.github.io/LittleJS/examples/puzzle/) - Match 3 puzzle game with HD rendering and high score tracking
85
- - [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter that loads level data from [Tiled Editor](https://github.com/mapeditor/tiled)
93
+ - [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter demo that loads level data
86
94
  - [Box2D Demo](https://killedbyapixel.github.io/LittleJS/examples/box2d/) - Box2D plugin demonstration and testbed
87
95
  - [Stress Test](https://killedbyapixel.github.io/LittleJS/examples/stress/) - Sprite rendering benchmark and music system demo
88
96
  - [Particle System Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Particle system editor and visualizer
@@ -117,6 +125,7 @@ Here are a few of the many amazing games created with LittleJS...
117
125
  - [Bug&Bee](https://itch.io/jam/littlejs-game-jam-2025/results) - Low fi shoot em up with co-op gameplay. LittleJS Jam 1st place! by [eoinmcg](https://eoinmcg.itch.io/)
118
126
  - [Little Platformer](https://psemo.itch.io/little-platformer) - Platformer with many mechanics. LittleJS Jam 2st place! by [PSEMO](https://psemo.itch.io/), [Solita666](https://itch.io/profile/solita666), [GabrielRG](https://gabrielrg.itch.io/), [Nate](https://natesassoon.itch.io/)
119
127
  - [Rogue Pong](https://itch.io/jam/littlejs-game-jam-2025/rate/4004165) - Roguelike crossed with classic pong gameplay. LittleJS Jam 3rd place! by [webdevbrian](https://webdevbrian.itch.io/)
128
+ - [Orbitswarm](https://focaccai.itch.io/orbitswarm) - Fast paced space strategy game. by [Focaccai](https://www.focaccai.com/)
120
129
  - [LittleJS Jam 2024 Results](https://itch.io/jam/littlejs-jam-2024/results) - All the games from the first LittleJS Game Jam.
121
130
  - [LittleJS Jam 2025 Results](https://itch.io/jam/littlejs-game-jam-2025/results) - All the games from the second LittleJS Game Jam.
122
131
 
@@ -377,6 +377,12 @@ declare module "littlejsengine" {
377
377
  * @default
378
378
  * @memberof Settings */
379
379
  export let tilesPixelated: boolean;
380
+ /** Scale factor applied to the canvas backing store for native-resolution rendering.
381
+ * Pass 1 for no scaling, a number for an explicit ratio, or undefined to track devicePixelRatio each frame.
382
+ * @type {number|undefined}
383
+ * @default
384
+ * @memberof Settings */
385
+ export let canvasPixelRatio: number | undefined;
380
386
  /** Default font used for text rendering
381
387
  * @type {string}
382
388
  * @default
@@ -500,6 +506,11 @@ declare module "littlejsengine" {
500
506
  * @default
501
507
  * @memberof Settings */
502
508
  export let touchGamepadAlpha: number;
509
+ /** How long to display the touch gamepad on screen in seconds, set to 0 to always display
510
+ * @type {number}
511
+ * @default
512
+ * @memberof Settings */
513
+ export let touchGamepadDisplayTime: number;
503
514
  /** Allow vibration hardware if it exists
504
515
  * @type {boolean}
505
516
  * @default
@@ -587,6 +598,11 @@ declare module "littlejsengine" {
587
598
  * @param {boolean} pixelated
588
599
  * @memberof Settings */
589
600
  export function setTilesPixelated(pixelated: boolean): void;
601
+ /** Set the canvas pixel ratio.
602
+ * Pass a number for an explicit ratio, or call with no argument to track devicePixelRatio each frame.
603
+ * @param {number} [pixelRatio]
604
+ * @memberof Settings */
605
+ export function setCanvasPixelRatio(pixelRatio?: number): void;
590
606
  /** Set default font used for text rendering
591
607
  * @param {string} font
592
608
  * @memberof Settings */
@@ -3304,7 +3320,7 @@ declare module "littlejsengine" {
3304
3320
  * - Buttons
3305
3321
  * - Checkboxes
3306
3322
  * - Images
3307
- * - Scrollbars
3323
+ * - Sliders
3308
3324
  * - Video
3309
3325
  * @namespace UISystem
3310
3326
  */
@@ -3719,18 +3735,18 @@ declare module "littlejsengine" {
3719
3735
  * @param {Color} [color=uiSystem.defaultButtonColor]
3720
3736
  */
3721
3737
  constructor(pos?: Vector2, size?: Vector2, checked?: boolean, text?: string, color?: Color);
3722
- /** @property {boolean} - Current percentage value of this scrollbar 0-1 */
3738
+ /** @property {boolean} - Current percentage value of this slider 0-1 */
3723
3739
  checked: boolean;
3724
3740
  text: string;
3725
3741
  click(): void;
3726
3742
  }
3727
3743
  /**
3728
- * UIScrollbar - A UI object that acts as a scrollbar
3744
+ * UISlider - A UI object that acts as a slider or scrollbar
3729
3745
  * @extends UIObject
3730
3746
  * @memberof UISystem
3731
3747
  */
3732
- export class UIScrollbar extends UIObject {
3733
- /** Create a UIScrollbar object
3748
+ export class UISlider extends UIObject {
3749
+ /** Create a UISlider object
3734
3750
  * @param {Vector2} [pos]
3735
3751
  * @param {Vector2} [size]
3736
3752
  * @param {number} [value]
@@ -3739,9 +3755,9 @@ declare module "littlejsengine" {
3739
3755
  * @param {Color} [handleColor=WHITE]
3740
3756
  */
3741
3757
  constructor(pos?: Vector2, size?: Vector2, value?: number, text?: string, color?: Color, handleColor?: Color);
3742
- /** @property {number} - Current percentage value of this scrollbar 0-1 */
3758
+ /** @property {number} - Current percentage value of this slider 0-1 */
3743
3759
  value: number;
3744
- /** @property {Color} - Color for the handle part of the scrollbar */
3760
+ /** @property {Color} - Color for the handle part of the slider */
3745
3761
  handleColor: Color;
3746
3762
  /** @property {boolean} - Should it fill up like a progress bar? */
3747
3763
  fillMode: boolean;
@@ -3921,9 +3937,12 @@ declare module "littlejsengine" {
3921
3937
  /** checks if a box2d object is null
3922
3938
  * @param {Object} o */
3923
3939
  isNull(o: any): boolean;
3924
- /** casts a box2d object to its correct type
3940
+ /** casts a box2d object to a shape type
3941
+ * @param {Object} o */
3942
+ castShapeObject(o: any): any;
3943
+ /** casts a box2d object to a joint type
3925
3944
  * @param {Object} o */
3926
- castObjectType(o: any): any;
3945
+ castJointObject(o: any): any;
3927
3946
  }
3928
3947
  /**
3929
3948
  * Box2D Object - extend with your own custom physics objects
@@ -35,7 +35,7 @@ const engineName = 'LittleJS';
35
35
  * @type {string}
36
36
  * @default
37
37
  * @memberof Engine */
38
- const engineVersion = '1.17.15';
38
+ const engineVersion = '1.18.1';
39
39
 
40
40
  /** Frames per second to update
41
41
  * @type {number}
@@ -318,12 +318,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
318
318
  }
319
319
  else
320
320
  {
321
+ // apply device pixel ratio for crisp rendering
322
+ const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
323
+ const viewWidth = innerWidth * dpr | 0;
324
+ const viewHeight = innerHeight * dpr | 0;
325
+
321
326
  // get main canvas size based on window size
322
- mainCanvasSize.x = min(innerWidth, canvasMaxSize.x);
323
- mainCanvasSize.y = min(innerHeight, canvasMaxSize.y);
327
+ mainCanvasSize.x = min(viewWidth, canvasMaxSize.x);
328
+ mainCanvasSize.y = min(viewHeight, canvasMaxSize.y);
324
329
 
325
330
  // responsive aspect ratio with native resolution
326
- const innerAspect = innerWidth / innerHeight;
331
+ const innerAspect = viewWidth / viewHeight;
327
332
  ASSERT(canvasMinAspect <= canvasMaxAspect);
328
333
  if (canvasMaxAspect && innerAspect > canvasMaxAspect)
329
334
  {
@@ -337,6 +342,17 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
337
342
  const h = mainCanvasSize.x / canvasMinAspect | 0;
338
343
  mainCanvasSize.y = min(h, canvasMaxSize.y);
339
344
  }
345
+
346
+ // set CSS display size so backing store renders at viewport size
347
+ const cssW = (mainCanvasSize.x / dpr | 0) + 'px';
348
+ const cssH = (mainCanvasSize.y / dpr | 0) + 'px';
349
+ mainCanvas.style.width = cssW;
350
+ mainCanvas.style.height = cssH;
351
+ if (glCanvas)
352
+ {
353
+ glCanvas.style.width = cssW;
354
+ glCanvas.style.height = cssH;
355
+ }
340
356
  }
341
357
 
342
358
  // clear main canvas and set size
@@ -556,8 +572,9 @@ function drawEngineLogo(t)
556
572
 
557
573
  // LittleJS Logo and Splash Screen
558
574
  const x = mainContext;
559
- const w = mainCanvas.width = innerWidth;
560
- const h = mainCanvas.height = innerHeight;
575
+ const dpr = canvasPixelRatio ?? (devicePixelRatio || 1);
576
+ const w = mainCanvas.width = innerWidth * dpr;
577
+ const h = mainCanvas.height = innerHeight * dpr;
561
578
  {
562
579
  // background
563
580
  const p3 = percent(t, 1, .8);
@@ -951,6 +968,8 @@ function debugShowErrors()
951
968
 
952
969
  function debugInit()
953
970
  {
971
+ if (showEngineVersion)
972
+ console.warn("LittleJS DEBUG build loaded. Use the release build for production.");
954
973
  }
955
974
 
956
975
  function debugUpdate()
@@ -961,8 +980,6 @@ function debugUpdate()
961
980
  debugOverlay = !debugOverlay;
962
981
  if (debugOverlay)
963
982
  {
964
- if (keyWasPressed('Digit0'))
965
- debugWatermark = !debugWatermark;
966
983
  if (keyWasPressed('Digit1'))
967
984
  debugPhysics = !debugPhysics, debugParticles = false;
968
985
  if (keyWasPressed('Digit2'))
@@ -1250,7 +1267,7 @@ function debugRenderPost()
1250
1267
  return;
1251
1268
  }
1252
1269
 
1253
- if (!debugWatermark) return;
1270
+ if (!debugWatermark && !debugOverlay) return;
1254
1271
 
1255
1272
  // update fps display
1256
1273
  mainContext.textAlign = 'right';
@@ -1734,7 +1751,7 @@ function lineTest(posStart, posEnd, testFunction, normal)
1734
1751
  // get ray direction and length
1735
1752
  const dx = posEnd.x - posStart.x;
1736
1753
  const dy = posEnd.y - posStart.y;
1737
- const totalLength = hypot(dx, dy);
1754
+ const totalLength = (dx*dx + dy*dy)**.5;
1738
1755
  if (!totalLength) return;
1739
1756
 
1740
1757
  // current integer cell we are in
@@ -2838,6 +2855,13 @@ let canvasPixelated = false;
2838
2855
  * @memberof Settings */
2839
2856
  let tilesPixelated = true;
2840
2857
 
2858
+ /** Scale factor applied to the canvas backing store for native-resolution rendering.
2859
+ * Pass 1 for no scaling, a number for an explicit ratio, or undefined to track devicePixelRatio each frame.
2860
+ * @type {number|undefined}
2861
+ * @default
2862
+ * @memberof Settings */
2863
+ let canvasPixelRatio = 1;
2864
+
2841
2865
  /** Default font used for text rendering
2842
2866
  * @type {string}
2843
2867
  * @default
@@ -3016,6 +3040,12 @@ let touchGamepadSize = 99;
3016
3040
  * @memberof Settings */
3017
3041
  let touchGamepadAlpha = .3;
3018
3042
 
3043
+ /** How long to display the touch gamepad on screen in seconds, set to 0 to always display
3044
+ * @type {number}
3045
+ * @default
3046
+ * @memberof Settings */
3047
+ let touchGamepadDisplayTime = 3;
3048
+
3019
3049
  /** Allow vibration hardware if it exists
3020
3050
  * @type {boolean}
3021
3051
  * @default
@@ -3144,6 +3174,12 @@ function setCanvasPixelated(pixelated)
3144
3174
  * @memberof Settings */
3145
3175
  function setTilesPixelated(pixelated) { tilesPixelated = pixelated; }
3146
3176
 
3177
+ /** Set the canvas pixel ratio.
3178
+ * Pass a number for an explicit ratio, or call with no argument to track devicePixelRatio each frame.
3179
+ * @param {number} [pixelRatio]
3180
+ * @memberof Settings */
3181
+ function setCanvasPixelRatio(pixelRatio) { canvasPixelRatio = pixelRatio; }
3182
+
3147
3183
  /** Set default font used for text rendering
3148
3184
  * @param {string} font
3149
3185
  * @memberof Settings */
@@ -3290,6 +3326,11 @@ function setTouchGamepadSize(size) { touchGamepadSize = size; }
3290
3326
  * @memberof Settings */
3291
3327
  function setTouchGamepadAlpha(alpha) { touchGamepadAlpha = alpha; }
3292
3328
 
3329
+ /** Set how long to display the touch gamepad on screen in seconds, set to 0 to always display
3330
+ * @param {number} time
3331
+ * @memberof Settings */
3332
+ function setTouchGamepadDisplayTime(time) { touchGamepadDisplayTime = time; }
3333
+
3293
3334
  /** Set to allow vibration hardware if it exists
3294
3335
  * @param {boolean} enable
3295
3336
  * @memberof Settings */
@@ -3561,10 +3602,10 @@ class EngineObject
3561
3602
  // if already was touching, try to push away
3562
3603
  const deltaPos = oldPos.subtract(o.pos);
3563
3604
  const length = deltaPos.length();
3564
- const pushAwayAccel = .001; // push away if already overlapping
3565
- const velocity = length < .01 ? randVec2(pushAwayAccel) : deltaPos.scale(pushAwayAccel/length);
3605
+ const pushAwayAccel = .001;
3606
+ const velocity = length < .001 ? vec2(0,1) : deltaPos.scale(pushAwayAccel/length);
3566
3607
  this.velocity = this.velocity.add(velocity);
3567
- if (o.mass) // push away if not fixed
3608
+ if (o.mass) // push away other object if not fixed
3568
3609
  o.velocity = o.velocity.subtract(velocity);
3569
3610
 
3570
3611
  debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
@@ -3993,6 +4034,7 @@ function tile(index=new Vector2, size=tileDefaultSize, texture=0, padding=tileDe
3993
4034
  const textureInfo = typeof texture === 'number' ?
3994
4035
  textureInfos[texture] : texture;
3995
4036
  ASSERT(textureInfo instanceof TextureInfo, 'tile texture is not loaded');
4037
+ ASSERT(textureInfo.size.x > 0, 'tile texture is not loaded');
3996
4038
 
3997
4039
  // get the position of the tile
3998
4040
  const sizePaddedX = size.x + padding*2;
@@ -5355,7 +5397,7 @@ function inputInit()
5355
5397
  document.addEventListener('mouseup', onMouseUp);
5356
5398
  document.addEventListener('mousemove', onMouseMove);
5357
5399
  document.addEventListener('mouseleave', onMouseLeave);
5358
- document.addEventListener('wheel', onMouseWheel);
5400
+ document.addEventListener('wheel', onMouseWheel, { passive: false });
5359
5401
  document.addEventListener('contextmenu', onContextMenu);
5360
5402
  document.addEventListener('blur', onBlur);
5361
5403
 
@@ -5374,7 +5416,7 @@ function inputInit()
5374
5416
  }
5375
5417
 
5376
5418
  // try to prevent default browser handling of input
5377
- if (!inputPreventDefault || !document.hasFocus() || !e.cancelable) return;
5419
+ if (!inputPreventDefault || !e.cancelable || !document.hasFocus()) return;
5378
5420
 
5379
5421
  // don't break browser shortcuts
5380
5422
  if (e.ctrlKey || e.metaKey || e.altKey) return;
@@ -5433,7 +5475,7 @@ function inputInit()
5433
5475
  mousePosScreen = mouseEventToScreen(vec2(e.x,e.y));
5434
5476
  mouseDeltaScreen = mouseDeltaScreen.add(mousePosScreen.subtract(mousePosScreenLast));
5435
5477
 
5436
- if (inputPreventDefault && document.hasFocus() && e.cancelable)
5478
+ if (inputPreventDefault && e.cancelable && document.hasFocus())
5437
5479
  e.preventDefault();
5438
5480
  }
5439
5481
  function onMouseUp(e)
@@ -5455,7 +5497,12 @@ function inputInit()
5455
5497
  mouseDeltaScreen = mouseDeltaScreen.add(movement);
5456
5498
  }
5457
5499
  function onMouseLeave() { mouseInWindow = false; } // mouse moved off window
5458
- function onMouseWheel(e) { mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY); }
5500
+ function onMouseWheel(e)
5501
+ {
5502
+ mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
5503
+ if (inputPreventDefault && e.cancelable && document.hasFocus())
5504
+ e.preventDefault(); // prevent page scrolling
5505
+ }
5459
5506
  function onContextMenu(e) { e.preventDefault(); } // prevent right click menu
5460
5507
  function onBlur() { inputClear(); } // reset input when focus is lost
5461
5508
 
@@ -5505,7 +5552,7 @@ function inputInit()
5505
5552
  wasTouching = touching;
5506
5553
 
5507
5554
  // prevent default handling like copy, magnifier lens, and scrolling
5508
- if (inputPreventDefault && document.hasFocus() && e.cancelable)
5555
+ if (inputPreventDefault && e.cancelable && document.hasFocus())
5509
5556
  e.preventDefault();
5510
5557
 
5511
5558
  // must return true so the document will get focus
@@ -5663,7 +5710,13 @@ function inputUpdate()
5663
5710
  }
5664
5711
 
5665
5712
  // return if gamepads are disabled or not supported
5666
- if (!gamepadsEnable || !navigator || !navigator.getGamepads) return;
5713
+ try {
5714
+ // protect against getGamepads disallowed security error
5715
+ if (!gamepadsEnable || !navigator?.getGamepads)
5716
+ return;
5717
+ } catch(e) {
5718
+ return;
5719
+ }
5667
5720
 
5668
5721
  // only poll gamepads when focused or in debug mode
5669
5722
  if (!debug && !document.hasFocus()) return;
@@ -5761,10 +5814,10 @@ function inputRender()
5761
5814
  function touchGamepadRender()
5762
5815
  {
5763
5816
  if (!touchInputEnable || !isTouchDevice || headlessMode) return;
5764
- if (!touchGamepadEnable || !touchGamepadTimer.isSet()) return;
5817
+ if (!touchGamepadEnable || !touchGamepadTimer.isSet() && touchGamepadDisplayTime) return;
5765
5818
 
5766
5819
  // fade off when not touching or paused
5767
- const alpha = percent(touchGamepadTimer.get(), 4, 3);
5820
+ const alpha = touchGamepadDisplayTime ? percent(touchGamepadTimer.get(), touchGamepadDisplayTime+1, touchGamepadDisplayTime) : 1;
5768
5821
  if (!alpha || paused) return;
5769
5822
 
5770
5823
  // setup the canvas
@@ -9335,7 +9388,7 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
9335
9388
  * - Buttons
9336
9389
  * - Checkboxes
9337
9390
  * - Images
9338
- * - Scrollbars
9391
+ * - Sliders
9339
9392
  * - Video
9340
9393
  * @namespace UISystem
9341
9394
  */
@@ -10532,7 +10585,7 @@ class UICheckbox extends UIObject
10532
10585
  ASSERT(isString(text), 'ui checkbox must be a string');
10533
10586
  ASSERT(isColor(color), 'ui checkbox color must be a color');
10534
10587
 
10535
- /** @property {boolean} - Current percentage value of this scrollbar 0-1 */
10588
+ /** @property {boolean} - Current percentage value of this slider 0-1 */
10536
10589
  this.checked = checked;
10537
10590
  // set properties
10538
10591
  this.text = text;
@@ -10567,13 +10620,13 @@ class UICheckbox extends UIObject
10567
10620
 
10568
10621
  ///////////////////////////////////////////////////////////////////////////////
10569
10622
  /**
10570
- * UIScrollbar - A UI object that acts as a scrollbar
10623
+ * UISlider - A UI object that acts as a slider or scrollbar
10571
10624
  * @extends UIObject
10572
10625
  * @memberof UISystem
10573
10626
  */
10574
- class UIScrollbar extends UIObject
10627
+ class UISlider extends UIObject
10575
10628
  {
10576
- /** Create a UIScrollbar object
10629
+ /** Create a UISlider object
10577
10630
  * @param {Vector2} [pos]
10578
10631
  * @param {Vector2} [size]
10579
10632
  * @param {number} [value]
@@ -10585,14 +10638,14 @@ class UIScrollbar extends UIObject
10585
10638
  {
10586
10639
  super(pos, size);
10587
10640
 
10588
- ASSERT(isNumber(value), 'ui scrollbar value must be a number');
10589
- ASSERT(isString(text), 'ui scrollbar must be a string');
10590
- ASSERT(isColor(color), 'ui scrollbar color must be a color');
10591
- ASSERT(isColor(handleColor), 'ui scrollbar handleColor must be a color');
10641
+ ASSERT(isNumber(value), 'ui slider value must be a number');
10642
+ ASSERT(isString(text), 'ui slider must be a string');
10643
+ ASSERT(isColor(color), 'ui slider color must be a color');
10644
+ ASSERT(isColor(handleColor), 'ui slider handleColor must be a color');
10592
10645
 
10593
- /** @property {number} - Current percentage value of this scrollbar 0-1 */
10646
+ /** @property {number} - Current percentage value of this slider 0-1 */
10594
10647
  this.value = value;
10595
- /** @property {Color} - Color for the handle part of the scrollbar */
10648
+ /** @property {Color} - Color for the handle part of the slider */
10596
10649
  this.handleColor = handleColor.copy();
10597
10650
  /** @property {boolean} - Should it fill up like a progress bar? */
10598
10651
  this.fillMode = false;
@@ -10611,7 +10664,7 @@ class UIScrollbar extends UIObject
10611
10664
  const oldValue = this.value;
10612
10665
  if (this.isActiveObject())
10613
10666
  {
10614
- // handle horizontal or vertical scrollbar
10667
+ // handle horizontal or vertical slider
10615
10668
  const isHorizontal = this.size.x > this.size.y;
10616
10669
  const handleSize = isHorizontal ? this.size.y : this.size.x;
10617
10670
  const barSize = isHorizontal ? this.size.x : this.size.y;
@@ -10639,7 +10692,7 @@ class UIScrollbar extends UIObject
10639
10692
  {
10640
10693
  super.render();
10641
10694
 
10642
- // handle horizontal or vertical scrollbar
10695
+ // handle horizontal or vertical slider
10643
10696
  const isHorizontal = this.size.x > this.size.y;
10644
10697
  const barWidth = isHorizontal ? this.size.x : this.size.y;
10645
10698
  const handleWidth = isHorizontal ? this.size.y : this.size.x;
@@ -10657,7 +10710,7 @@ class UIScrollbar extends UIObject
10657
10710
  }
10658
10711
  else
10659
10712
  {
10660
- // draw the scrollbar handle
10713
+ // draw the slider handle
10661
10714
  const value = clamp(isHorizontal ? this.value : 1 - this.value);
10662
10715
  const p = (barWidth - handleWidth) * (value - .5);
10663
10716
  const pos = this.pos.add(isHorizontal ? vec2(p, 0) : vec2(0, p));
@@ -10666,7 +10719,7 @@ class UIScrollbar extends UIObject
10666
10719
  uiSystem.drawRect(pos, drawSize, color, this.lineWidth, this.lineColor, this.cornerRadius, this.gradientColor);
10667
10720
  }
10668
10721
 
10669
- // draw the text scaled to fit on the scrollbar
10722
+ // draw the text scaled to fit on the slider
10670
10723
  const textSize = this.getTextSize();
10671
10724
  uiSystem.drawText(this.text, this.pos, textSize,
10672
10725
  this.textColor, this.textLineWidth, this.textLineColor, this.align, this.font, this.fontStyle, true, this.textShadow);
@@ -10941,7 +10994,7 @@ class Box2dObject extends EngineObject
10941
10994
  // draw non-edge fixtures
10942
10995
  this.getFixtureList().forEach((fixture)=>
10943
10996
  {
10944
- const shape = box2d.castObjectType(fixture.GetShape());
10997
+ const shape = box2d.castShapeObject(fixture.GetShape());
10945
10998
  if (shape.GetType() !== box2d.instance.b2Shape.e_edge)
10946
10999
  {
10947
11000
  box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, useWebGL, context);
@@ -11581,7 +11634,7 @@ class Box2dJoint
11581
11634
  constructor(jointDef)
11582
11635
  {
11583
11636
  /** @property {Object} - The Box2d joint */
11584
- this.box2dJoint = box2d.castObjectType(box2d.world.CreateJoint(jointDef));
11637
+ this.box2dJoint = box2d.castJointObject(box2d.world.CreateJoint(jointDef));
11585
11638
  }
11586
11639
 
11587
11640
  /** Destroy this joint */
@@ -11866,7 +11919,7 @@ class Box2dRevoluteJoint extends Box2dJoint
11866
11919
 
11867
11920
  /** Enable/disable the joint limit
11868
11921
  * @param {boolean} [enable] */
11869
- enableLimit(enable=true) { return this.box2dJoint.enableLimit(enable); }
11922
+ enableLimit(enable=true) { return this.box2dJoint.EnableLimit(enable); }
11870
11923
 
11871
11924
  /** Get the lower joint limit
11872
11925
  * @return {number} */
@@ -12024,7 +12077,7 @@ class Box2dPrismaticJoint extends Box2dJoint
12024
12077
 
12025
12078
  /** Enable/disable the joint limit
12026
12079
  * @param {boolean} [enable] */
12027
- enableLimit(enable=true) { return this.box2dJoint.enableLimit(enable); }
12080
+ enableLimit(enable=true) { return this.box2dJoint.EnableLimit(enable); }
12028
12081
 
12029
12082
  /** Get the lower joint limit
12030
12083
  * @return {number} */
@@ -12638,7 +12691,7 @@ class Box2dPlugin
12638
12691
  * @param {CanvasRenderingContext2D} [context] */
12639
12692
  drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, useWebgl, context)
12640
12693
  {
12641
- const shape = box2d.castObjectType(fixture.GetShape());
12694
+ const shape = box2d.castShapeObject(fixture.GetShape());
12642
12695
  switch (shape.GetType())
12643
12696
  {
12644
12697
  case box2d.instance.b2Shape.e_polygon:
@@ -12696,9 +12749,9 @@ class Box2dPlugin
12696
12749
  * @param {Object} o */
12697
12750
  isNull(o) { return !box2d.instance.getPointer(o); }
12698
12751
 
12699
- /** casts a box2d object to its correct type
12752
+ /** casts a box2d object to a shape type
12700
12753
  * @param {Object} o */
12701
- castObjectType(o)
12754
+ castShapeObject(o)
12702
12755
  {
12703
12756
  switch (o.GetType())
12704
12757
  {
@@ -12710,6 +12763,17 @@ class Box2dPlugin
12710
12763
  return box2d.instance.castObject(o, box2d.instance.b2PolygonShape);
12711
12764
  case box2d.instance.b2Shape.e_chain:
12712
12765
  return box2d.instance.castObject(o, box2d.instance.b2ChainShape);
12766
+ }
12767
+
12768
+ ASSERT(false, 'Unknown box2d object type');
12769
+ }
12770
+
12771
+ /** casts a box2d object to a joint type
12772
+ * @param {Object} o */
12773
+ castJointObject(o)
12774
+ {
12775
+ switch (o.GetType())
12776
+ {
12713
12777
  case box2d.instance.e_revoluteJoint:
12714
12778
  return box2d.instance.castObject(o, box2d.instance.b2RevoluteJoint);
12715
12779
  case box2d.instance.e_prismaticJoint:
@@ -13040,6 +13104,7 @@ export
13040
13104
  canvasFixedSize,
13041
13105
  canvasPixelated,
13042
13106
  tilesPixelated,
13107
+ canvasPixelRatio,
13043
13108
  fontDefault,
13044
13109
  showSplashScreen,
13045
13110
  headlessMode,
@@ -13064,6 +13129,7 @@ export
13064
13129
  touchGamepadAnalog,
13065
13130
  touchGamepadSize,
13066
13131
  touchGamepadAlpha,
13132
+ touchGamepadDisplayTime,
13067
13133
  vibrateEnable,
13068
13134
  soundEnable,
13069
13135
  soundVolume,
@@ -13085,6 +13151,7 @@ export
13085
13151
  setCanvasFixedSize,
13086
13152
  setCanvasPixelated,
13087
13153
  setTilesPixelated,
13154
+ setCanvasPixelRatio,
13088
13155
  setFontDefault,
13089
13156
  setShowSplashScreen,
13090
13157
  setHeadlessMode,
@@ -13360,7 +13427,7 @@ export
13360
13427
  UITile,
13361
13428
  UIButton,
13362
13429
  UICheckbox,
13363
- UIScrollbar,
13430
+ UISlider,
13364
13431
  UIVideo,
13365
13432
 
13366
13433
  // Box2D Physics