littlejsengine 1.10.2 → 1.10.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 (53) hide show
  1. package/README.md +15 -93
  2. package/dist/littlejs.d.ts +79 -17
  3. package/dist/littlejs.esm.js +179 -90
  4. package/dist/littlejs.esm.min.js +1 -1
  5. package/dist/littlejs.js +165 -90
  6. package/dist/littlejs.min.js +1 -1
  7. package/dist/littlejs.release.js +165 -90
  8. package/examples/box2d/game.js +15 -1
  9. package/examples/box2d/gameObjects.js +10 -9
  10. package/examples/box2d/index.html +5 -5
  11. package/examples/box2d/scenes.js +4 -4
  12. package/examples/box2d/tiles.png +0 -0
  13. package/examples/breakout/index.html +3 -3
  14. package/examples/breakoutTutorial/README.md +9 -7
  15. package/examples/breakoutTutorial/game.js +6 -6
  16. package/examples/breakoutTutorial/index.html +2 -2
  17. package/examples/electron/game.js +3 -0
  18. package/examples/electron/index.html +2 -2
  19. package/examples/htmlMenu/index.html +3 -3
  20. package/examples/js13k/game.js +3 -0
  21. package/examples/js13k/index.html +13 -13
  22. package/examples/module/game.js +3 -0
  23. package/examples/module/index.html +1 -1
  24. package/examples/particles/index.html +4 -1
  25. package/examples/platformer/game.js +21 -15
  26. package/examples/platformer/gameCharacter.js +15 -14
  27. package/examples/platformer/gameEffects.js +3 -4
  28. package/examples/platformer/gameLevel.js +18 -33
  29. package/examples/platformer/gameObjects.js +9 -14
  30. package/examples/platformer/index.html +8 -8
  31. package/examples/platformer/tiles.png +0 -0
  32. package/examples/puzzle/index.html +2 -2
  33. package/examples/starter/game.js +3 -0
  34. package/examples/starter/index.html +13 -13
  35. package/examples/stress/index.html +1 -1
  36. package/examples/typescript/game.js +2 -0
  37. package/examples/typescript/game.ts +4 -1
  38. package/examples/typescript/index.html +1 -1
  39. package/examples/uiSystem/game.js +23 -16
  40. package/examples/uiSystem/index.html +3 -14
  41. package/package.json +1 -1
  42. package/plugins/postProcess.js +1 -1
  43. package/plugins/uiSystem.js +84 -24
  44. package/src/engine.js +14 -22
  45. package/src/engineAudio.js +7 -13
  46. package/src/engineDraw.js +20 -19
  47. package/src/engineExport.js +14 -0
  48. package/src/engineInput.js +8 -6
  49. package/src/engineMedals.js +19 -5
  50. package/src/engineObject.js +9 -5
  51. package/src/engineTileLayer.js +10 -8
  52. package/src/engineUtilities.js +60 -10
  53. package/src/engineWebGL.js +17 -2
@@ -12,16 +12,14 @@ const tileType_empty = 0;
12
12
  const tileType_solid = 1;
13
13
  const tileType_breakable = 2;
14
14
 
15
- let player, playerStartPos, tileData, tileLayers, foregroundLayerIndex, sky;
16
- let levelSize, levelColor, levelBackgroundColor, levelOutlineColor, warmup;
17
-
18
- const setTileData = (pos, layer, data)=>
19
- pos.arrayCheck(tileCollisionSize) && (tileData[layer][(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
20
- const getTileData = (pos, layer)=>
21
- pos.arrayCheck(tileCollisionSize) ? tileData[layer][(pos.y|0)*tileCollisionSize.x+pos.x|0]: 0;
15
+ let player, playerStartPos, tileLayers, foregroundLayerIndex, sky;
16
+ let levelSize, levelColor, levelBackgroundColor, levelOutlineColor;
22
17
 
23
18
  function buildLevel()
24
19
  {
20
+ // destroy all objects
21
+ engineObjectsDestroy();
22
+
25
23
  // create the level
26
24
  levelColor = randColor(hsl(0,0,.2), hsl(0,0,.8));
27
25
  levelBackgroundColor = levelColor.mutate().scale(.4,1);
@@ -34,33 +32,18 @@ function buildLevel()
34
32
  // create parallax layers
35
33
  for (let i=3; i--;)
36
34
  new ParallaxLayer(i);
37
-
38
- // apply decoration to all level tiles
39
- const pos = vec2();
40
- const layerCount = tileLayers.length;
41
- for (let layer=layerCount; layer--;)
42
- for (pos.x=levelSize.x; pos.x--;)
43
- for (pos.y=levelSize.y; pos.y--;)
44
- decorateTile(pos, layer);
45
-
46
- // warm up level
47
- warmup = 1;
48
- for (let i = 500; i--;)
49
- engineObjectsUpdate();
50
- warmup = 0;
51
35
 
52
36
  // spawn player
53
37
  player = new Player(playerStartPos);
38
+ cameraPos = getCameraTarget();
54
39
  }
55
40
 
56
41
  function loadLevel(level=0)
57
42
  {
58
43
  // load level data from an exported Tiled js file
59
- const dataName = Object.keys(TileMaps)[level];
60
- const tileMapData = TileMaps[dataName];
44
+ const tileMapData = TileMaps['gameLevelData'];
61
45
  levelSize = vec2(tileMapData.width, tileMapData.height);
62
46
  initTileCollision(levelSize);
63
- engineObjectsDestroy();
64
47
 
65
48
  // create table for tiles in the level tilemap
66
49
  const tileLookup =
@@ -76,7 +59,6 @@ function loadLevel(level=0)
76
59
  }
77
60
 
78
61
  // set all level data tiles
79
- tileData = [];
80
62
  tileLayers = [];
81
63
  playerStartPos = vec2(1, levelSize.y);
82
64
  const layerCount = tileMapData.layers.length;
@@ -87,7 +69,6 @@ function loadLevel(level=0)
87
69
  const tileLayer = new TileLayer(vec2(), levelSize, tile(0,16,1));
88
70
  tileLayer.renderOrder = -1e3+layer;
89
71
  tileLayers[layer] = tileLayer;
90
- tileData[layer] = [];
91
72
 
92
73
  for (let x=levelSize.x; x--;)
93
74
  for (let y=levelSize.y; y--;)
@@ -109,10 +90,7 @@ function loadLevel(level=0)
109
90
  new Coin(objectPos);
110
91
  continue;
111
92
  }
112
-
113
- // set the tile data
114
- setTileData(pos, layer, tile);
115
-
93
+
116
94
  // get tile type for special tiles
117
95
  let tileType = tileType_empty;
118
96
  if (tile > 0)
@@ -144,6 +122,13 @@ function loadLevel(level=0)
144
122
  }
145
123
  tileLayer.redraw();
146
124
  }
125
+
126
+ // apply decoration to all level tiles
127
+ const pos = vec2();
128
+ for (let layer=layerCount; layer--;)
129
+ for (pos.x=levelSize.x; pos.x--;)
130
+ for (pos.y=levelSize.y; pos.y--;)
131
+ decorateTile(pos, layer);
147
132
  }
148
133
 
149
134
  function decorateTile(pos, layer=1)
@@ -181,11 +166,11 @@ function decorateTile(pos, layer=1)
181
166
  else
182
167
  {
183
168
  // make round corners
184
- for (let i=4;i--;)
169
+ for (let i=4; i--;)
185
170
  {
186
171
  // check corner neighbors
187
- const neighborTileDataA = getTileData(pos.add(vec2().setDirection(i)), layer);
188
- const neighborTileDataB = getTileData(pos.add(vec2().setAngle((i+1)%4*PI/2)), layer);
172
+ const neighborTileDataA = tileLayer.getData(pos.add(vec2().setDirection(i))).tile;
173
+ const neighborTileDataB = tileLayer.getData(pos.add(vec2().setDirection((i+1)%4))).tile;
189
174
  if (neighborTileDataA > 0 || neighborTileDataB > 0)
190
175
  continue;
191
176
 
@@ -23,17 +23,14 @@ class GameObject extends EngineObject
23
23
  super.update();
24
24
 
25
25
  // flash white when damaged
26
+ let brightness = 0;
26
27
  if (!this.isDead() && this.damageTimer.isSet())
27
- {
28
- const a = .5*percent(this.damageTimer, .15, 0);
29
- this.additiveColor = hsl(0,0,a,0);
30
- }
31
- else
32
- this.additiveColor = hsl(0,0,0,0);
28
+ brightness = .5*percent(this.damageTimer, .15, 0);
29
+ this.additiveColor = hsl(0,0,brightness,0);
33
30
 
34
31
  // kill if below level
35
32
  if (!this.isDead() && this.pos.y < -9)
36
- warmup ? this.destroy() : this.kill();
33
+ this.kill();
37
34
  }
38
35
 
39
36
  damage(damage, damagingObject)
@@ -104,10 +101,10 @@ class Coin extends EngineObject
104
101
  drawTile(this.pos, vec2(.5+.5*Math.sin(t*2*PI), 1), this.tileInfo, this.color);
105
102
  }
106
103
 
107
- update(o)
104
+ update()
108
105
  {
109
106
  if (!player)
110
- return;
107
+ return;
111
108
 
112
109
  // check if player in range
113
110
  const d = this.pos.distanceSquared(player.pos);
@@ -145,9 +142,7 @@ class Enemy extends GameObject
145
142
 
146
143
  // jump around randomly
147
144
  if (this.groundObject && rand() < .01 && this.pos.distance(player.pos) < 20)
148
- {
149
145
  this.velocity = vec2(rand(.1,-.1), rand(.4,.2));
150
- }
151
146
 
152
147
  // damage player if touching
153
148
  if (isOverlapping(this.pos, this.size, player.pos, player.size))
@@ -344,17 +339,17 @@ class Bullet extends EngineObject
344
339
  }
345
340
 
346
341
  this.kill();
347
- return 1;
342
+ return true;
348
343
  }
349
344
 
350
345
  collideWithTile(data, pos)
351
346
  {
352
347
  if (data <= 0)
353
- return 0;
348
+ return false;
354
349
 
355
350
  destroyTile(pos);
356
351
  this.kill();
357
- return 1;
352
+ return true;
358
353
  }
359
354
 
360
355
  kill()
@@ -7,11 +7,11 @@
7
7
  <link rel=icon type=image/png href=../favicon.png>
8
8
  </head><body>
9
9
 
10
- <script src=../../dist/littlejs.js?1100></script>
11
- <script src=gameObjects.js?1100></script>
12
- <script src=gameCharacter.js?1100></script>
13
- <script src=gamePlayer.js?1100></script>
14
- <script src=gameEffects.js?1100></script>
15
- <script src=gameLevel.js?1100></script>
16
- <script src=gameLevelData.js?1100></script>
17
- <script src=game.js?1100></script>
10
+ <script src=../../dist/littlejs.js?1105></script>
11
+ <script src=gameObjects.js?1105></script>
12
+ <script src=gameCharacter.js?1105></script>
13
+ <script src=gamePlayer.js?1105></script>
14
+ <script src=gameEffects.js?1105></script>
15
+ <script src=gameLevel.js?1105></script>
16
+ <script src=gameLevelData.js?1105></script>
17
+ <script src=game.js?1105></script>
Binary file
@@ -6,5 +6,5 @@
6
6
  <link rel=icon type=image/png href=../favicon.png>
7
7
  </head><body>
8
8
 
9
- <script src=../../dist/littlejs.js?1100></script>
10
- <script src=game.js?1100></script>
9
+ <script src=../../dist/littlejs.js?1105></script>
10
+ <script src=game.js?1105></script>
@@ -10,6 +10,9 @@
10
10
  // show the LittleJS splash screen
11
11
  setShowSplashScreen(true);
12
12
 
13
+ // fix texture bleeding by shrinking tile slightly
14
+ tileFixBleedScale = .5;
15
+
13
16
  // sound effects
14
17
  const sound_click = new Sound([1,.5]);
15
18
 
@@ -7,18 +7,18 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../src/engineDebug.js?1100></script>
11
- <script src=../../src/engineUtilities.js?1100></script>
12
- <script src=../../src/engineSettings.js?1100></script>
13
- <script src=../../src/engineObject.js?1100></script>
14
- <script src=../../src/engineDraw.js?1100></script>
15
- <script src=../../src/engineInput.js?1100></script>
16
- <script src=../../src/engineAudio.js?1100></script>
17
- <script src=../../src/engineTileLayer.js?1100></script>
18
- <script src=../../src/engineParticles.js?1100></script>
19
- <script src=../../src/engineMedals.js?1100></script>
20
- <script src=../../src/engineWebGL.js?1100></script>
21
- <script src=../../src/engine.js?1100></script>
10
+ <script src=../../src/engineDebug.js?1105></script>
11
+ <script src=../../src/engineUtilities.js?1105></script>
12
+ <script src=../../src/engineSettings.js?1105></script>
13
+ <script src=../../src/engineObject.js?1105></script>
14
+ <script src=../../src/engineDraw.js?1105></script>
15
+ <script src=../../src/engineInput.js?1105></script>
16
+ <script src=../../src/engineAudio.js?1105></script>
17
+ <script src=../../src/engineTileLayer.js?1105></script>
18
+ <script src=../../src/engineParticles.js?1105></script>
19
+ <script src=../../src/engineMedals.js?1105></script>
20
+ <script src=../../src/engineWebGL.js?1105></script>
21
+ <script src=../../src/engine.js?1105></script>
22
22
 
23
23
  <!-- Add your game scripts here -->
24
- <script src=game.js?1100></script>
24
+ <script src=game.js?1105></script>
@@ -7,7 +7,7 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../dist/littlejs.min.js?1100></script>
10
+ <script src=../../dist/littlejs.min.js?1105></script>
11
11
  <script>
12
12
 
13
13
  /*
@@ -9,6 +9,8 @@ import * as LittleJS from '../../dist/littlejs.esm.js';
9
9
  const { tile, vec2, hsl } = LittleJS;
10
10
  // show the LittleJS splash screen
11
11
  LittleJS.setShowSplashScreen(true);
12
+ // fix texture bleeding by shrinking tile slightly
13
+ LittleJS.setTileFixBleedScale(.5);
12
14
  // sound effects
13
15
  const sound_click = new LittleJS.Sound([1, .5]);
14
16
  // medals
@@ -13,6 +13,9 @@ const {tile, vec2, hsl} = LittleJS;
13
13
  // show the LittleJS splash screen
14
14
  LittleJS.setShowSplashScreen(true);
15
15
 
16
+ // fix texture bleeding by shrinking tile slightly
17
+ LittleJS.setTileFixBleedScale(.5);
18
+
16
19
  // sound effects
17
20
  const sound_click = new LittleJS.Sound([1,.5]);
18
21
 
@@ -128,4 +131,4 @@ function gameRenderPost()
128
131
 
129
132
  ///////////////////////////////////////////////////////////////////////////////
130
133
  // Startup LittleJS Engine
131
- LittleJS.engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost);
134
+ LittleJS.engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, ['tiles.png']);
@@ -7,4 +7,4 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- Add your game scripts here -->
10
- <script src=game.js?1100 type=module></script>
10
+ <script src=game.js?1105 type=module></script>
@@ -10,7 +10,7 @@
10
10
  setShowSplashScreen(true);
11
11
 
12
12
  // sound effects
13
- const sound_click = new Sound([1,0]);
13
+ const sound_ui = new Sound([1,0]);
14
14
 
15
15
  // UI system
16
16
  let uiRoot, uiMenu;
@@ -20,7 +20,7 @@ const setMenuVisible =(visible)=> uiMenu.visible = visible;
20
20
  function createUI()
21
21
  {
22
22
  // setup root to attach all ui elements to
23
- uiRoot = new UIObject(vec2(mainCanvasSize.x/2,0));
23
+ uiRoot = new UIObject();
24
24
  const uiInfo = new UIText(vec2(0,50), vec2(1e3, 70),
25
25
  'LittleJS UI System Example\nM = Toggle menu');
26
26
  uiInfo.textColor = WHITE;
@@ -30,54 +30,61 @@ function createUI()
30
30
  // setup example menu
31
31
  uiMenu = new UIObject(vec2(0,450));
32
32
  uiRoot.addChild(uiMenu);
33
- const uiBackground = new UIObject(vec2(0,0), vec2(450,550));
33
+ const uiBackground = new UIObject(vec2(0,0), vec2(450,580));
34
34
  uiMenu.addChild(uiBackground);
35
35
 
36
36
  // example large text
37
- const textTitle = new UIText(vec2(0,-200), vec2(500, 90), 'Test Title');
37
+ const textTitle = new UIText(vec2(0,-220), vec2(500, 90), 'Test Title');
38
38
  uiMenu.addChild(textTitle);
39
39
  textTitle.textColor = RED;
40
40
  textTitle.lineWidth = 4;
41
41
  textTitle.lineColor = BLUE;
42
42
 
43
43
  // example multiline text
44
- const textTest = new UIText(vec2(-60,-120), vec2(300, 50), 'Test Text\nSecond text line.')
44
+ const textTest = new UIText(vec2(-60,-140), vec2(300, 50), 'Test Text\nSecond text line.')
45
45
  uiMenu.addChild(textTest);
46
46
 
47
47
  // example tile image
48
- const tileTest = new UITile(vec2(150,-110), vec2(110), tile(3,128))
48
+ const tileTest = new UITile(vec2(150,-130), vec2(110), tile(3,128))
49
49
  uiMenu.addChild(tileTest);
50
50
 
51
51
  // example checkbox
52
- const checkbox = new UICheckbox(vec2(-160,0), vec2(50));
52
+ const checkbox = new UICheckbox(vec2(-140,-20), vec2(40));
53
53
  uiMenu.addChild(checkbox);
54
- checkbox.onClick = ()=>
54
+ checkbox.onPress = ()=>
55
55
  {
56
56
  checkbox.checked = !checkbox.checked;
57
57
  console.log('Checkbox clicked');
58
- sound_click.play(0,.5,checkbox.checked?4:1);
58
+ sound_ui.play(0,.5,checkbox.checked?4:1);
59
59
  }
60
60
 
61
61
  // text attached to checkbox
62
- const checkboxText = new UIText(vec2(200,0), vec2(300, 50), 'Test Checkbox');
62
+ const checkboxText = new UIText(vec2(170,0), vec2(300, 40), 'Test Checkbox');
63
63
  checkbox.addChild(checkboxText);
64
64
 
65
+ // example scrollbar
66
+ const scrollbar = new UIScrollbar(vec2(0,60), vec2(350, 50));
67
+ uiMenu.addChild(scrollbar);
68
+ scrollbar.onChange = ()=> console.log('New scrollbar value:', scrollbar.value);
69
+ scrollbar.onPress = ()=> sound_ui.play(0,.3,2);
70
+ scrollbar.onRelease = ()=> sound_ui.play(0,.3,4);
71
+
65
72
  // example button
66
- const button1 = new UIButton(vec2(0,90), vec2(350, 70), 'Test Button', RED, 6, CYAN);
73
+ const button1 = new UIButton(vec2(0,140), vec2(350, 50), 'Test Button');
67
74
  uiMenu.addChild(button1);
68
- button1.onClick = ()=>
75
+ button1.onPress = ()=>
69
76
  {
70
77
  console.log('Button 1 clicked');
71
- sound_click.play();
78
+ sound_ui.play();
72
79
  }
73
80
 
74
81
  // exit button
75
- const button2 = new UIButton(vec2(0,190), vec2(350, 70), 'Exit Menu', RED, 6, CYAN);
82
+ const button2 = new UIButton(vec2(0,220), vec2(350, 50), 'Exit Menu');
76
83
  uiMenu.addChild(button2);
77
- button2.onClick = ()=>
84
+ button2.onPress = ()=>
78
85
  {
79
86
  console.log('Button 2 clicked');
80
- sound_click.play(0,.5,2);
87
+ sound_ui.play(0,.5,2);
81
88
  setMenuVisible(false);
82
89
  }
83
90
  }
@@ -7,19 +7,8 @@
7
7
  </head><body>
8
8
 
9
9
  <!-- LittleJS Engine -->
10
- <script src=../../src/engineDebug.js?1100></script>
11
- <script src=../../src/engineUtilities.js?1100></script>
12
- <script src=../../src/engineSettings.js?1100></script>
13
- <script src=../../src/engineObject.js?1100></script>
14
- <script src=../../src/engineDraw.js?1100></script>
15
- <script src=../../src/engineInput.js?1100></script>
16
- <script src=../../src/engineAudio.js?1100></script>
17
- <script src=../../src/engineTileLayer.js?1100></script>
18
- <script src=../../src/engineParticles.js?1100></script>
19
- <script src=../../src/engineMedals.js?1100></script>
20
- <script src=../../src/engineWebGL.js?1100></script>
21
- <script src=../../src/engine.js?1100></script>
10
+ <script src=../../dist/littlejs.js?1105></script>
22
11
 
23
12
  <!-- Add your game scripts here -->
24
- <script src=../../plugins/uiSystem.js?1100></script>
25
- <script src=game.js?1100></script>
13
+ <script src=../../plugins/uiSystem.js?1105></script>
14
+ <script src=game.js?1105></script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.10.2",
3
+ "version": "1.10.7",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "dist/littlejs.esm.js",
6
6
  "types": "dist/littlejs.d.ts",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * LittleJS Post Processing Plugin
3
3
  * - Supports shadertoy style post processing shaders
4
- * - call glInitPostProcess
4
+ * - call initPostProcess to set it up
5
5
  */
6
6
 
7
7
  'use strict';
@@ -40,7 +40,7 @@ function initUISystem(context=overlayContext)
40
40
  o.pos = o.localPos.add(o.parent.pos);
41
41
  o.update();
42
42
  for(const c of o.children)
43
- updateObject(c)
43
+ updateObject(c);
44
44
  }
45
45
  uiObjects.forEach(o=> o.parent || updateObject(o));
46
46
  }
@@ -50,9 +50,11 @@ function initUISystem(context=overlayContext)
50
50
  {
51
51
  if (!o.visible)
52
52
  return;
53
+ if (o.parent)
54
+ o.pos = o.localPos.add(o.parent.pos);
53
55
  o.render();
54
56
  for(const c of o.children)
55
- renderObject(c)
57
+ renderObject(c);
56
58
  }
57
59
  uiObjects.forEach(o=> o.parent || renderObject(o));
58
60
  }
@@ -82,9 +84,9 @@ function drawUILine(posA, posB, thickness=uiDefaultLineWidth, color=uiDefaultLin
82
84
  uiContext.stroke();
83
85
  }
84
86
 
85
- function drawUITile(pos, size, tileInfo, color=uiDefaultColor, angle=0, mirror=false, additiveColor=BLACK)
87
+ function drawUITile(pos, size, tileInfo, color=uiDefaultColor, angle=0, mirror=false)
86
88
  {
87
- drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, false, true, uiContext);
89
+ drawTile(pos, size, tileInfo, color, angle, mirror, BLACK, false, true, uiContext);
88
90
  }
89
91
 
90
92
  function drawUIText(text, pos, size, color=uiDefaultColor, lineWidth=uiDefaultLineWidth, lineColor=uiDefaultLineColor, align='center', font=uiDefaultFont)
@@ -96,7 +98,7 @@ function drawUIText(text, pos, size, color=uiDefaultColor, lineWidth=uiDefaultLi
96
98
 
97
99
  class UIObject
98
100
  {
99
- constructor(localPos, size=vec2())
101
+ constructor(localPos=vec2(), size=vec2())
100
102
  {
101
103
  this.localPos = localPos.copy();
102
104
  this.pos = localPos.copy();
@@ -131,21 +133,28 @@ class UIObject
131
133
  {
132
134
  // track mouse input
133
135
  const mouseWasOver = this.mouseIsOver;
134
- this.mouseIsOver = isOverlapping(this.pos, this.size, mousePosScreen);
135
- if (this.mouseIsOver && !mouseWasOver)
136
- this.onEnter();
137
- if (!this.mouseIsOver && mouseWasOver)
138
- this.onLeave();
136
+ const mouseDown = mouseIsDown(0);
137
+ if (!mouseDown || isTouchDevice)
138
+ {
139
+ this.mouseIsOver = isOverlapping(this.pos, this.size, mousePosScreen);
140
+ if (!mouseDown && isTouchDevice)
141
+ this.mouseIsOver = false;
142
+ if (this.mouseIsOver && !mouseWasOver)
143
+ this.onEnter();
144
+ if (!this.mouseIsOver && mouseWasOver)
145
+ this.onLeave();
146
+ }
139
147
  if (mouseWasPressed(0) && this.mouseIsOver)
140
148
  {
141
149
  this.mouseIsHeld = true;
142
150
  this.onPress();
151
+ if (isTouchDevice)
152
+ this.mouseIsOver = false;
143
153
  }
144
- else if (this.mouseIsHeld && !mouseIsDown(0))
154
+ else if (this.mouseIsHeld && !mouseDown)
145
155
  {
146
156
  this.mouseIsHeld = false;
147
- if (this.mouseIsOver)
148
- this.onClick();
157
+ this.onRelease();
149
158
  }
150
159
  }
151
160
  render()
@@ -155,17 +164,18 @@ class UIObject
155
164
  }
156
165
 
157
166
  // callback functions
158
- onEnter() {}
159
- onLeave() {}
160
- onPress() {}
161
- onClick() {}
167
+ onEnter() {}
168
+ onLeave() {}
169
+ onPress() {}
170
+ onRelease() {}
171
+ onChange() {}
162
172
  }
163
173
 
164
174
  ///////////////////////////////////////////////////////////////////////////////
165
175
 
166
176
  class UIText extends UIObject
167
177
  {
168
- constructor(pos, size, text, align='center', font=fontDefault)
178
+ constructor(pos, size, text='', align='center', font=fontDefault)
169
179
  {
170
180
  super(pos, size);
171
181
 
@@ -184,7 +194,7 @@ class UIText extends UIObject
184
194
 
185
195
  class UITile extends UIObject
186
196
  {
187
- constructor(pos, size, tileInfo, color=WHITE, angle=0, mirror=false, additiveColor=BLACK)
197
+ constructor(pos, size, tileInfo, color=WHITE, angle=0, mirror=false)
188
198
  {
189
199
  super(pos, size);
190
200
 
@@ -192,11 +202,10 @@ class UITile extends UIObject
192
202
  this.color = color;
193
203
  this.angle = angle;
194
204
  this.mirror = mirror;
195
- this.additiveColor = additiveColor;
196
205
  }
197
206
  render()
198
207
  {
199
- drawUITile(this.pos, this.size, this.tileInfo, this.color, this.angle, this.mirror, this.additiveColor);
208
+ drawUITile(this.pos, this.size, this.tileInfo, this.color, this.angle, this.mirror);
200
209
  }
201
210
  }
202
211
 
@@ -215,8 +224,9 @@ class UIButton extends UIObject
215
224
  const lineColor = this.mouseIsHeld ? this.color : this.lineColor;
216
225
  const color = this.mouseIsOver? this.hoverColor : this.color;
217
226
  drawUIRect(this.pos, this.size, color, this.lineWidth, lineColor);
218
- drawTextScreen(this.text, this.pos, this.size.y*.8,
219
- this.textColor, undefined, undefined, this.align, this.font, uiContext);
227
+ const textSize = vec2(this.size.x, this.size.y*.8);
228
+ drawUIText(this.text, this.pos, textSize,
229
+ this.textColor, 0, undefined, this.align, this.font);
220
230
  }
221
231
  }
222
232
 
@@ -229,7 +239,11 @@ class UICheckbox extends UIObject
229
239
  super(pos, size);
230
240
  this.checked = checked;
231
241
  }
232
- onClick() { this.checked = !this.checked; }
242
+ onPress()
243
+ {
244
+ this.checked = !this.checked;
245
+ this.onChange();
246
+ }
233
247
  render()
234
248
  {
235
249
  drawUIRect(this.pos, this.size, this.color, this.lineWidth, this.lineColor);
@@ -241,3 +255,49 @@ class UICheckbox extends UIObject
241
255
  }
242
256
  }
243
257
  }
258
+
259
+ ///////////////////////////////////////////////////////////////////////////////
260
+
261
+ class UIScrollbar extends UIObject
262
+ {
263
+ constructor(pos, size, value=.5, text='')
264
+ {
265
+ super(pos, size);
266
+ this.value = value;
267
+ this.text = text;
268
+ this.color = uiDefaultButtonColor;
269
+ this.handleColor = WHITE;
270
+ }
271
+ update()
272
+ {
273
+ super.update();
274
+ if (this.mouseIsHeld)
275
+ {
276
+ const handleSize = vec2(this.size.y);
277
+ const handleWidth = this.size.x - handleSize.x;
278
+ const p1 = this.pos.x - handleWidth/2;
279
+ const p2 = this.pos.x + handleWidth/2;
280
+ const oldValue = this.value;
281
+ this.value = percent(mousePosScreen.x, p1, p2);
282
+ this.value == oldValue || this.onChange();
283
+ }
284
+ }
285
+ render()
286
+ {
287
+ const lineColor = this.mouseIsHeld ? this.color : this.lineColor;
288
+ const color = this.mouseIsOver? this.hoverColor : this.color;
289
+ drawUIRect(this.pos, this.size, color, this.lineWidth, lineColor);
290
+
291
+ const handleSize = vec2(this.size.y);
292
+ const handleWidth = this.size.x - handleSize.x;
293
+ const p1 = this.pos.x - handleWidth/2;
294
+ const p2 = this.pos.x + handleWidth/2;
295
+ const handlePos = vec2(lerp(this.value, p1, p2), this.pos.y);
296
+ const barColor = this.mouseIsHeld ? this.color : this.handleColor;
297
+ drawUIRect(handlePos, handleSize, barColor, this.lineWidth, this.lineColor);
298
+
299
+ const textSize = vec2(this.size.x, this.size.y*.8);
300
+ drawUIText(this.text, this.pos, textSize,
301
+ this.textColor, 0, undefined, this.align, this.font);
302
+ }
303
+ }