littlejsengine 1.14.11 → 1.14.19

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 (80) hide show
  1. package/dist/littlejs.d.ts +303 -137
  2. package/dist/littlejs.esm.js +936 -463
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +934 -462
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +859 -417
  7. package/examples/box2d/game.js +3 -2
  8. package/examples/box2d/gameObjects.js +2 -2
  9. package/examples/box2d/tiles.png +0 -0
  10. package/examples/breakout/game.js +5 -5
  11. package/examples/breakout/gameObjects.js +2 -2
  12. package/examples/breakoutTutorial/README.md +32 -32
  13. package/examples/breakoutTutorial/game.js +1 -1
  14. package/examples/electron/game.js +4 -4
  15. package/examples/electron/index.html +2 -2
  16. package/examples/electron/package.json +1 -8
  17. package/examples/index.html +67 -56
  18. package/examples/module/game.js +4 -4
  19. package/examples/platformer/gameEffects.js +5 -5
  20. package/examples/platformer/gameLevel.js +1 -1
  21. package/examples/platformer/gameObjects.js +4 -4
  22. package/examples/puzzle/game.js +1 -1
  23. package/examples/shorts/animation.js +1 -1
  24. package/examples/shorts/base.html +1 -1
  25. package/examples/shorts/blending.js +8 -14
  26. package/examples/shorts/box2d.js +7 -3
  27. package/examples/shorts/box2dCar.js +2 -1
  28. package/examples/shorts/empty.js +30 -0
  29. package/examples/shorts/helloWorld.js +1 -1
  30. package/examples/shorts/hillGlideGame.js +10 -4
  31. package/examples/shorts/landerGame.js +11 -8
  32. package/examples/shorts/medals.js +4 -4
  33. package/examples/shorts/music.js +29 -56
  34. package/examples/shorts/musicPlayer.js +135 -0
  35. package/examples/shorts/nineSlice.js +34 -15
  36. package/examples/shorts/parallax.js +5 -4
  37. package/examples/shorts/particles.js +15 -15
  38. package/examples/shorts/piano.js +15 -21
  39. package/examples/shorts/pongGame.js +6 -4
  40. package/examples/shorts/raycasting.js +9 -4
  41. package/examples/shorts/sequencer.js +122 -0
  42. package/examples/shorts/shader.js +29 -0
  43. package/examples/shorts/shapes.js +7 -4
  44. package/examples/shorts/slidingPuzzle.js +4 -2
  45. package/examples/shorts/sound.js +18 -9
  46. package/examples/shorts/spaceGame.js +12 -8
  47. package/examples/shorts/spriteAtlas.js +7 -7
  48. package/examples/shorts/starfield.js +1 -1
  49. package/examples/shorts/systemFont.js +2 -2
  50. package/examples/shorts/texture.js +2 -2
  51. package/examples/shorts/tileLayer.js +10 -10
  52. package/examples/shorts/tiltedView.js +24 -5
  53. package/examples/shorts/timers.js +10 -0
  54. package/examples/shorts/topDown.js +4 -1
  55. package/examples/shorts/uiSystem.js +8 -5
  56. package/examples/starter/game.js +4 -4
  57. package/examples/starter/index.html +2 -2
  58. package/examples/style.css +1 -0
  59. package/examples/typescript/game.js +4 -4
  60. package/examples/typescript/game.ts +4 -4
  61. package/examples/uiSystem/game.js +4 -3
  62. package/package.json +4 -2
  63. package/plugins/box2d.js +17 -2
  64. package/plugins/newgrounds.js +7 -5
  65. package/plugins/postProcess.js +76 -53
  66. package/plugins/uiSystem.js +192 -53
  67. package/plugins/zzfxm.js +5 -1
  68. package/reference.md +1 -1
  69. package/src/engine.js +60 -23
  70. package/src/engineAudio.js +44 -17
  71. package/src/engineDebug.js +75 -45
  72. package/src/engineDraw.js +94 -59
  73. package/src/engineExport.js +2 -1
  74. package/src/engineMedals.js +10 -2
  75. package/src/engineObject.js +14 -10
  76. package/src/engineParticles.js +60 -47
  77. package/src/engineSettings.js +7 -7
  78. package/src/engineTileLayer.js +73 -56
  79. package/src/engineUtilities.js +67 -20
  80. package/src/engineWebGL.js +134 -63
@@ -69,16 +69,16 @@ function gameInit()
69
69
  // create particle emitter
70
70
  particleEmitter = new LJS.ParticleEmitter(
71
71
  vec2(16,9), 0, // emitPos, emitAngle
72
- 1, 0, 500, Math.PI, // emitSize, emitTime, emitRate, emitCone
72
+ 1, 0, 500, Math.PI, // emitSize, emitTime, rate, cone
73
73
  tile(0, 16), // tileIndex, tileSize
74
74
  hsl(1,1,1), hsl(0,0,0), // colorStartA, colorStartB
75
75
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
76
- 2, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
76
+ 1, .2, .2, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
77
77
  .99, 1, 1, Math.PI, // damping, angleDamping, gravityScale, cone
78
78
  .05, .5, true, true // fadeRate, randomness, collide, additive
79
79
  );
80
80
  particleEmitter.restitution = .3; // bounce when it collides
81
- particleEmitter.trailScale = 2; // stretch in direction of motion
81
+ particleEmitter.trailScale = 2; // stretch as it moves
82
82
  }
83
83
 
84
84
  ///////////////////////////////////////////////////////////////////////////////
@@ -90,7 +90,7 @@ function gameUpdate()
90
90
  sound_click.play(LJS.mousePos);
91
91
 
92
92
  // change particle color and set to fade out
93
- particleEmitter.colorStartA = hsl();
93
+ particleEmitter.colorStartA = LJS.randColor();
94
94
  particleEmitter.colorStartB = LJS.randColor();
95
95
  particleEmitter.colorEndA = particleEmitter.colorStartA.scale(1,0);
96
96
  particleEmitter.colorEndB = particleEmitter.colorStartB.scale(1,0);
@@ -48,13 +48,13 @@ export function makeDebris(pos, color = hsl(), amount = 50, size=.2, restitution
48
48
  {
49
49
  const color2 = color.lerp(hsl(), .5);
50
50
  const emitter = new LJS.ParticleEmitter(
51
- pos, 0, 1, .1, amount/.1, 3.14, // pos, angle, emitSize, emitTime, emitRate, emitCone
51
+ pos, 0, 1, .1, amount/.1, 3.14, // pos, angle, size, time, rate, cone
52
52
  0, // tileInfo
53
53
  color, color2, // colorStartA, colorStartB
54
54
  color, color2, // colorEndA, colorEndB
55
55
  3, size,size, .1, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
56
56
  1, .95, .4, 3.14, 0, // damp, angleDamp, gravity, particleCone, fade
57
- .5, 1 // randomness, collide, additive, colorLinear, renderOrder
57
+ .5, 1 // randomness, collide
58
58
  );
59
59
  emitter.restitution = restitution;
60
60
  emitter.particleDestroyCallback = persistentParticleDestroyCallback;
@@ -109,7 +109,7 @@ export function explosion(pos, radius=3)
109
109
  // smoke
110
110
  new LJS.ParticleEmitter(
111
111
  pos, 0, // pos, angle
112
- radius/2, .2, 50*radius, 3.14,// emitSize, emitTime, emitRate, emitCone
112
+ radius/2, .2, 50*radius, 3.14,// emitSize, emitTime, rate, cone
113
113
  0, // tileInfo
114
114
  hsl(0,0,0), hsl(0,0,0), // colorStartA, colorStartB
115
115
  hsl(0,0,0,0), hsl(0,0,0,0), // colorEndA, colorEndB
@@ -121,7 +121,7 @@ export function explosion(pos, radius=3)
121
121
  // fire
122
122
  new LJS.ParticleEmitter(
123
123
  pos, 0, // pos, angle
124
- radius/2, .1, 100*radius, 3.14, // emitSize, emitTime, emitRate, emitCone
124
+ radius/2, .1, 100*radius, 3.14, // emitSize, emitTime, rate, cone
125
125
  0, // tileInfo
126
126
  rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
127
127
  rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
@@ -255,7 +255,7 @@ export class ParallaxLayer extends LJS.CanvasLayer
255
255
  this.context.clearRect(0,0,1,h);
256
256
 
257
257
  // make WebGL texture
258
- this.useWebGL(LJS.glEnable);
258
+ this.useWebGL();
259
259
  }
260
260
 
261
261
  render()
@@ -50,7 +50,7 @@ function loadLevelData()
50
50
  {
51
51
  // load the level data
52
52
  const tileMapData = Game.gameLevelData;
53
- tileLayers = LJS.tileCollisionLoad(tileMapData, tile(0,16,1), 0, 1);
53
+ tileLayers = LJS.tileLayersLoad(tileMapData, tile(0,16,1), 0, 1);
54
54
  levelSize = tileLayers[0].size;
55
55
  playerStartPos = vec2(0, levelSize.y); // default player start
56
56
  foregroundTileLayer = tileLayers[0];
@@ -247,13 +247,13 @@ export class Weapon extends LJS.EngineObject
247
247
 
248
248
  // shell effect
249
249
  this.addChild(this.shellEmitter = new LJS.ParticleEmitter(
250
- vec2(), 0, 0, 0, 0, .1, // pos, angle, emitSize, emitTime, emitRate, emitCone
250
+ vec2(), 0, 0, 0, 0, .1, // pos, angle, size, time, rate, cone
251
251
  0, // tileInfo
252
252
  rgb(1,.8,.5), rgb(.9,.7,.5), // colorStartA, colorStartB
253
253
  rgb(1,.8,.5), rgb(.9,.7,.5), // colorEndA, colorEndB
254
254
  3, .1, .1, .15, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
255
255
  1, .95, 1, 0, 0, // damp, angleDamp, gravity, particleCone, fade
256
- .1, 1 // randomness, collide, additive, colorLinear, renderOrder
256
+ .1, 1 // randomness, collide
257
257
  ), vec2(.1,0), -.8);
258
258
  this.shellEmitter.restitution = .5;
259
259
  this.shellEmitter.particleDestroyCallback = GameEffects.persistentParticleDestroyCallback;
@@ -368,13 +368,13 @@ export class Bullet extends LJS.EngineObject
368
368
 
369
369
  // spark effects
370
370
  const emitter = new LJS.ParticleEmitter(
371
- this.pos, 0, 0, .1, 100, .5, // pos, angle, emitSize, emitTime, emitRate, emitCone
371
+ this.pos, 0, 0, .1, 100, .5, // pos, angle, size, time, rate, cone
372
372
  0, // tileInfo
373
373
  rgb(1,1,0), rgb(1,0,0), // colorStartA, colorStartB
374
374
  rgb(1,1,0), rgb(1,0,0), // colorEndA, colorEndB
375
375
  .2, .2, 0, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
376
376
  1, 1, .5, 3.14, .1, // damp, angleDamp, gravityScale, particleCone, fade,
377
- .5, 1, 1 // randomness, collide, additive, colorLinear, renderOrder
377
+ .5, 1, 1 // randomness, collide, additive
378
378
  );
379
379
  emitter.trailScale = 1;
380
380
  emitter.restitution = .3;
@@ -309,7 +309,7 @@ function clearMatches()
309
309
  const color2 = color1.lerp(hsl(), .5);
310
310
  new LJS.ParticleEmitter(
311
311
  pos.add(vec2(.5)), 0, // pos, angle
312
- .5, .1, 200, 3.14, // emitSize, emitTime, emitRate, emitCone
312
+ .5, .1, 200, 3.14, // emitSize, emitTime, rate, cone
313
313
  0, // tileInfo
314
314
  color1, color2, // colorStartA, colorStartB
315
315
  color1.scale(1,0), color2.scale(1,0),// colorEndA, colorEndB
@@ -3,7 +3,7 @@ canvasClearColor = GRAY;
3
3
  function gameRender()
4
4
  {
5
5
  {
6
- // animate using multiple frames
6
+ // animate by changing frames
7
7
  const pos = vec2(-5, 2*abs(Math.sin(time*2*PI)));
8
8
  const frame = (time*4)%2|0;
9
9
  drawTile(pos, vec2(7), tile(3).frame(frame), RED);
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html><meta charset=utf-8><body>
2
- <script src=../../dist/littlejs.js?1134></script>
2
+ <script src=../../dist/littlejs.js?11417></script>
3
3
  <script src=../../dist/box2d.wasm.js></script>
4
4
 
5
5
  <!-- LittleJS Engine Source
@@ -1,20 +1,14 @@
1
- // use smooth blending
2
- setCanvasPixelated(false);
3
- setTilesPixelated(false);
4
-
5
1
  function gameRender()
6
2
  {
7
- const circleTile = tile(2, 128); // get the circle tile
8
-
9
- // additive blend
3
+ // additive blending
10
4
  setBlendMode(1);
11
- drawTile(vec2(-8,-2), vec2(7), circleTile, rgb(0,0,.5), 0, false, rgb(0,0,.5));
12
- drawTile(vec2(-6, 2), vec2(7), circleTile, rgb(0,1,0));
13
- drawTile(vec2(-4,-2), vec2(7), circleTile, rgb(1,0,0));
5
+ drawCircle(vec2(-8,-2), 7, rgb(0,0,.5));
6
+ drawCircle(vec2(-6, 2), 7, rgb(0,1,0));
7
+ drawCircle(vec2(-4,-2), 7, rgb(1,0,0));
14
8
 
15
- // alpha blend
9
+ // alpha blending
16
10
  setBlendMode(0);
17
- drawTile(vec2(4,-2), vec2(7), circleTile, hsl(time/9 ,1,.5), 0, false, hsl(1,1,.5));
18
- drawTile(vec2(8,-2), vec2(7), circleTile, hsl(time/9+1/3,1,.5,.5));
19
- drawTile(vec2(6, 2), vec2(7), circleTile, hsl(time/9+2/3,1,.5,.5));
11
+ drawCircle(vec2(4,-2), 7, hsl(time/9 ,1,.5));
12
+ drawCircle(vec2(8,-2), 7, hsl(time/9+1/3,1,.5,.5));
13
+ drawCircle(vec2(6, 2), 7, hsl(time/9+2/3,1,.5,.5));
20
14
  }
@@ -7,13 +7,16 @@ async function gameInit()
7
7
  canvasClearColor = hsl(0,0,.9);
8
8
 
9
9
  // create ground object
10
- groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0, GRAY, box2d.bodyTypeStatic);
10
+ groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
11
+ GRAY, box2d.bodyTypeStatic);
11
12
  groundObject.addBox(vec2(100,2));
12
13
 
13
14
  // add some random objects
14
15
  for (let i=50; i--;)
15
16
  {
16
- const o = new Box2dObject(randInCircle(5), vec2(), 0, 0, randColor());
17
+ const pos = randInCircle(5);
18
+ const color = randColor();
19
+ const o = new Box2dObject(pos, vec2(), 0, 0, color);
17
20
  randInt(2) ? o.addCircle(rand(1,2)) : o.addRandomPoly(rand(1,2));
18
21
  }
19
22
  }
@@ -36,7 +39,8 @@ function gameUpdate()
36
39
  // grab object
37
40
  const object = box2d.pointCast(mousePos);
38
41
  if (object)
39
- mouseJoint = new Box2dTargetJoint(object, groundObject, mousePos);
42
+ mouseJoint = new Box2dTargetJoint(object,
43
+ groundObject, mousePos);
40
44
  }
41
45
  }
42
46
 
@@ -3,7 +3,8 @@ async function gameInit()
3
3
  // setup box2d and create the objects
4
4
  await box2dInit();
5
5
  gravity.y = -20;
6
- groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0, GRAY, box2d.bodyTypeStatic);
6
+ groundObject = new Box2dObject(vec2(-8), vec2(), 0, 0,
7
+ GRAY, box2d.bodyTypeStatic);
7
8
  groundObject.addBox(vec2(100,6));
8
9
  new CarObject(vec2(0,-2));
9
10
  canvasClearColor = hsl(0,0,.9);
@@ -0,0 +1,30 @@
1
+ function gameInit()
2
+ {
3
+ // called once after the engine starts up
4
+ // setup the game
5
+ }
6
+
7
+ function gameUpdate()
8
+ {
9
+ // called every frame at 60 frames per second
10
+ // handle input and update the game state
11
+ }
12
+
13
+ function gameUpdatePost()
14
+ {
15
+ // called after physics and objects are updated
16
+ // setup camera and prepare for render
17
+ }
18
+
19
+ function gameRender()
20
+ {
21
+ // called before objects are rendered
22
+ // draw any background effects that appear behind objects
23
+ }
24
+
25
+ function gameRenderPost()
26
+ {
27
+ // called after objects are rendered
28
+ // draw effects or hud that appear above all objects
29
+ drawTextScreen('LittleJS Engine', mainCanvasSize.scale(.5), 80);
30
+ }
@@ -4,7 +4,7 @@ function gameRender()
4
4
  drawRectGradient(cameraPos, getCameraSize(), BLACK, WHITE);
5
5
 
6
6
  // draw text to the overlay canvas
7
- drawTextOverlay('Hello World', vec2(0,3), 3);
7
+ drawTextOverlay('LittleJS Engine', vec2(0,3), 3);
8
8
 
9
9
  // draw a tile
10
10
  drawTile(vec2(Math.sin(time)*3,-2), vec2(7), tile(3,128));
@@ -2,7 +2,7 @@ class Player extends EngineObject
2
2
  {
3
3
  constructor(pos)
4
4
  {
5
- super(pos, vec2(2), tile(9), 0, CYAN);
5
+ super(pos, vec2(2), tile(9), 0, RED);
6
6
  this.damping = 1; // disable damping
7
7
  this.clampSpeed = false; // disable speed clamping
8
8
  }
@@ -11,12 +11,14 @@ class Player extends EngineObject
11
11
  {
12
12
  super.update();
13
13
 
14
+ // check ground height
14
15
  const h = getGroundHeight(this.pos.x);
15
16
  if (this.pos.y < h + this.size.y/2)
16
17
  {
17
18
  // clamp to ground and reflect velocity
18
19
  this.pos.y = h + this.size.y/2;
19
- const n = vec2((h-getGroundHeight(this.pos.x+.1))/.1, 1).normalize();
20
+ const h2 = getGroundHeight(this.pos.x+.1);
21
+ const n = vec2((h-h2)/.1, 1).normalize();
20
22
  this.velocity = this.velocity.reflect(n,0);
21
23
  }
22
24
 
@@ -40,13 +42,17 @@ function gameInit()
40
42
  {
41
43
  gravity.y = -.01;
42
44
  new Player(vec2(0,5));
43
- canvasClearColor = hsl(.7,1,.8);
45
+ canvasClearColor = hsl(.6,1,.8);
44
46
  }
45
47
 
46
48
  function gameRender()
47
49
  {
50
+ // draw ground as a series of thin rectangles
48
51
  const h = 100, w = 20;
49
- const pos = vec2(), sizeTop = vec2(.4), size = vec2(.2,h), color = WHITE;
52
+ const pos = vec2();
53
+ const sizeTop = vec2(.4);
54
+ const size = vec2(.2,h);
55
+ const color = rgb();
50
56
  for (let x=cameraPos.x-w; x<cameraPos.x+w; x+=.1)
51
57
  {
52
58
  pos.x = x;
@@ -14,7 +14,8 @@ class Player extends EngineObject
14
14
  // space ship controls
15
15
  const moveInput = keyDirection();
16
16
  this.applyAngularAcceleration(moveInput.x * .002);
17
- this.applyAcceleration(vec2().setAngle(this.angle, moveInput.y*.002));
17
+ const accel = vec2(0, moveInput.y*.002).rotate(this.angle);
18
+ this.applyAcceleration(accel);
18
19
  }
19
20
 
20
21
  // explode when it collides
@@ -25,16 +26,16 @@ class Player extends EngineObject
25
26
  if (this.velocity.length() < .05)
26
27
  return true;
27
28
 
29
+ // explode!
28
30
  this.destroy();
29
31
  new ParticleEmitter(
30
- this.pos, 0, // pos, angle
31
- 1, .1, 300, 3.14, // emitSize, emitTime, emitRate, emitCone
32
- 0, // tileInfo
32
+ this.pos, 0, // pos, angle
33
+ 1, .1, 300, 3.14, 0, // emitSize, emitTime, rate, cone, tile
33
34
  rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
34
35
  rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
35
- .7, .8, .2, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
36
- .9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, particleCone, fade
37
- 1, 0, 1 // randomness, collide, additive
36
+ .7, .8, .2, .2, .05, // time, start, end, speed, angleSpeed
37
+ .9, 1, -.2, 3.14, .05, // damp, angleDamp, gravity, cone, fade
38
+ 1, 0, 1 // randomness, collide, additive
38
39
  );
39
40
  }
40
41
  }
@@ -49,7 +50,9 @@ function gameInit()
49
50
  for (let i=0, y=0; i<20; ++i)
50
51
  {
51
52
  y = (y + rand(1,-1)*4) * .5;
52
- const o = new EngineObject(vec2(i*2-20, y-54), vec2(2, 99), 0, 0, hsl(0,0,.5+i%.29));
53
+ const pos = vec2(i*2-20, y-54);
54
+ const color = hsl(0, 0, .5+i%.29);
55
+ const o = new EngineObject(pos, vec2(2, 99), 0, 0, color);
53
56
  o.setCollision(); // make object collide
54
57
  o.mass = 0; // make object have static physics
55
58
  }
@@ -1,8 +1,8 @@
1
1
  // create example medals
2
- const medal_openedExample = new Medal(0, 'Opened Example', 'You opened this example!');
3
- const medal_leftClick = new Medal(1, 'Left Clicked', 'You left clicked!', '🐁');
4
- const medal_rightClick = new Medal(2, 'Right Clicked', 'You right clicked!', '🐭');
5
- const medal_spacePressed = new Medal(3, 'Pressed Spacebar', 'You pressed spacebar!', '🚀');
2
+ const medal_openedExample = new Medal(0, 'Open', 'Opened this example!');
3
+ const medal_leftClick = new Medal(1, 'Lefty', 'Left clicked!', '🐁');
4
+ const medal_rightClick = new Medal(2, 'Righty', 'Right clicked!', '🐭');
5
+ const medal_spacePressed = new Medal(3, 'Space', 'Pressed spacebar!', '🚀');
6
6
 
7
7
  // setup medals
8
8
  const saveName = 'Medals Example';
@@ -1,7 +1,7 @@
1
- let playButton, stopButton, progressBar;
1
+ let musicPlayer, playButton, stopButton, infoText;
2
2
  let musicSound = new SoundWave('song.mp3');
3
3
  let musicVolume = 1;
4
- let musicInstance;
4
+ let music;
5
5
 
6
6
  function gameInit()
7
7
  {
@@ -10,27 +10,28 @@ function gameInit()
10
10
  uiSystem.defaultSoundPress = new Sound([.5,0,220]);
11
11
  uiSystem.defaultSoundClick = new Sound([.5,0,440]);
12
12
  uiSystem.defaultCornerRadius = 20;
13
- canvasClearColor = hsl(.9,.3,.2); // background color
13
+ canvasClearColor = hsl(.9,.3,.2);
14
14
 
15
15
  // setup music player UI
16
- const musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 300));
16
+ musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 220));
17
17
 
18
- // title
19
- const title = new UIText(vec2(0, -100), vec2(500, 40), 'LittleJS Music Player');
20
- musicPlayer.addChild(title);
18
+ // infomation text
19
+ infoText = new UIText(vec2(0, -70), vec2(400, 50));
20
+ musicPlayer.addChild(infoText);
21
21
 
22
22
  // volume slider
23
- const volumeSlider = new UIScrollbar(vec2(0, -40), vec2(400, 30), musicVolume, 'Music Volume');
23
+ const volumeSlider = new UIScrollbar(vec2(0, -20), vec2(400, 30),
24
+ musicVolume, 'Music Volume');
24
25
  musicPlayer.addChild(volumeSlider);
25
26
  volumeSlider.onChange = () =>
26
27
  {
27
28
  musicVolume = volumeSlider.value;
28
- if (musicInstance)
29
- musicInstance.setVolume(musicVolume);
29
+ if (music)
30
+ music.setVolume(musicVolume);
30
31
  };
31
32
 
32
33
  // play button
33
- playButton = new UIButton(vec2(-90, 30), vec2(140, 50), 'Play');
34
+ playButton = new UIButton(vec2(-90, 50), vec2(140, 50), 'Play');
34
35
  musicPlayer.addChild(playButton);
35
36
  playButton.onClick = ()=>
36
37
  {
@@ -38,68 +39,40 @@ function gameInit()
38
39
  return;
39
40
 
40
41
  // handle play/pause toggle
41
- if (!musicInstance)
42
- musicInstance = musicSound.playMusic(musicVolume);
43
- else if (musicInstance.isPaused())
44
- musicInstance.resume();
42
+ if (!music)
43
+ music = musicSound.playMusic(musicVolume);
44
+ else if (music.isPaused())
45
+ music.resume();
45
46
  else
46
- musicInstance.pause();
47
+ music.pause();
47
48
  };
48
49
 
49
50
  // stop button
50
- stopButton = new UIButton(vec2(90, 30), vec2(140, 50), 'Stop');
51
- stopButton.onClick = ()=>
52
- {
53
- if (!musicInstance)
54
- return;
55
-
56
- // stop sound
57
- musicInstance.stop();
58
- };
51
+ stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
52
+ stopButton.onClick = ()=> music && music.stop();
59
53
  musicPlayer.addChild(stopButton);
60
-
61
- // progress bar and scrollbar for seeking
62
- progressBar = new UIScrollbar(vec2(0, 100), vec2(400, 30), 0, 'Progress');
63
- progressBar.disabledColor = RED;
64
- progressBar.onChange = ()=>
65
- {
66
- // control music seek position
67
- const wasPlaying = musicInstance && musicInstance.isPlaying();
68
- if (!musicInstance)
69
- musicInstance = musicSound.playMusic(musicVolume, true, true);
70
- progressBar.value = min(progressBar.value, .999); // prevent looping around
71
- const seekTime = progressBar.value * musicSound.getDuration();
72
- musicInstance.start(seekTime);
73
- if (!wasPlaying)
74
- musicInstance.pause();
75
- };
76
- musicPlayer.addChild(progressBar);
77
54
  }
78
55
 
79
56
  function gameUpdate()
80
57
  {
81
- // disable buttons while loading or waiting for interaction
82
- const isDisabled = !musicSound.isLoaded() || !audioIsRunning();
83
- playButton.disabled = isDisabled
84
- stopButton.disabled = isDisabled
85
- progressBar.disabled = isDisabled
58
+ // disable buttons while loading
59
+ const isDisabled = !musicSound.isLoaded();
60
+ playButton.disabled = stopButton.disabled = isDisabled;
86
61
 
87
62
  // update ui
88
- if (!musicSound.isLoaded())
63
+ if (isDisabled)
89
64
  {
90
65
  // update loading progress
91
- const loadingPercent = musicSound.loadedPercent * 100;
92
- progressBar.text = `Loading: ${(loadingPercent).toFixed(2)}%`;
66
+ const loadingPercent = musicSound.loadedPercent * 100|0;
67
+ infoText.text = `Loading: ${loadingPercent}%`;
93
68
  }
94
69
  else
95
70
  {
96
71
  // update ui text
97
- playButton.text = !musicInstance || !musicInstance.isPlaying() ? 'Play' : 'Pause';
98
- const currentTime = musicInstance ? musicInstance.getCurrentTime() : 0;
72
+ const isPlaying = music && music.isPlaying();
73
+ playButton.text = isPlaying ? 'Pause' : 'Play';
74
+ const current = music ? music.getCurrentTime() : 0;
99
75
  const duration = musicSound.getDuration();
100
- if (!progressBar.mouseIsHeld)
101
- progressBar.value = currentTime / duration;
102
- const timeText = `${formatTime(currentTime)} / ${formatTime(duration)}`;
103
- progressBar.text = audioIsRunning() ? timeText : 'Click to Enable Audio';
76
+ infoText.text = formatTime(current) +' / '+ formatTime(duration);
104
77
  }
105
78
  }
@@ -0,0 +1,135 @@
1
+ let musicPlayer, playButton, stopButton, progressBar;
2
+ let musicSound, music;
3
+ let musicVolume = 1;
4
+
5
+ function gameInit()
6
+ {
7
+ // setup ui system plugin
8
+ new UISystemPlugin;
9
+ uiSystem.defaultSoundPress = new Sound([.5,0,220]);
10
+ uiSystem.defaultSoundClick = new Sound([.5,0,440]);
11
+ uiSystem.defaultCornerRadius = 20;
12
+ uiSystem.defaultGradientColor = WHITE;
13
+ canvasClearColor = hsl(.9,.3,.2);
14
+
15
+ // setup music player UI
16
+ musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 300));
17
+ const title = new UIText(vec2(0, -100), vec2(500, 40),
18
+ 'LittleJS Music Player');
19
+ musicPlayer.addChild(title);
20
+
21
+ // drop zone text
22
+ const dropZoneText = new UIText(vec2(0, -60), vec2(450, 20),
23
+ 'Drag & Drop Audio Files Here!');
24
+ dropZoneText.textColor = hsl(.9, .3, .8, .7);
25
+ musicPlayer.addChild(dropZoneText);
26
+
27
+ // volume slider
28
+ const volumeSlider = new UIScrollbar(vec2(0, -20), vec2(400, 30),
29
+ musicVolume, 'Music Volume');
30
+ musicPlayer.addChild(volumeSlider);
31
+ volumeSlider.onChange = () =>
32
+ {
33
+ musicVolume = volumeSlider.value;
34
+ if (music)
35
+ music.setVolume(musicVolume);
36
+ };
37
+
38
+ // play button
39
+ playButton = new UIButton(vec2(-90, 50), vec2(140, 50), 'Play');
40
+ musicPlayer.addChild(playButton);
41
+ playButton.onClick = ()=>
42
+ {
43
+ if (!musicSound.isLoaded())
44
+ return;
45
+
46
+ // handle play/pause toggle
47
+ if (!music)
48
+ music = musicSound.playMusic(musicVolume);
49
+ else if (music.isPaused())
50
+ music.resume();
51
+ else
52
+ music.pause();
53
+ };
54
+
55
+ // stop button
56
+ stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
57
+ stopButton.onClick = ()=> music && music.stop();
58
+ musicPlayer.addChild(stopButton);
59
+
60
+ // progress bar and scrollbar for seeking
61
+ progressBar = new UIScrollbar(vec2(0, 120), vec2(400, 30), 0);
62
+ progressBar.disabledColor = RED;
63
+ progressBar.onChange = ()=>
64
+ {
65
+ // control music seek position
66
+ const wasPlaying = music && music.isPlaying();
67
+ if (!music)
68
+ music = musicSound.playMusic(musicVolume, true, true);
69
+ progressBar.value = min(progressBar.value, .999); // prevent wrap
70
+ const seekTime = progressBar.value * musicSound.getDuration();
71
+ music.start(seekTime);
72
+ if (!wasPlaying)
73
+ music.pause();
74
+ };
75
+ musicPlayer.addChild(progressBar);
76
+
77
+ {
78
+ // setup drag and drop for audio files
79
+ function onDragEnter() { musicPlayer.color = RED; };
80
+ function onDragLeave() { musicPlayer.color = WHITE; };
81
+ function onDrop(e)
82
+ {
83
+ musicPlayer.color = WHITE
84
+
85
+ // get the dropped file
86
+ const file = e.dataTransfer.files[0];
87
+ if (!file || !file.type.startsWith('audio'))
88
+ return;
89
+
90
+ // create new sound from dropped file
91
+ const fileURL = URL.createObjectURL(file);
92
+ musicSound = new SoundWave(fileURL, musicVolume);
93
+ dropZoneText.text = file.name;
94
+
95
+ // reset UI
96
+ music && music.stop();
97
+ music = undefined;
98
+ progressBar.value = 0;
99
+ }
100
+ uiSystem.setupDragAndDrop(onDrop, onDragEnter, onDragLeave);
101
+ }
102
+ }
103
+
104
+ function gameUpdate()
105
+ {
106
+ // disable buttons while loading
107
+ const isDisabled = !musicSound || !musicSound.isLoaded();
108
+ playButton.disabled = isDisabled
109
+ stopButton.disabled = isDisabled
110
+ progressBar.disabled = isDisabled
111
+
112
+ // update ui
113
+ if (!musicSound)
114
+ {
115
+ // waiting for file
116
+ progressBar.text = 'No File Loaded';
117
+ }
118
+ else if (isDisabled)
119
+ {
120
+ // update loading progress
121
+ const loadingPercent = musicSound.loadedPercent * 100|0;
122
+ progressBar.text = `Loading: ${loadingPercent}%`;
123
+ }
124
+ else
125
+ {
126
+ // update ui text
127
+ const isPlaying = music && music.isPlaying();
128
+ playButton.text = isPlaying ? 'Pause' : 'Play';
129
+ const current = music ? music.getCurrentTime() : 0;
130
+ const duration = musicSound.getDuration();
131
+ progressBar.text = formatTime(current) +' / '+ formatTime(duration);
132
+ if (!progressBar.mouseIsHeld)
133
+ progressBar.value = current / duration;
134
+ }
135
+ }