littlejsengine 1.14.11 → 1.14.16

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 (74) hide show
  1. package/dist/littlejs.d.ts +252 -109
  2. package/dist/littlejs.esm.js +559 -252
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +557 -251
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +482 -206
  7. package/examples/box2d/gameObjects.js +2 -2
  8. package/examples/breakout/gameObjects.js +2 -2
  9. package/examples/breakoutTutorial/README.md +32 -32
  10. package/examples/breakoutTutorial/game.js +1 -1
  11. package/examples/electron/game.js +3 -3
  12. package/examples/electron/index.html +2 -2
  13. package/examples/electron/package.json +1 -8
  14. package/examples/index.html +10 -7
  15. package/examples/module/game.js +3 -3
  16. package/examples/platformer/gameEffects.js +4 -4
  17. package/examples/platformer/gameLevel.js +1 -1
  18. package/examples/platformer/gameObjects.js +4 -4
  19. package/examples/puzzle/game.js +1 -1
  20. package/examples/shorts/animation.js +1 -1
  21. package/examples/shorts/base.html +1 -1
  22. package/examples/shorts/blending.js +8 -14
  23. package/examples/shorts/box2d.js +7 -3
  24. package/examples/shorts/box2dCar.js +2 -1
  25. package/examples/shorts/empty.js +30 -0
  26. package/examples/shorts/helloWorld.js +1 -1
  27. package/examples/shorts/hillGlideGame.js +10 -4
  28. package/examples/shorts/landerGame.js +11 -8
  29. package/examples/shorts/medals.js +4 -4
  30. package/examples/shorts/music.js +29 -56
  31. package/examples/shorts/musicPlayer.js +134 -0
  32. package/examples/shorts/nineSlice.js +34 -15
  33. package/examples/shorts/parallax.js +4 -3
  34. package/examples/shorts/particles.js +15 -15
  35. package/examples/shorts/piano.js +15 -21
  36. package/examples/shorts/pongGame.js +6 -4
  37. package/examples/shorts/raycasting.js +9 -4
  38. package/examples/shorts/sequencer.js +122 -0
  39. package/examples/shorts/shapes.js +7 -4
  40. package/examples/shorts/slidingPuzzle.js +4 -2
  41. package/examples/shorts/sound.js +18 -9
  42. package/examples/shorts/spaceGame.js +12 -8
  43. package/examples/shorts/spriteAtlas.js +7 -7
  44. package/examples/shorts/starfield.js +1 -1
  45. package/examples/shorts/systemFont.js +2 -2
  46. package/examples/shorts/texture.js +2 -2
  47. package/examples/shorts/tileLayer.js +10 -10
  48. package/examples/shorts/tiltedView.js +14 -3
  49. package/examples/shorts/timers.js +10 -0
  50. package/examples/shorts/topDown.js +4 -1
  51. package/examples/shorts/uiSystem.js +8 -5
  52. package/examples/starter/game.js +3 -3
  53. package/examples/starter/index.html +2 -2
  54. package/examples/typescript/game.js +3 -3
  55. package/examples/typescript/game.ts +3 -3
  56. package/examples/uiSystem/game.js +3 -3
  57. package/package.json +4 -2
  58. package/plugins/box2d.js +17 -2
  59. package/plugins/newgrounds.js +7 -5
  60. package/plugins/postProcess.js +5 -2
  61. package/plugins/uiSystem.js +120 -34
  62. package/plugins/zzfxm.js +5 -1
  63. package/reference.md +1 -1
  64. package/src/engine.js +35 -12
  65. package/src/engineAudio.js +31 -14
  66. package/src/engineDebug.js +75 -45
  67. package/src/engineDraw.js +60 -31
  68. package/src/engineExport.js +2 -1
  69. package/src/engineMedals.js +10 -2
  70. package/src/engineObject.js +14 -10
  71. package/src/engineParticles.js +59 -46
  72. package/src/engineSettings.js +7 -7
  73. package/src/engineTileLayer.js +45 -20
  74. package/src/engineUtilities.js +67 -20
@@ -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,134 @@
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
+ canvasClearColor = hsl(.9,.3,.2);
13
+
14
+ // setup music player UI
15
+ musicPlayer = new UIObject(mainCanvasSize.scale(.5), vec2(500, 300));
16
+ const title = new UIText(vec2(0, -100), vec2(500, 40),
17
+ 'LittleJS Music Player');
18
+ musicPlayer.addChild(title);
19
+
20
+ // drop zone text
21
+ const dropZoneText = new UIText(vec2(0, -60), vec2(450, 20),
22
+ 'Drag & Drop Audio Files Here!');
23
+ dropZoneText.textColor = hsl(.9, .3, .8, .7);
24
+ musicPlayer.addChild(dropZoneText);
25
+
26
+ // volume slider
27
+ const volumeSlider = new UIScrollbar(vec2(0, -20), vec2(400, 30),
28
+ musicVolume, 'Music Volume');
29
+ musicPlayer.addChild(volumeSlider);
30
+ volumeSlider.onChange = () =>
31
+ {
32
+ musicVolume = volumeSlider.value;
33
+ if (music)
34
+ music.setVolume(musicVolume);
35
+ };
36
+
37
+ // play button
38
+ playButton = new UIButton(vec2(-90, 50), vec2(140, 50), 'Play');
39
+ musicPlayer.addChild(playButton);
40
+ playButton.onClick = ()=>
41
+ {
42
+ if (!musicSound.isLoaded())
43
+ return;
44
+
45
+ // handle play/pause toggle
46
+ if (!music)
47
+ music = musicSound.playMusic(musicVolume);
48
+ else if (music.isPaused())
49
+ music.resume();
50
+ else
51
+ music.pause();
52
+ };
53
+
54
+ // stop button
55
+ stopButton = new UIButton(vec2(90, 50), vec2(140, 50), 'Stop');
56
+ stopButton.onClick = ()=> music && music.stop();
57
+ musicPlayer.addChild(stopButton);
58
+
59
+ // progress bar and scrollbar for seeking
60
+ progressBar = new UIScrollbar(vec2(0, 120), vec2(400, 30), 0);
61
+ progressBar.disabledColor = RED;
62
+ progressBar.onChange = ()=>
63
+ {
64
+ // control music seek position
65
+ const wasPlaying = music && music.isPlaying();
66
+ if (!music)
67
+ music = musicSound.playMusic(musicVolume, true, true);
68
+ progressBar.value = min(progressBar.value, .999); // prevent wrap
69
+ const seekTime = progressBar.value * musicSound.getDuration();
70
+ music.start(seekTime);
71
+ if (!wasPlaying)
72
+ music.pause();
73
+ };
74
+ musicPlayer.addChild(progressBar);
75
+
76
+ {
77
+ // setup drag and drop for audio files
78
+ function onDragEnter() { musicPlayer.color = RED; };
79
+ function onDragLeave() { musicPlayer.color = WHITE; };
80
+ function onDrop(e)
81
+ {
82
+ musicPlayer.color = WHITE
83
+
84
+ // get the dropped file
85
+ const file = e.dataTransfer.files[0];
86
+ if (!file || !file.type.startsWith('audio'))
87
+ return;
88
+
89
+ // create new sound from dropped file
90
+ const fileURL = URL.createObjectURL(file);
91
+ musicSound = new SoundWave(fileURL, musicVolume);
92
+ dropZoneText.text = file.name;
93
+
94
+ // reset UI
95
+ music && music.stop();
96
+ music = undefined;
97
+ progressBar.value = 0;
98
+ }
99
+ uiSystem.setupDragAndDrop(onDrop, onDragEnter, onDragLeave);
100
+ }
101
+ }
102
+
103
+ function gameUpdate()
104
+ {
105
+ // disable buttons while loading
106
+ const isDisabled = !musicSound || !musicSound.isLoaded();
107
+ playButton.disabled = isDisabled
108
+ stopButton.disabled = isDisabled
109
+ progressBar.disabled = isDisabled
110
+
111
+ // update ui
112
+ if (!musicSound)
113
+ {
114
+ // waiting for file
115
+ progressBar.text = 'No File Loaded';
116
+ }
117
+ else if (isDisabled)
118
+ {
119
+ // update loading progress
120
+ const loadingPercent = musicSound.loadedPercent * 100|0;
121
+ progressBar.text = `Loading: ${loadingPercent}%`;
122
+ }
123
+ else
124
+ {
125
+ // update ui text
126
+ const isPlaying = music && music.isPlaying();
127
+ playButton.text = isPlaying ? 'Pause' : 'Play';
128
+ const current = music ? music.getCurrentTime() : 0;
129
+ const duration = musicSound.getDuration();
130
+ progressBar.text = formatTime(current) +' / '+ formatTime(duration);
131
+ if (!progressBar.mouseIsHeld)
132
+ progressBar.value = current / duration;
133
+ }
134
+ }
@@ -3,19 +3,38 @@ function gameRender()
3
3
  const nineSliceTile = tile(16);
4
4
  const threeSliceTile = tile(19);
5
5
 
6
- // draw nine slice with thin border and color
7
- drawNineSlice(vec2(-7,4), vec2(11+wave(.5,2), 6), nineSliceTile, hsl(.1,.5,.9), .5);
8
- drawTextOverlay('Nine Slice\nThin Border', vec2(-7,4), 1, BLACK);
9
-
10
- // draw nine slice in screen space with thick border and rotation
11
- drawNineSliceScreen(vec2(700,150), vec2(250), nineSliceTile, 32, 2, time/2);
12
- drawTextScreen('Nine Slice\nScreen Space', vec2(700,150), 30, BLACK);
13
-
14
- // draw three slice with variable border and additive color
15
- drawThreeSlice(vec2(-7,-4), vec2(9, 7), threeSliceTile, WHITE, 2+wave(.2)*2, hsl(time/30,.5,.5));
16
- drawTextOverlay('Three Slice\nVariable\n Border', vec2(-7,-4), 1, BLACK);
17
-
18
- // draw three slice in screen space with changing size
19
- drawThreeSliceScreen(vec2(700,420), vec2(350-wave(.3,90),120+wave(.3,60)), threeSliceTile);
20
- drawTextScreen('Three Slice\nScreen Space', vec2(700,420), 30, BLACK);
6
+ {
7
+ // draw nine slice with thin border and color
8
+ const pos = vec2(-7,4);
9
+ const size = vec2(11+wave(.5,2), 6);
10
+ const color = hsl(.1,.5,.9);
11
+ const border = .5;
12
+ drawNineSlice(pos, size, nineSliceTile, color, border);
13
+ drawTextOverlay('Nine Slice\nThin Border', pos, 1, BLACK);
14
+ }
15
+ {
16
+ // draw nine slice in screen space with thick border and rotation
17
+ const pos = vec2(700,150);
18
+ const size = vec2(250);
19
+ const border = 32;
20
+ const angle = time/2;
21
+ drawNineSliceScreen(pos, size, nineSliceTile, border, 2, angle);
22
+ drawTextScreen('Nine Slice\nScreen Space', pos, 30, BLACK);
23
+ }
24
+ {
25
+ // draw three slice with variable border and additive color
26
+ const pos = vec2(-7,-4);
27
+ const size = vec2(9, 7);
28
+ const border = 2 + wave(.2)*2;
29
+ const additive = hsl(time/30,.5,.5);
30
+ drawThreeSlice(pos, size, threeSliceTile, WHITE, border, additive);
31
+ drawTextOverlay('Three Slice\nVariable\nBorder', pos, 1, BLACK);
32
+ }
33
+ {
34
+ // draw three slice in screen space with changing size
35
+ const pos = vec2(700,420);
36
+ const size = vec2(350-wave(.3,90),120+wave(.3,60));
37
+ drawThreeSliceScreen(pos, size, threeSliceTile);
38
+ drawTextScreen('Three Slice\nScreen Space', pos, 30, BLACK);
39
+ }
21
40
  }
@@ -23,7 +23,7 @@ class ParallaxLayer extends CanvasLayer
23
23
  const w = canvasSize.x, h = canvasSize.y;
24
24
  for (let i = h; i--;)
25
25
  {
26
- // draw a 1 pixel gradient line on the left side of the canvas
26
+ // draw a 1 pixel gradient line on the left side
27
27
  const p = i/h;
28
28
  this.context.fillStyle = topColor.lerp(bottomColor, p);
29
29
  this.context.fillRect(0, i, 1, 1);
@@ -34,7 +34,8 @@ class ParallaxLayer extends CanvasLayer
34
34
  const levelness = .005; // how much the mountains level out
35
35
  const slopeRange = 1; // max slope of the mountains
36
36
  const startGroundLevel = h/2;
37
- let y = startGroundLevel, groundSlope = rand(-slopeRange, slopeRange);
37
+ let y = startGroundLevel;
38
+ let groundSlope = rand(-slopeRange, slopeRange);
38
39
  for (let x=w; x--;)
39
40
  {
40
41
  // pull slope towards start ground level
@@ -45,7 +46,7 @@ class ParallaxLayer extends CanvasLayer
45
46
  groundSlope = rand(-slopeRange, slopeRange);
46
47
 
47
48
  // draw 1 pixel wide vertical slice of mountain
48
- this.context.drawImage(this.canvas, 0, 0, 1, h, x, y, 1, h - y);
49
+ this.context.drawImage(this.canvas, 0,0,1,h,x,y,1,h-y);
49
50
  }
50
51
 
51
52
  // remove gradient sliver from left side
@@ -4,25 +4,25 @@ function gameInit()
4
4
 
5
5
  // fire
6
6
  new ParticleEmitter(
7
- vec2(-5,-2), 0, // pos, angle
8
- 2, 0, 200, PI, // emitSize, emitTime, emitRate, emitCone
9
- tile(0), // tileInfo
10
- rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
11
- rgb(1,.5,.1,0), rgb(1,.1,.1,0), // colorEndA, colorEndB
12
- .7, 2, 0, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
13
- .9, 1, -1, PI, .05, // damp, angleDamp, gravity, particleCone, fade
14
- .5, 0, 1, 0 // randomness, collide, additive, colorLinear
7
+ vec2(-5,-2), 0, // pos, angle
8
+ 2, 0, 200, PI, // emitSize, emitTime, rate, cone
9
+ tile(0), // tileInfo
10
+ rgb(1,.5,.1), rgb(1,.1,.1), // colorStartA, colorStartB
11
+ rgb(1,.5,.1,0), rgb(1,.1,.1,0),// colorEndA, colorEndB
12
+ .7, 2, 0, .2, .05, // time, sizeStart, sizeEnd, speed, angleSpeed
13
+ .9, 1, -1, PI, .05,// damp, angleDamp, gravity, particleCone, fade
14
+ .5, 0, 1, 0 // randomness, collide, additive, colorLinear
15
15
  );
16
16
 
17
17
  // smoke
18
18
  new ParticleEmitter(
19
19
  vec2(5,-2), 0, // pos, angle
20
- 3, 0, 100, PI, // emitSize, emitTime, emitRate, emitCone
21
- tile(0), // tileInfo
22
- hsl(0,0,0,.5), hsl(0,0,1,.5), // colorStartA, colorStartB
23
- hsl(0,0,0,0), hsl(0,0,1,0), // colorEndA, colorEndB
24
- 1, 1, 5, .2, .01, // time, sizeStart, sizeEnd, speed, angleSpeed
25
- .85, 1, -1, PI, .3, // damp, angleDamp, gravity, particleCone, fade
26
- .5, 0, 0, 1 // randomness, collide, additive, colorLinear
20
+ 3, 0, 100, PI, // emitSize, emitTime, rate, cone
21
+ tile(0), // tileInfo
22
+ hsl(0,0,0,.5), hsl(0,0,1,.5),// colorStartA, colorStartB
23
+ hsl(0,0,0,0), hsl(0,0,1,0), // colorEndA, colorEndB
24
+ 1, 1, 5, .2, .01, // time, sizeStart, sizeEnd, speed, angleSpeed
25
+ .85, 1, -1, PI, .3,// damp, angleDamp, gravity, particleCone, fade
26
+ .5, 0, 0, 1 // randomness, collide, additive, colorLinear
27
27
  );
28
28
  }
@@ -2,29 +2,21 @@ const pianoSound = new Sound([,0,220,,9]);
2
2
 
3
3
  class PianoKey extends UIButton
4
4
  {
5
- constructor(pos, size, semitone, isWhite)
5
+ constructor(pos, size, semitone, color, hoverColor)
6
6
  {
7
7
  const keySize = 65;
8
8
  size = size.scale(keySize);
9
9
  pos = pos.scale(keySize).add(vec2(0,size.y/2-keySize*2));
10
10
  pos = pos.add(mainCanvasSize.scale(.5));
11
- super(pos, size, '', hsl(0,0,isWhite ? 1 : .3));
12
- this.semitone = semitone;
11
+ super(pos, size, '', color);
12
+
13
13
  this.dragActivate = true;
14
- this.hoverColor = hsl(0,1,isWhite ? .9 : .3);
14
+ this.semitone = semitone;
15
+ this.hoverColor = hoverColor;
15
16
  this.activeColor = RED;
16
17
  }
17
- onPress()
18
- {
19
- if (!this.soundInstance)
20
- this.soundInstance = pianoSound.playNote(this.semitone);
21
- }
22
- onRelease()
23
- {
24
- if (this.soundInstance)
25
- this.soundInstance.stop(.2);
26
- this.soundInstance = 0;
27
- }
18
+ onPress() { this.sound = pianoSound.playNote(this.semitone); }
19
+ onRelease() { this.sound.stop(.2); }
28
20
  }
29
21
 
30
22
  function gameInit()
@@ -35,16 +27,18 @@ function gameInit()
35
27
  // create piano keyboard
36
28
  for (let i=15; i--;)
37
29
  {
38
- const pos = vec2(i-7,0);
39
- const size = vec2(1,4);
30
+ // white keys
31
+ const pos = vec2(i-7, 0);
32
+ const size = vec2(1, 4);
40
33
  const semitone = [0,2,4,5,7,9,11][i%7]+(i/7|0)*12;
41
- new PianoKey(pos, size, semitone, true);
34
+ new PianoKey(pos, size, semitone, WHITE, hsl(0,1,.9));
42
35
  }
43
36
  for (let i=10; i--;)
44
37
  {
45
- const pos = vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5,0)
46
- const size = vec2(1,2);
38
+ // black keys
39
+ const pos = vec2([1,2,4,5,6][i%5]+(i/5|0)*7-7.5, 0)
40
+ const size = vec2(1, 2);
47
41
  const semitone = [1,3,6,8,10][i%5]+(i/5|0)*12;
48
- new PianoKey(pos, size, semitone);
42
+ new PianoKey(pos, size, semitone, hsl(0,0,.3), hsl(0,1,.3));
49
43
  }
50
44
  }
@@ -18,10 +18,12 @@ function gameInit()
18
18
  canvasFixedSize = vec2(1280, 720); // use a 720p fixed size canvas
19
19
 
20
20
  // create objects
21
- paddle = new PhysicsObject(vec2(0,1), vec2(6,1)); // create player's paddle
22
- new PhysicsObject(vec2(-.5,levelSize.y/2), vec2(1,100)); // left wall
23
- new PhysicsObject(vec2(levelSize.x+.5,levelSize.y/2), vec2(1,100)); // right wall
24
- new PhysicsObject(vec2(levelSize.x/2,levelSize.y+.5), vec2(100,1)); // top wall
21
+ paddle = new PhysicsObject(vec2(0,1), vec2(6,1)); // player
22
+
23
+ const w = levelSize.x, h = levelSize.y;
24
+ new PhysicsObject(vec2(-.5,h/2), vec2(1,100)); // left wall
25
+ new PhysicsObject(vec2(w+.5,h/2), vec2(1,100)); // right wall
26
+ new PhysicsObject(vec2(w/2,h+.5), vec2(100,1)); // top wall
25
27
  }
26
28
 
27
29
  function gameUpdate()
@@ -45,7 +45,7 @@ function gameRender()
45
45
  {
46
46
  // draw horizontal slizes to create floor and ceiling
47
47
  const h = 9;
48
- let pos = vec2(), size = vec2(39, .15), color = WHITE;
48
+ let pos = vec2(), size = vec2(39, .15), color = rgb();
49
49
  for (let y=-h; y<h; y+=.1)
50
50
  {
51
51
  const p = 1.01-abs(y/h)
@@ -57,7 +57,7 @@ function gameRender()
57
57
  {
58
58
  // draw vertical slices to create the walls
59
59
  const w = 20;
60
- const pos = vec2(), size = vec2(.15), color = WHITE;
60
+ const pos = vec2(), size = vec2(.15), color = rgb();
61
61
  for (let x=-w; x<w; x+=.1)
62
62
  {
63
63
  const p = raycast(playerPos, playerAngle + x/w);
@@ -68,7 +68,12 @@ function gameRender()
68
68
  }
69
69
  }
70
70
  // draw instructions and pointer lock status
71
- const instructions = pointerLockIsActive() ? 'Mouse Control Active - ESC To Exit' : 'Click To Enable Mouse Control';
71
+ const instructions = pointerLockIsActive() ?
72
+ 'Mouse Control Active - ESC To Exit' :
73
+ 'Click To Enable Mouse Control';
74
+ const textPos = vec2(mainCanvasSize.x/2, 50);
75
+ const textSize = 24;
76
+ const textColor = pointerLockIsActive() ? GREEN : WHITE;
72
77
  if (!isTouchDevice)
73
- drawTextScreen(instructions, vec2(mainCanvasSize.x/2, 50), 24, pointerLockIsActive() ? GREEN : WHITE);
78
+ drawTextScreen(instructions, textPos, textSize, textColor);
74
79
  }