littlejsengine 1.13.1 → 1.14.2

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 (83) hide show
  1. package/README.md +15 -11
  2. package/copyToGithub.bat +28 -0
  3. package/dist/littlejs.d.ts +430 -304
  4. package/dist/littlejs.esm.js +1745 -982
  5. package/dist/littlejs.esm.min.js +1 -1
  6. package/dist/littlejs.js +1716 -965
  7. package/dist/littlejs.min.js +1 -1
  8. package/dist/littlejs.release.js +1673 -922
  9. package/examples/box2d/game.js +2 -2
  10. package/examples/box2d/gameObjects.js +2 -2
  11. package/examples/box2d/scenes.js +1 -1
  12. package/examples/breakout/game.js +30 -25
  13. package/examples/breakoutTutorial/README.md +44 -41
  14. package/examples/breakoutTutorial/game.js +2 -2
  15. package/examples/electron/build.bat +7 -0
  16. package/examples/electron/build.js +124 -0
  17. package/examples/electron/electron.js +35 -0
  18. package/examples/electron/game.js +140 -0
  19. package/examples/electron/index.html +13 -0
  20. package/examples/electron/package.json +12 -0
  21. package/examples/electron/tiles.png +0 -0
  22. package/examples/empty/game.js +1 -0
  23. package/examples/htmlMenu/game.js +1 -1
  24. package/examples/index.html +332 -160
  25. package/examples/module/game.js +5 -2
  26. package/examples/particles/index.html +12 -3
  27. package/examples/platformer/gameEffects.js +20 -19
  28. package/examples/platformer/gameLevel.js +6 -1
  29. package/examples/shorts/base.html +1 -1
  30. package/examples/shorts/blending.js +9 -5
  31. package/examples/shorts/box2d.js +1 -1
  32. package/examples/shorts/box2dCar.js +1 -1
  33. package/examples/shorts/clock.js +1 -1
  34. package/examples/shorts/colors.js +2 -2
  35. package/examples/shorts/flappyGame.js +2 -1
  36. package/examples/shorts/helloWorld.js +1 -1
  37. package/examples/shorts/maze.js +1 -1
  38. package/examples/shorts/music.js +106 -0
  39. package/examples/shorts/nineSlice.js +9 -9
  40. package/examples/shorts/parallax.js +71 -0
  41. package/examples/shorts/piano.js +9 -10
  42. package/examples/shorts/postProcess.js +25 -8
  43. package/examples/shorts/raycasting.js +2 -2
  44. package/examples/shorts/shapes.js +7 -15
  45. package/examples/shorts/slidingPuzzle.js +2 -2
  46. package/examples/shorts/song.mp3 +0 -0
  47. package/examples/shorts/starfield.js +5 -7
  48. package/examples/shorts/systemFont.js +1 -1
  49. package/examples/shorts/uiSystem.js +16 -8
  50. package/examples/starter/build.js +9 -8
  51. package/examples/starter/game.js +5 -2
  52. package/examples/starter/index.html +2 -2
  53. package/examples/stress/index.html +13 -8
  54. package/examples/style.css +19 -6
  55. package/examples/typescript/build.js +1 -1
  56. package/examples/typescript/game.js +2 -2
  57. package/examples/typescript/game.ts +5 -2
  58. package/examples/uiSystem/game.js +13 -12
  59. package/package.json +2 -2
  60. package/plugins/box2d.js +24 -97
  61. package/plugins/drawUtilities.js +29 -23
  62. package/plugins/newgrounds.js +6 -6
  63. package/plugins/pluginExport.js +1 -1
  64. package/plugins/postProcess.js +7 -0
  65. package/plugins/uiSystem.js +106 -82
  66. package/plugins/zzfxm.js +10 -10
  67. package/reference.md +90 -54
  68. package/src/engine.js +28 -23
  69. package/src/engineAudio.js +285 -110
  70. package/src/engineBuild.js +9 -9
  71. package/src/engineDebug.js +28 -28
  72. package/src/engineDraw.js +346 -202
  73. package/src/engineExport.js +28 -16
  74. package/src/engineInput.js +58 -68
  75. package/src/engineMedals.js +29 -29
  76. package/src/engineObject.js +28 -25
  77. package/src/engineParticles.js +67 -60
  78. package/src/engineRelease.js +1 -1
  79. package/src/engineSettings.js +70 -16
  80. package/src/engineTileLayer.js +34 -34
  81. package/src/engineUtilities.js +69 -62
  82. package/src/engineWebGL.js +467 -65
  83. /package/examples/shorts/{playSound.js → sound.js} +0 -0
@@ -136,8 +136,8 @@ function gameUpdatePost()
136
136
  ///////////////////////////////////////////////////////////////////////////////
137
137
  function gameRender()
138
138
  {
139
- // draw a grey square in the background without using webgl
140
- LJS.drawRect(vec2(20,8), vec2(100), hsl(0,0,.8), 0, 0);
139
+ // draw a grey square in the background without using WebGL
140
+ LJS.drawRect(vec2(20,8), vec2(100), hsl(0,0,.8), 0, false);
141
141
 
142
142
  if (Scenes.scene == 5)
143
143
  {
@@ -20,7 +20,7 @@ const restitution = .2;
20
20
 
21
21
  export function spawnBox(pos, size=1, color=LJS.WHITE, type=LJS.box2d.bodyTypeDynamic, applyTexture=true, angle=0)
22
22
  {
23
- size = typeof size == 'number' ? vec2(size) : size; // square
23
+ size = typeof size === 'number' ? vec2(size) : size; // square
24
24
  const o = new LJS.Box2dObject(pos, size, applyTexture && Game.spriteAtlas.squareOutline, angle, color, type);
25
25
  o.drawSize = size.scale(1.02); // slightly enlarge to cover gaps
26
26
  o.addBox(size, vec2(), 0, density, friction, restitution);
@@ -308,7 +308,7 @@ export class SoftBodyObject extends LJS.Box2dObject
308
308
  for (let y = 0; y < sy.y; ++y) poly.push(this.getNode(sx-1, y).pos);
309
309
  for (let x = sx; x--;) poly.push(this.getNode(x, sy-1).pos);
310
310
  for (let y = sy; y--;) poly.push(this.getNode(0, y).pos);
311
- LJS.box2d.drawPoly(vec2(), 0, poly, LJS.BLACK)
311
+ LJS.drawPoly(poly, LJS.BLACK)
312
312
  }
313
313
  getNode(x, y)
314
314
  {
@@ -181,7 +181,7 @@ export function loadScene(_scene)
181
181
  if (scene == 10)
182
182
  {
183
183
  sceneName = 'Softbodies';
184
- for(let i=3;i--;)
184
+ for (let i=3;i--;)
185
185
  new GameObjects.SoftBodyObject(vec2(20, 3+i*7), vec2(6-i), vec2(9-i), LJS.randColor());
186
186
  }
187
187
  }
@@ -122,38 +122,43 @@ function setupPostProcess()
122
122
  p=fract(p*.3197);
123
123
  return fract(1.+sin(51.*p.x+73.*p.y)*13753.3);
124
124
  }
125
- float noise(vec2 p)
126
- {
127
- vec2 i=floor(p),f=fract(p),u=f*f*(3.-2.*f);
128
- return mix(mix(hash(i),hash(i+vec2(1,0)),u.x),mix(hash(i+vec2(0,1)),hash(i+1.),u.x),u.y);
129
- }
125
+
130
126
  void mainImage(out vec4 c, vec2 p)
131
127
  {
132
- // put uv in texture pixel space
128
+ // setup the shader
129
+ vec2 uv = p;
133
130
  p /= iResolution.xy;
134
-
135
- // apply fuzz as horizontal offset
136
- const float fuzz = .0005;
137
- const float fuzzScale = 800.;
138
- const float fuzzSpeed = 9.;
139
- p.x += fuzz*(noise(vec2(p.y*fuzzScale, iTime*fuzzSpeed))*2.-1.);
140
-
141
- // init output color
142
131
  c = texture(iChannel0, p);
143
132
 
144
- // chromatic aberration
145
- const float chromatic = .002;
146
- c.r = texture(iChannel0, p - vec2(chromatic,0)).r;
147
- c.b = texture(iChannel0, p + vec2(chromatic,0)).b;
148
-
149
- // tv static noise
150
- const float staticNoise = .1;
151
- c += staticNoise * hash(p + mod(iTime, 1e3));
133
+ // static noise
134
+ const float staticAlpha = .1;
135
+ const float staticScale = .002;
136
+ c += staticAlpha * hash(floor(p/staticScale) + mod(iTime*500., 1e3));
152
137
 
153
138
  // scan lines
154
- const float scanlineScale = 1e3;
155
- const float scanlineAlpha = .1;
156
- c *= 1. + scanlineAlpha*sin(p.y*scanlineScale);
139
+ const float scanlineScale = 2.;
140
+ const float scanlineAlpha = .3;
141
+ c *= 1. - scanlineAlpha*cos(p.y*2.*iResolution.y/scanlineScale);
142
+
143
+ {
144
+ // bloom effect
145
+ const float blurSize = .002;
146
+ const float bloomIntensity = .2;
147
+
148
+ // 5-tap Gaussian blur
149
+ vec4 bloom = vec4(0);
150
+ bloom += texture(iChannel0, p + vec2(-2.*blurSize, 0)) * .12;
151
+ bloom += texture(iChannel0, p + vec2( -blurSize, 0)) * .24;
152
+ bloom += texture(iChannel0, p) * .28;
153
+ bloom += texture(iChannel0, p + vec2( blurSize, 0)) * .24;
154
+ bloom += texture(iChannel0, p + vec2( 2.*blurSize, 0)) * .12;
155
+ bloom += texture(iChannel0, p + vec2(0, -2.*blurSize)) * .12;
156
+ bloom += texture(iChannel0, p + vec2(0, -blurSize)) * .24;
157
+ bloom += texture(iChannel0, p) * .28;
158
+ bloom += texture(iChannel0, p + vec2(0, blurSize)) * .24;
159
+ bloom += texture(iChannel0, p + vec2(0, 2.*blurSize)) * .12;
160
+ c += bloom * bloomIntensity;
161
+ }
157
162
 
158
163
  // black vignette around edges
159
164
  const float vignette = 2.;
@@ -21,11 +21,11 @@ The first step is to make a 2D grid of brick objects in gameInit. As a placehold
21
21
 
22
22
  ```javascript
23
23
  // create bricks
24
- for(let x=0; x<=20; x++)
25
- for(let y=0; y<=20; y++)
24
+ for (let x=0; x<=20; x++)
25
+ for (let y=0; y<=20; y++)
26
26
  {
27
- const brick = new EngineObject(vec2(x,y)); // create a brick
28
- brick.color = randColor(); // give brick a random color
27
+ const brick = new LJS.EngineObject(vec2(x,y)); // create a brick
28
+ brick.color = LJS.randColor(); // give brick a random color
29
29
  }
30
30
  ```
31
31
 
@@ -42,11 +42,11 @@ Let’s make the bricks more rectangular by passing vec2(2,1) to the size parame
42
42
  ```javascript
43
43
  // create bricks
44
44
  const levelSize = vec2(20, 20);
45
- for(let x=0; x<=levelSize.x; x+=2)
46
- for(let y=0; y<=levelSize.y; y+=1)
45
+ for (let x=0; x<=levelSize.x; x+=2)
46
+ for (let y=0; y<=levelSize.y; y+=1)
47
47
  {
48
- const brick = new EngineObject(vec2(x,y), vec2(2,1)); // create a brick
49
- brick.color = randColor(); // give brick a random color
48
+ const brick = new LJS.EngineObject(vec2(x,y), vec2(2,1)); // create a brick
49
+ brick.color = LJS.randColor(); // give brick a random color
50
50
  }
51
51
  ```
52
52
 
@@ -57,13 +57,13 @@ You can also change the camera zoom by using camaraScale which controls the numb
57
57
  For this example the camera will just remain stationary, but in other types of games it is very useful!
58
58
 
59
59
  ```javascript
60
- setCameraPos(levelSize.scale(.5)); // center camera in level
60
+ LJS.setCameraPos(levelSize.scale(.5)); // center camera in level
61
61
  ```
62
62
 
63
63
  We’ll also start with a blank slate by commenting out the default “Hello World!” text in gameRenderPost.
64
64
 
65
65
  ```javascript
66
- // drawTextScreen('Hello World!', mainCanvasSize.scale(.5), 80);
66
+ // LJS.drawTextScreen('Hello World!', LJS.mainCanvasSize.scale(.5), 80);
67
67
  ```
68
68
 
69
69
  ![LittleJS Screenshot](images/2.png)
@@ -77,14 +77,14 @@ For this example we will use a fixed size canvas. This will let the drawing canv
77
77
  To enable it we will set canvasFixedSize in gameInit to use 720p resolution.
78
78
 
79
79
  ```javascript
80
- setCanvasFixedSize(vec2(1280, 720)); // use a 720p fixed size canvas
80
+ LJS.setCanvasFixedSize(vec2(1280, 720)); // use a 720p fixed size canvas
81
81
  ```
82
82
 
83
83
  Before we tweak the level size, let’s add this bit of code to gameRender to show the size of the level. This will cause some rects to be drawn each frame before the engine objects. To create color objects we pass in RGB values between 0 and 1.
84
84
 
85
85
  ```javascript
86
- drawRect(cameraPos, vec2(100), new Color(.5,.5,.5)); // draw background
87
- drawRect(cameraPos, levelSize, new Color(.1,.1,.1)); // draw level boundary
86
+ LJS.drawRect(LJS.cameraPos, vec2(100), rgb(.5,.5,.5)); // draw background
87
+ LJS.drawRect(LJS.cameraPos, levelSize, rgb(.1,.1,.1)); // draw level boundary
88
88
  ```
89
89
 
90
90
  We also need to make levelSize a global by moving it to the top so it can be accessed from other functions.
@@ -98,11 +98,11 @@ Now we can see the boundaries of our level and tweak the size to fill the canvas
98
98
  We can also adjust the for loop where the bricks are created to make them only fill the top middle part of the level.
99
99
 
100
100
  ```javascript
101
- for(let x=2; x<=levelSize.x-2; x+=2)
102
- for(let y=12; y<=levelSize.y-2; y+=1)
101
+ for (let x=2; x<=levelSize.x-2; x+=2)
102
+ for (let y=12; y<=levelSize.y-2; y+=1)
103
103
  {
104
- const brick = new EngineObject(vec2(x,y), vec2(2,1)); // create a brick
105
- brick.color = randColor(); // give brick a random color
104
+ const brick = new LJS.EngineObject(vec2(x,y), vec2(2,1)); // create a brick
105
+ brick.color = LJS.randColor(); // give brick a random color
106
106
  }
107
107
  ```
108
108
 
@@ -115,11 +115,11 @@ Now that looks almost like a breakout game!
115
115
  For the player’s paddle, let’s create a new class of object that extends the built in EngineObject. This will allow us to control movement with the mouse. In this Paddle class we will just add some new code to the update function which is automatically called each frame by the engine.
116
116
 
117
117
  ```javascript
118
- class Paddle extends EngineObject
118
+ class Paddle extends LJS.EngineObject
119
119
  {
120
120
  update()
121
121
  {
122
- this.pos.x = mousePos.x; // move paddle to mouse
122
+ this.pos.x = LJS.mousePos.x; // move paddle to mouse
123
123
  }
124
124
  }
125
125
  ```
@@ -149,7 +149,7 @@ You can also add this code to the paddle update that will keep the paddle from f
149
149
 
150
150
  ```javascript
151
151
  // clamp paddle to level size
152
- this.pos.x = clamp(this.pos.x, this.size.x/2, levelSize.x - this.size.x/2);
152
+ this.pos.x = LJS.clamp(this.pos.x, this.size.x/2, levelSize.x - this.size.x/2);
153
153
  ```
154
154
 
155
155
  ## Create the Ball
@@ -158,7 +158,7 @@ The final missing piece is of course that ball that moves around and bounces off
158
158
  We can create a Ball class the same way we created the paddle. In this case we will also apply some velocity to ball so it starts moving right away.
159
159
 
160
160
  ```javascript
161
- class Ball extends EngineObject
161
+ class Ball extends LJS.EngineObject
162
162
  {
163
163
  constructor(pos)
164
164
  {
@@ -172,7 +172,10 @@ class Ball extends EngineObject
172
172
  Then we just need to create the ball in gameInit, passing in the camera position for it’s location.
173
173
 
174
174
  ```javascript
175
- new Ball(cameraPos); // create a ball
175
+ {
176
+ // create a ball
177
+ ball = new Ball(LJS.cameraPos);
178
+ }
176
179
  ```
177
180
 
178
181
  ## Make the Ball Collide
@@ -210,7 +213,7 @@ super(pos, vec2(.5)); // set object position and size
210
213
  Next, let’s make the ball bounce when it hits the top or sides of the screen. To do this, we will make a Wall object class that works similar to the paddle but without an update function.
211
214
 
212
215
  ```javascript
213
- class Wall extends EngineObject
216
+ class Wall extends LJS.EngineObject
214
217
  {
215
218
  constructor(pos, size)
216
219
  {
@@ -236,7 +239,7 @@ new Wall(vec2(levelSize.x/2,levelSize.y+.5), vec2(100,1)) // top
236
239
  Now we have white walls around the outside that block the ball. These walls should be invisible so we will set their color to be transparent by adding another line to the Wall constructor.
237
240
 
238
241
  ```javascript
239
- this.color = new Color(0,0,0,0); // make object invisible
242
+ this.color = rgb(0,0,0,0); // make object invisible
240
243
  ```
241
244
 
242
245
  ## Debug Display
@@ -268,7 +271,7 @@ if (!ball || ball.pos.y < -1)
268
271
  ball.destroy();
269
272
 
270
273
  // create a ball
271
- ball = new Ball(cameraPos);
274
+ ball = new Ball(LJS.cameraPos);
272
275
  }
273
276
  ```
274
277
 
@@ -279,7 +282,7 @@ Don’t forget to destroy the old ball before creating the new one! Though it do
279
282
  Still, the ball doesn’t collide with the bricks much less breaks them and it wouldn’t be breakout without that. So we need to make the brick collide with the ball, just like the walls, so let’s start with Brick class that is the same as Wall.
280
283
 
281
284
  ```javascript
282
- class Brick extends EngineObject
285
+ class Brick extends LJS.EngineObject
283
286
  {
284
287
  constructor(pos, size)
285
288
  {
@@ -333,7 +336,7 @@ Then increment it in the Brick.collideWithObject function.
333
336
  And change that drawTextScreen code we had commented out in gameRenderPost to display the score. We can adjust the position and size of the text to fit at the top of the screen.
334
337
 
335
338
  ```javascript
336
- drawTextScreen("Score " + score, vec2(mainCanvasSize.x/2, 70), 50); // show score
339
+ LJS.drawTextScreen("Score " + score, vec2(LJS.mainCanvasSize.x/2, 70), 50); // show score
337
340
  ```
338
341
 
339
342
  ![LittleJS Screenshot](images/9.png)
@@ -347,7 +350,7 @@ We will start with the ball bounce sound. [You can use the official ZzFX sound d
347
350
  To make a sound effect with this system we will create a global object for each sound.
348
351
 
349
352
  ```javascript
350
- const sound_bounce = new Sound([,,1e3,,.03,.02,1,2,,,940,.03,,,,,.2,.6,,.06], 0);
353
+ const sound_bounce = new LJS.Sound([,,1e3,,.03,.02,1,2,,,940,.03,,,,,.2,.6,,.06], 0);
351
354
  ```
352
355
 
353
356
  You can use the sound I chose or copy the code for your own sound from ZzFX. There is a checkbox for LittleJS style sounds to make exporting a little easier.
@@ -366,7 +369,7 @@ Let’s also make a brick break sound. You can use the ZzFX sound designer again
366
369
  Create a global object for this sound the same way we did for the bounce sound. You can replace it with your own generated sound or use mine.
367
370
 
368
371
  ```javascript
369
- const sound_break = new Sound([,,90,,.01,.03,4,,,,,,,9,50,.2,,.2,.01], 0);
372
+ const sound_break = new LJS.Sound([,,90,,.01,.03,4,,,,,,,9,50,.2,,.2,.01], 0);
370
373
  ```
371
374
 
372
375
  Then in the Brick’s collideWithObject function just add some code to play that sound.
@@ -384,7 +387,7 @@ Let’s improve the gameplay by letting the player click to start, instead of cr
384
387
  We can also add a special sound that plays on startup. Try making an interesting start from the ZzFX sound designer, maybe using the Powerup preset.
385
388
 
386
389
  ```javascript
387
- const sound_start = new Sound([,0,500,,.04,.3,1,2,,,570,.02,.02,,,,.04]);
390
+ const sound_start = new LJS.Sound([,0,500,,.04,.3,1,2,,,570,.02,.02,,,,.04]);
388
391
  ```
389
392
 
390
393
  We can modify the gameUpdate to wait for player input from the mouse and play the sound when the ball is created.
@@ -396,9 +399,9 @@ if (ball && ball.pos.y < -1) // if ball is below level
396
399
  ball.destroy();
397
400
  ball = 0;
398
401
  }
399
- if (!ball && mouseWasPressed(0)) // if there is no ball and left mouse is pressed
402
+ if (!ball && LJS.mouseWasPressed(0)) // if there is no ball and left mouse is pressed
400
403
  {
401
- ball = new Ball(cameraPos); // create the ball
404
+ ball = new Ball(LJS.cameraPos); // create the ball
402
405
  sound_start.play(); // play start sound
403
406
  }
404
407
  ```
@@ -413,7 +416,7 @@ Make sure you replace the first parameter, vec2(), with this.pos so the effect a
413
416
 
414
417
  ```javascript
415
418
  // create explosion effect
416
- new ParticleEmitter(this.pos, 0, 0, 0.1, 100, 3.14, 0, new Color(1, 1, 1, 1), new Color(1, 1, 1, 1), new Color(1, 1, 1, 0), new Color(1, 1, 1, 0), 0.5, 0.1, 1, 0.1, 0.05, 1, 1, 0, 3.14, 0.1, 0.2, 0, 0, 1);
419
+ new LJS.ParticleEmitter(this.pos, 0, 0, 0.1, 100, 3.14, 0, rgb(1, 1, 1, 1), rgb(1, 1, 1, 1), rgb(1, 1, 1, 0), rgb(1, 1, 1, 0), 0.5, 0.1, 1, 0.1, 0.05, 1, 1, 0, 3.14, 0.1, 0.2, 0, 0, 1);
417
420
  ```
418
421
 
419
422
  Now you should see this simple particle effect play wherever a brick breaks. You can continue tweaking the parameters to make your own effect or use the one I made which also uses this.color to change the particle’s color so it matches the brick.
@@ -421,15 +424,15 @@ Now you should see this simple particle effect play wherever a brick breaks. You
421
424
  ```javascript
422
425
  // create explosion effect
423
426
  const color = this.color;
424
- new ParticleEmitter(
425
- this.pos, 0, // pos, angle
426
- this.size, .1, 200, PI, // emitSize, emitTime, emitRate, emiteCone
427
- undefined, // tileInfo
428
- color, color, // colorStartA, colorStartB
427
+ new LJS.ParticleEmitter(
428
+ this.pos, 0, // pos, angle
429
+ this.size, .1, 200, 3.14,// emitSize, emitTime, emitRate, emitCone
430
+ undefined, // tileInfo
431
+ color, color, // colorStartA, colorStartB
429
432
  color.scale(1,0), color.scale(1,0), // colorEndA, colorEndB
430
433
  .2, .5, 1, .1, .1, // time, sizeStart, sizeEnd, speed, angleSpeed
431
- .99, .95, .4, PI, // damping, angleDamping, gravityScale, cone
432
- .1, .5, false, true // fadeRate, randomness, collide, additive
434
+ .99, .95, .4, 3.14, // damp, angleDamp, gravity, cone
435
+ .1, .5, false, true // fade, randomness, collide, additive
433
436
  );
434
437
  ```
435
438
 
@@ -459,7 +462,7 @@ collideWithObject(o)
459
462
  this.velocity = this.velocity.rotate(.3 * deltaX);
460
463
 
461
464
  // make sure ball is moving upwards with a minimum speed
462
- this.velocity.y = max(-this.velocity.y, .2);
465
+ this.velocity.y = LJS.max(-this.velocity.y, .2);
463
466
 
464
467
  // prevent default collision code
465
468
  return false;
@@ -138,8 +138,8 @@ function gameInit()
138
138
  LJS.setCanvasFixedSize(vec2(1280, 720)); // use a 720p fixed size canvas
139
139
 
140
140
  // create bricks
141
- for(let x=2; x<=levelSize.x-2; x+=2)
142
- for(let y=12; y<=levelSize.y-2; y+=1)
141
+ for (let x=2; x<=levelSize.x-2; x+=2)
142
+ for (let y=12; y<=levelSize.y-2; y+=1)
143
143
  new Brick(vec2(x,y), vec2(2,1)); // create a brick
144
144
 
145
145
  // create player paddle
@@ -0,0 +1,7 @@
1
+ rem LittleJS Build Script
2
+ call node build.js
3
+ if %errorlevel% neq 0 (
4
+ echo Build failed with error level %errorlevel%
5
+ pause
6
+ exit /b %errorlevel%
7
+ )
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LittleJS Build System
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const PROGRAM_TITLE = 'Little JS Electron Project';
10
+ const PROGRAM_NAME = 'game';
11
+ const BUILD_FOLDER = 'build';
12
+ const USE_ROADROLLER = false; // enable for extra compression
13
+ const sourceFiles =
14
+ [
15
+ '../../dist/littlejs.release.js',
16
+ 'game.js',
17
+ // add your game's files here
18
+ ];
19
+ const dataFiles =
20
+ [
21
+ 'tiles.png',
22
+ // add your game's data files here
23
+ ];
24
+
25
+ console.log(`Building ${PROGRAM_NAME}...`);
26
+ const startTime = Date.now();
27
+ const fs = require('node:fs');
28
+ const child_process = require('node:child_process');
29
+
30
+ // rebuild engine
31
+ //child_process.execSync(`npm run build`, { stdio: 'inherit' });
32
+
33
+ // remove old files and setup build folder
34
+ fs.rmSync(BUILD_FOLDER, { recursive: true, force: true });
35
+ fs.rmSync(`${PROGRAM_NAME}.zip`, { force: true });
36
+ fs.mkdirSync(BUILD_FOLDER);
37
+
38
+ // copy data files
39
+ for (const file of dataFiles)
40
+ fs.copyFileSync(file, `${BUILD_FOLDER}/${file}`);
41
+
42
+ Build
43
+ (
44
+ `${BUILD_FOLDER}/index.js`,
45
+ sourceFiles,
46
+ USE_ROADROLLER ?
47
+ [closureCompilerStep, uglifyBuildStep, roadrollerBuildStep, htmlBuildStep, electronBuildStep] :
48
+ [closureCompilerStep, uglifyBuildStep, htmlBuildStep, electronBuildStep]
49
+ );
50
+
51
+ console.log('');
52
+ console.log(`Build Completed in ${((Date.now() - startTime)/1e3).toFixed(2)} seconds!`);
53
+
54
+ ///////////////////////////////////////////////////////////////////////////////
55
+
56
+ // A single build with its own source files, build steps, and output file
57
+ // - each build step is a callback that accepts a single filename
58
+ function Build(outputFile, files=[], buildSteps=[])
59
+ {
60
+ // copy files into a buffer
61
+ let buffer = '';
62
+ for (const file of files)
63
+ buffer += fs.readFileSync(file) + '\n';
64
+
65
+ // output file
66
+ fs.writeFileSync(outputFile, buffer, {flag: 'w+'});
67
+
68
+ // execute build steps in order
69
+ for (const buildStep of buildSteps)
70
+ buildStep(outputFile);
71
+ }
72
+
73
+ function closureCompilerStep(filename)
74
+ {
75
+ console.log('Running closure compiler...');
76
+
77
+ // use closer compiler to minify the code
78
+ const filenameTemp = filename + '.tmp';
79
+ fs.copyFileSync(filename, filenameTemp);
80
+ child_process.execSync(`npx google-closure-compiler --js=${filenameTemp} --js_output_file=${filename} --compilation_level=ADVANCED --warning_level=VERBOSE --jscomp_off=* --assume_function_wrapper`, {stdio: 'inherit'});
81
+ fs.rmSync(filenameTemp);
82
+ };
83
+
84
+ function uglifyBuildStep(filename)
85
+ {
86
+ console.log('Running uglify...');
87
+ child_process.execSync(`npx uglifyjs ${filename} -c -m -o ${filename}`, {stdio: 'inherit'});
88
+ };
89
+
90
+ function roadrollerBuildStep(filename)
91
+ {
92
+ console.log('Running roadroller...');
93
+ child_process.execSync(`npx roadroller ${filename} -o ${filename}`, {stdio: 'inherit'});
94
+ };
95
+
96
+ function htmlBuildStep(filename)
97
+ {
98
+ console.log('Building html...');
99
+
100
+ // create html file
101
+ let buffer = '';
102
+ buffer += '<!DOCTYPE html>';
103
+ buffer += '<head>';
104
+ buffer += `<title>${PROGRAM_TITLE}</title>`;
105
+ buffer += '<meta charset=utf-8>';
106
+ buffer += '</head>';
107
+ buffer += '<body>';
108
+ buffer += '<script src="index.js"></script>';
109
+
110
+ // output html file
111
+ fs.writeFileSync(`${BUILD_FOLDER}/index.html`, buffer, {flag: 'w+'});
112
+ };
113
+
114
+ function electronBuildStep(filename)
115
+ {
116
+ console.log('Building executable with electron...');
117
+
118
+ // copy elecron files to build folder
119
+ fs.copyFileSync('electron.js', `${BUILD_FOLDER}/electron.js`);
120
+ fs.copyFileSync('package.json', `${BUILD_FOLDER}/package.json`);
121
+
122
+ // run electron packager
123
+ child_process.execSync(`npx electron-packager ./${BUILD_FOLDER} --overwrite`, {stdio: 'inherit'});
124
+ };
@@ -0,0 +1,35 @@
1
+ const { app, BrowserWindow } = require('electron');
2
+
3
+ function createWindow()
4
+ {
5
+ // create the browser window
6
+ const mainWindow = new BrowserWindow({width: 800, height: 600});
7
+
8
+ // hide the toolbar menu
9
+ mainWindow.setMenu(null);
10
+
11
+ // load the index.html of the app
12
+ mainWindow.loadFile('index.html');
13
+
14
+ // go fullscreen
15
+ //mainWindow.setFullScreen(true);
16
+
17
+ // open the dev tools debugging
18
+ //mainWindow.webContents.openDevTools()
19
+ }
20
+
21
+ // wait until the app is ready and create the window
22
+ app.whenReady().then(createWindow);
23
+
24
+ // quit when all windows are closed (except macOS convention)
25
+ app.on('window-all-closed', ()=>
26
+ {
27
+ if (process.platform != 'darwin')
28
+ app.quit();
29
+ });
30
+
31
+ app.on('activate', ()=>
32
+ {
33
+ if (BrowserWindow.getAllWindows().length == 0)
34
+ createWindow();
35
+ });