littlejsengine 1.11.2 → 1.11.4

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 (56) hide show
  1. package/.vscode/launch.json +14 -0
  2. package/README.md +14 -20
  3. package/dist/littlejs.d.ts +41 -30
  4. package/dist/littlejs.esm.js +145 -141
  5. package/dist/littlejs.esm.min.js +1 -1
  6. package/dist/littlejs.js +141 -140
  7. package/dist/littlejs.min.js +1 -1
  8. package/dist/littlejs.release.js +138 -133
  9. package/examples/box2d/gameObjects.js +4 -4
  10. package/examples/box2d/scenes.js +2 -2
  11. package/examples/breakout/gameObjects.js +2 -2
  12. package/examples/breakoutTutorial/game.js +1 -1
  13. package/examples/index.html +1 -7
  14. package/examples/logo.png +0 -0
  15. package/examples/module/game.js +1 -1
  16. package/examples/platformer/game.js +2 -2
  17. package/examples/platformer/gameCharacter.js +5 -5
  18. package/examples/platformer/gameEffects.js +4 -4
  19. package/examples/platformer/gameObjects.js +2 -2
  20. package/examples/puzzle/game.js +2 -2
  21. package/examples/starter/game.js +10 -44
  22. package/examples/starter/tiles.png +0 -0
  23. package/jsconfig.json +1 -0
  24. package/package.json +1 -1
  25. package/plugins/box2d.js +10 -10
  26. package/plugins/newgrounds.js +1 -1
  27. package/src/engine.js +5 -3
  28. package/src/engineAudio.js +4 -4
  29. package/src/engineDebug.js +3 -7
  30. package/src/engineDraw.js +50 -25
  31. package/src/engineExport.js +4 -1
  32. package/src/engineInput.js +1 -1
  33. package/src/engineObject.js +8 -8
  34. package/src/engineParticles.js +6 -6
  35. package/src/engineSettings.js +5 -5
  36. package/src/engineTileLayer.js +2 -2
  37. package/src/engineUtilities.js +5 -5
  38. package/src/engineWebGL.js +52 -74
  39. package/examples/electron/build.js +0 -107
  40. package/examples/electron/electron.js +0 -43
  41. package/examples/electron/game.js +0 -131
  42. package/examples/electron/index.html +0 -13
  43. package/examples/electron/package.json +0 -22
  44. package/examples/electron/tiles.png +0 -0
  45. package/examples/js13k/build.bat +0 -2
  46. package/examples/js13k/build.js +0 -131
  47. package/examples/js13k/game.js +0 -118
  48. package/examples/js13k/index.html +0 -21
  49. package/examples/js13k/tiles.png +0 -0
  50. package/examples/typescript/build.bat +0 -5
  51. package/examples/typescript/build.js +0 -33
  52. package/examples/typescript/game.js +0 -102
  53. package/examples/typescript/game.ts +0 -134
  54. package/examples/typescript/index.html +0 -10
  55. package/examples/typescript/tiles.png +0 -0
  56. package/examples/typescript/tsconfig.json +0 -8
@@ -197,14 +197,16 @@ export {
197
197
  drawEllipse,
198
198
  drawCircle,
199
199
  drawCanvas2D,
200
- setBlendMode,
201
200
  drawText,
202
201
  drawTextOverlay,
203
202
  drawTextScreen,
203
+ setBlendMode,
204
+ combineCanvases,
204
205
  engineFontImage,
205
206
  FontImage,
206
207
  isFullscreen,
207
208
  toggleFullscreen,
209
+ setCursor,
208
210
  getCameraSize,
209
211
 
210
212
  // WebGL
@@ -218,6 +220,7 @@ export {
218
220
  glFlush,
219
221
  glSetTexture,
220
222
  glSetAntialias,
223
+ glClearCanvas,
221
224
  glAntialias,
222
225
  glShader,
223
226
  glActiveTexture,
@@ -341,7 +341,7 @@ function vibrateStop() { vibrate(0); }
341
341
 
342
342
  /** True if a touch device has been detected
343
343
  * @memberof Input */
344
- const isTouchDevice = window.ontouchstart !== undefined;
344
+ const isTouchDevice = !headlessMode && window.ontouchstart !== undefined;
345
345
 
346
346
  // touch gamepad internal variables
347
347
  let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
@@ -155,7 +155,7 @@ class EngineObject
155
155
  const oldPos = this.pos.copy();
156
156
  this.velocity.x *= this.damping;
157
157
  this.velocity.y *= this.damping;
158
- if (this.mass) // dont apply gravity to static objects
158
+ if (this.mass) // don't apply gravity to static objects
159
159
  this.velocity.y += gravity * this.gravityScale;
160
160
  this.pos.x += this.velocity.x;
161
161
  this.pos.y += this.velocity.y;
@@ -164,7 +164,7 @@ class EngineObject
164
164
  // physics sanity checks
165
165
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
166
166
  ASSERT(this.damping >= 0 && this.damping <= 1);
167
- if (!enablePhysicsSolver || !this.mass) // dont do collision for static objects
167
+ if (!enablePhysicsSolver || !this.mass) // don't do collision for static objects
168
168
  return;
169
169
 
170
170
  const wasMovingDown = this.velocity.y < 0;
@@ -183,7 +183,7 @@ class EngineObject
183
183
  const epsilon = .001; // necessary to push slightly outside of the collision
184
184
  for (const o of engineObjectsCollide)
185
185
  {
186
- // non solid objects don't collide with eachother
186
+ // non solid objects don't collide with each other
187
187
  if (!this.isSolid && !o.isSolid || o.destroyed || o.parent || o == this)
188
188
  continue;
189
189
 
@@ -243,7 +243,7 @@ class EngineObject
243
243
  const elastic1 = o.velocity.y * (o.mass - this.mass) / (this.mass + o.mass)
244
244
  + this.velocity.y * 2 * this.mass / (this.mass + o.mass);
245
245
 
246
- // lerp betwen elastic or inelastic based on elasticity
246
+ // lerp between elastic or inelastic based on elasticity
247
247
  this.velocity.y = lerp(elasticity, inelastic, elastic0);
248
248
  o.velocity.y = lerp(elasticity, inelastic, elastic1);
249
249
  }
@@ -263,7 +263,7 @@ class EngineObject
263
263
  const elastic1 = o.velocity.x * (o.mass - this.mass) / (this.mass + o.mass)
264
264
  + this.velocity.x * 2 * this.mass / (this.mass + o.mass);
265
265
 
266
- // lerp betwen elastic or inelastic based on elasticity
266
+ // lerp between elastic or inelastic based on elasticity
267
267
  this.velocity.x = lerp(elasticity, inelastic, elastic0);
268
268
  o.velocity.x = lerp(elasticity, inelastic, elastic1);
269
269
  }
@@ -329,7 +329,7 @@ class EngineObject
329
329
  if (this.destroyed)
330
330
  return;
331
331
 
332
- // disconnect from parent and destroy chidren
332
+ // disconnect from parent and destroy children
333
333
  this.destroyed = 1;
334
334
  this.parent && this.parent.removeChild(this);
335
335
  for (const child of this.children)
@@ -354,7 +354,7 @@ class EngineObject
354
354
 
355
355
  /** Called to check if a tile collision should be resolved
356
356
  * @param {Number} tileData - the value of the tile at the position
357
- * @param {Vector2} pos - tile where the collision occured
357
+ * @param {Vector2} pos - tile where the collision occurred
358
358
  * @return {Boolean} - true if the collision should be resolved */
359
359
  collideWithTile(tileData, pos) { return tileData > 0; }
360
360
 
@@ -417,7 +417,7 @@ class EngineObject
417
417
  this.collideRaycast = collideRaycast;
418
418
  }
419
419
 
420
- /** Returns string containg info about this object for debugging
420
+ /** Returns string containing info about this object for debugging
421
421
  * @return {String} */
422
422
  toString()
423
423
  {
@@ -12,7 +12,7 @@
12
12
  * let pos = vec2(2,3);
13
13
  * let particleEmitter = new ParticleEmitter
14
14
  * (
15
- * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
15
+ * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emitCone
16
16
  * tile(0, 16), // tileInfo
17
17
  * rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
18
18
  * rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
@@ -47,7 +47,7 @@ class ParticleEmitter extends EngineObject
47
47
  * @param {Number} [fadeRate] - How quick to fade particles at start/end in percent of life
48
48
  * @param {Number} [randomness] - Apply extra randomness percent
49
49
  * @param {Boolean} [collideTiles] - Do particles collide against tiles
50
- * @param {Boolean} [additive] - Should particles use addtive blend
50
+ * @param {Boolean} [additive] - Should particles use additive blend
51
51
  * @param {Boolean} [randomColorLinear] - Should color be randomized linearly or across each component
52
52
  * @param {Number} [renderOrder] - Render order for particles (additive is above other stuff by default)
53
53
  * @param {Boolean} [localSpace] - Should it be in local space of emitter (world space is default)
@@ -132,11 +132,11 @@ class ParticleEmitter extends EngineObject
132
132
  this.randomness = randomness;
133
133
  /** @property {Boolean} - Do particles collide against tiles */
134
134
  this.collideTiles = collideTiles;
135
- /** @property {Boolean} - Should particles use addtive blend */
135
+ /** @property {Boolean} - Should particles use additive blend */
136
136
  this.additive = additive;
137
137
  /** @property {Boolean} - Should it be in local space of emitter */
138
138
  this.localSpace = localSpace;
139
- /** @property {Number} - If non zero the partile is drawn as a trail, stretched in the drection of velocity */
139
+ /** @property {Number} - If non zero the particle is drawn as a trail, stretched in the direction of velocity */
140
140
  this.trailScale = 0;
141
141
  /** @property {Function} - Callback when particle is destroyed */
142
142
  this.particleDestroyCallback = undefined;
@@ -185,7 +185,7 @@ class ParticleEmitter extends EngineObject
185
185
  angle += this.angle;
186
186
  }
187
187
 
188
- // randomness scales each paremeter by a percentage
188
+ // randomness scales each parameter by a percentage
189
189
  const randomness = this.randomness;
190
190
  const randomizeScale = (v)=> v + v*rand(randomness, -randomness);
191
191
 
@@ -214,7 +214,7 @@ class ParticleEmitter extends EngineObject
214
214
  particle.renderOrder = this.renderOrder;
215
215
  particle.mirror = !!randInt(2);
216
216
 
217
- // call particle create callaback
217
+ // call particle create callback
218
218
  this.particleCreateCallback && this.particleCreateCallback(particle);
219
219
 
220
220
  // return the newly created particle
@@ -106,7 +106,7 @@ let tileFixBleedScale = 0;
106
106
  * @memberof Settings */
107
107
  let enablePhysicsSolver = true;
108
108
 
109
- /** Default object mass for collision calcuations (how heavy objects are)
109
+ /** Default object mass for collision calculations (how heavy objects are)
110
110
  * @type {Number}
111
111
  * @default
112
112
  * @memberof Settings */
@@ -317,7 +317,7 @@ function setFontDefault(font) { fontDefault = font; }
317
317
  * @memberof Settings */
318
318
  function setShowSplashScreen(show) { showSplashScreen = show; }
319
319
 
320
- /** Set to disalbe rendering, audio, and input for servers
320
+ /** Set to disable rendering, audio, and input for servers
321
321
  * @param {Boolean} headless
322
322
  * @memberof Settings */
323
323
  function setHeadlessMode(headless) { headlessMode = headless; }
@@ -347,7 +347,7 @@ function setTileFixBleedScale(scale) { tileFixBleedScale = scale; }
347
347
  * @memberof Settings */
348
348
  function setEnablePhysicsSolver(enable) { enablePhysicsSolver = enable; }
349
349
 
350
- /** Set default object mass for collison calcuations
350
+ /** Set default object mass for collision calculations
351
351
  * @param {Number} mass
352
352
  * @memberof Settings */
353
353
  function setObjectDefaultMass(mass) { objectDefaultMass = mass; }
@@ -417,7 +417,7 @@ function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
417
417
  * @memberof Settings */
418
418
  function setTouchGamepadAnalog(analog) { touchGamepadAnalog = analog; }
419
419
 
420
- /** Set size of virutal gamepad for touch devices in pixels
420
+ /** Set size of virtual gamepad for touch devices in pixels
421
421
  * @param {Number} size
422
422
  * @memberof Settings */
423
423
  function setTouchGamepadSize(size) { touchGamepadSize = size; }
@@ -444,7 +444,7 @@ function setSoundVolume(volume)
444
444
  {
445
445
  soundVolume = volume;
446
446
  if (soundEnable && !headlessMode && audioGainNode)
447
- audioGainNode.gain.value = volume; // update gain immediatly
447
+ audioGainNode.gain.value = volume; // update gain immediately
448
448
  }
449
449
 
450
450
  /** Set default range where sound no longer plays
@@ -301,7 +301,7 @@ class TileLayer extends EngineObject
301
301
 
302
302
  /** Draw the tile at a given position in the tile grid
303
303
  * This can be used to clear out tiles when they are destroyed
304
- * Tiles can also be redrawn if isinde a redrawStart/End block
304
+ * Tiles can also be redrawn if inside a redrawStart/End block
305
305
  * @param {Vector2} layerPos
306
306
  * @param {Boolean} [clear] - should the old tile be cleared out
307
307
  */
@@ -326,7 +326,7 @@ class TileLayer extends EngineObject
326
326
  }
327
327
  }
328
328
 
329
- /** Draw directly to the 2D canvas in world space (bipass webgl)
329
+ /** Draw directly to the 2D canvas in world space (bypass webgl)
330
330
  * @param {Vector2} pos
331
331
  * @param {Vector2} size
332
332
  * @param {Number} angle
@@ -16,7 +16,7 @@
16
16
  * @memberof Utilities */
17
17
  const PI = Math.PI;
18
18
 
19
- /** Returns absoulte value of value passed in
19
+ /** Returns absolute value of value passed in
20
20
  * @param {Number} value
21
21
  * @return {Number}
22
22
  * @memberof Utilities */
@@ -49,7 +49,7 @@ function sign(value) { return Math.sign(value); }
49
49
  * @memberof Utilities */
50
50
  function mod(dividend, divisor=1) { return ((dividend % divisor) + divisor) % divisor; }
51
51
 
52
- /** Clamps the value beween max and min
52
+ /** Clamps the value between max and min
53
53
  * @param {Number} value
54
54
  * @param {Number} [min]
55
55
  * @param {Number} [max]
@@ -485,7 +485,7 @@ class Vector2
485
485
  return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
486
486
  }
487
487
 
488
- /** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
488
+ /** Set the integer direction of this vector, corresponding to multiples of 90 degree rotation (0-3)
489
489
  * @param {Number} [direction]
490
490
  * @param {Number} [length] */
491
491
  setDirection(direction, length=1)
@@ -496,7 +496,7 @@ class Vector2
496
496
  direction%2 ? 0 : direction ? -length : length);
497
497
  }
498
498
 
499
- /** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
499
+ /** Returns the integer direction of this vector, corresponding to multiples of 90 degree rotation (0-3)
500
500
  * @return {Number} */
501
501
  direction()
502
502
  { return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
@@ -881,7 +881,7 @@ const MAGENTA = rgb(1,0,1);
881
881
  * a.set(3); // sets the timer to 3 seconds
882
882
  *
883
883
  * let b = new Timer(1); // creates a timer with 1 second left
884
- * b.unset(); // unsets the timer
884
+ * b.unset(); // unset the timer
885
885
  */
886
886
  class Timer
887
887
  {
@@ -22,7 +22,7 @@ let glCanvas;
22
22
  * @memberof WebGL */
23
23
  let glContext;
24
24
 
25
- /** Shoule webgl be setup with antialiasing, must be set before calling engineInit
25
+ /** Should webgl be setup with anti-aliasing? must be set before calling engineInit
26
26
  * @type {Boolean}
27
27
  * @memberof WebGL */
28
28
  let glAntialias = true;
@@ -30,9 +30,15 @@ let glAntialias = true;
30
30
  // WebGL internal variables not exposed to documentation
31
31
  let glShader, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glInstanceCount, glAdditive, glBatchAdditive;
32
32
 
33
+ // WebGL internal constants
34
+ const gl_MAX_INSTANCES = 1e4;
35
+ const gl_INDICES_PER_INSTANCE = 11;
36
+ const gl_INSTANCE_BYTE_STRIDE = gl_INDICES_PER_INSTANCE * 4;
37
+ const gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
38
+
33
39
  ///////////////////////////////////////////////////////////////////////////////
34
40
 
35
- // Initalize WebGL, called automatically by the engine
41
+ // Initialize WebGL, called automatically by the engine
36
42
  function glInit()
37
43
  {
38
44
  if (!glEnable || headlessMode) return;
@@ -82,8 +88,8 @@ function glInit()
82
88
 
83
89
  // create the geometry buffer, triangle strip square
84
90
  const geometry = new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);
85
- glContext.bindBuffer(gl_ARRAY_BUFFER, glGeometryBuffer);
86
- glContext.bufferData(gl_ARRAY_BUFFER, geometry, gl_STATIC_DRAW);
91
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
92
+ glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
87
93
  }
88
94
 
89
95
  // Setup render each frame, called automatically by engine
@@ -91,15 +97,12 @@ function glPreRender()
91
97
  {
92
98
  if (!glEnable || headlessMode) return;
93
99
 
94
- // clear and set to same size as main canvas
95
- glContext.viewport(0, 0, glCanvas.width=mainCanvas.width, glCanvas.height=mainCanvas.height);
96
- glContext.clear(gl_COLOR_BUFFER_BIT);
97
-
98
- // set up the shader
100
+ // set up the shader and canvas
101
+ glClearCanvas();
99
102
  glContext.useProgram(glShader);
100
- glContext.activeTexture(gl_TEXTURE0);
103
+ glContext.activeTexture(glContext.TEXTURE0);
101
104
  if (textureInfos[0])
102
- glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
105
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
103
106
 
104
107
  // set vertex attributes
105
108
  let offset = glAdditive = glBatchAdditive = 0;
@@ -114,15 +117,15 @@ function glPreRender()
114
117
  glContext.vertexAttribDivisor(location, divisor);
115
118
  offset += size*typeSize;
116
119
  }
117
- glContext.bindBuffer(gl_ARRAY_BUFFER, glGeometryBuffer);
118
- initVertexAttribArray('g', gl_FLOAT, 0, 2); // geometry
119
- glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
120
- glContext.bufferData(gl_ARRAY_BUFFER, gl_INSTANCE_BUFFER_SIZE, gl_DYNAMIC_DRAW);
121
- initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & size
122
- initVertexAttribArray('u', gl_FLOAT, 4, 4); // texture coords
123
- initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4); // color
124
- initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4); // additiveColor
125
- initVertexAttribArray('r', gl_FLOAT, 4, 1); // rotation
120
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
121
+ initVertexAttribArray('g', glContext.FLOAT, 0, 2); // geometry
122
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
123
+ glContext.bufferData(glContext.ARRAY_BUFFER, gl_INSTANCE_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
124
+ initVertexAttribArray('p', glContext.FLOAT, 4, 4); // position & size
125
+ initVertexAttribArray('u', glContext.FLOAT, 4, 4); // texture coords
126
+ initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
127
+ initVertexAttribArray('a', glContext.UNSIGNED_BYTE, 1, 4); // additiveColor
128
+ initVertexAttribArray('r', glContext.FLOAT, 4, 1); // rotation
126
129
 
127
130
  // build the transform matrix
128
131
  const s = vec2(2*cameraScale).divide(mainCanvasSize);
@@ -137,6 +140,15 @@ function glPreRender()
137
140
  );
138
141
  }
139
142
 
143
+ /** Clear the canvas and setup the viewport
144
+ * @memberof WebGL */
145
+ function glClearCanvas()
146
+ {
147
+ // clear and set to same size as main canvas
148
+ glContext.viewport(0, 0, glCanvas.width=mainCanvas.width, glCanvas.height=mainCanvas.height);
149
+ glContext.clear(glContext.COLOR_BUFFER_BIT);
150
+ }
151
+
140
152
  /** Set the WebGl texture, called automatically if using multiple textures
141
153
  * - This may also flush the gl buffer resulting in more draw calls and worse performance
142
154
  * @param {WebGLTexture} texture
@@ -148,7 +160,7 @@ function glSetTexture(texture)
148
160
  return;
149
161
 
150
162
  glFlush();
151
- glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = texture);
163
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = texture);
152
164
  }
153
165
 
154
166
  /** Compile WebGL shader of the given type, will throw errors if in debug mode
@@ -164,7 +176,7 @@ function glCompileShader(source, type)
164
176
  glContext.compileShader(shader);
165
177
 
166
178
  // check for errors
167
- if (debug && !glContext.getShaderParameter(shader, gl_COMPILE_STATUS))
179
+ if (debug && !glContext.getShaderParameter(shader, glContext.COMPILE_STATUS))
168
180
  throw glContext.getShaderInfoLog(shader);
169
181
  return shader;
170
182
  }
@@ -178,12 +190,12 @@ function glCreateProgram(vsSource, fsSource)
178
190
  {
179
191
  // build the program
180
192
  const program = glContext.createProgram();
181
- glContext.attachShader(program, glCompileShader(vsSource, gl_VERTEX_SHADER));
182
- glContext.attachShader(program, glCompileShader(fsSource, gl_FRAGMENT_SHADER));
193
+ glContext.attachShader(program, glCompileShader(vsSource, glContext.VERTEX_SHADER));
194
+ glContext.attachShader(program, glCompileShader(fsSource, glContext.FRAGMENT_SHADER));
183
195
  glContext.linkProgram(program);
184
196
 
185
197
  // check for errors
186
- if (debug && !glContext.getProgramParameter(program, gl_LINK_STATUS))
198
+ if (debug && !glContext.getProgramParameter(program, glContext.LINK_STATUS))
187
199
  throw glContext.getProgramInfoLog(program);
188
200
  return program;
189
201
  }
@@ -196,20 +208,20 @@ function glCreateTexture(image)
196
208
  {
197
209
  // build the texture
198
210
  const texture = glContext.createTexture();
199
- glContext.bindTexture(gl_TEXTURE_2D, texture);
211
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
200
212
  if (image && image.width)
201
- glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
213
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
202
214
  else
203
215
  {
204
216
  // create a white texture
205
217
  const whitePixel = new Uint8Array([255, 255, 255, 255]);
206
- glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, 1, 1, 0, gl_RGBA, gl_UNSIGNED_BYTE, whitePixel);
218
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
207
219
  }
208
220
 
209
221
  // use point filtering for pixelated rendering
210
- const filter = tilesPixelated ? gl_NEAREST : gl_LINEAR;
211
- glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
212
- glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
222
+ const filter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
223
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, filter);
224
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, filter);
213
225
  return texture;
214
226
  }
215
227
 
@@ -219,20 +231,20 @@ function glFlush()
219
231
  {
220
232
  if (!glInstanceCount) return;
221
233
 
222
- const destBlend = glBatchAdditive ? gl_ONE : gl_ONE_MINUS_SRC_ALPHA;
223
- glContext.blendFuncSeparate(gl_SRC_ALPHA, destBlend, gl_ONE, destBlend);
224
- glContext.enable(gl_BLEND);
234
+ const destBlend = glBatchAdditive ? glContext.ONE : glContext.ONE_MINUS_SRC_ALPHA;
235
+ glContext.blendFuncSeparate(glContext.SRC_ALPHA, destBlend, glContext.ONE, destBlend);
236
+ glContext.enable(glContext.BLEND);
225
237
 
226
238
  // draw all the sprites in the batch and reset the buffer
227
- glContext.bufferSubData(gl_ARRAY_BUFFER, 0, glPositionData);
228
- glContext.drawArraysInstanced(gl_TRIANGLE_STRIP, 0, 4, glInstanceCount);
239
+ glContext.bufferSubData(glContext.ARRAY_BUFFER, 0, glPositionData);
240
+ glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP, 0, 4, glInstanceCount);
229
241
  if (showWatermark)
230
242
  drawCount += glInstanceCount;
231
243
  glInstanceCount = 0;
232
244
  glBatchAdditive = glAdditive;
233
245
  }
234
246
 
235
- /** Draw any sprites still in the buffer, copy to main canvas and clear
247
+ /** Draw any sprites still in the buffer and copy to main canvas
236
248
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
237
249
  * @param {Boolean} [forceDraw]
238
250
  * @memberof WebGL */
@@ -247,7 +259,7 @@ function glCopyToContext(context, forceDraw=false)
247
259
  context.drawImage(glCanvas, 0, 0);
248
260
  }
249
261
 
250
- /** Set antialiasing for webgl canvas
262
+ /** Set anti-aliasing for webgl canvas
251
263
  * @param {Boolean} [antialias]
252
264
  * @memberof WebGL */
253
265
  function glSetAntialias(antialias=true)
@@ -277,7 +289,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
277
289
  if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
278
290
  glFlush();
279
291
 
280
- let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
292
+ let offset = glInstanceCount++ * gl_INDICES_PER_INSTANCE;
281
293
  glPositionData[offset++] = x;
282
294
  glPositionData[offset++] = y;
283
295
  glPositionData[offset++] = sizeX;
@@ -289,38 +301,4 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
289
301
  glColorData[offset++] = rgba;
290
302
  glColorData[offset++] = rgbaAdditive;
291
303
  glPositionData[offset++] = angle;
292
- glInstanceCount++;
293
- }
294
-
295
- ///////////////////////////////////////////////////////////////////////////////
296
- // store gl constants as integers so their name doesn't use space in minifed
297
- const
298
- gl_ONE = 1,
299
- gl_TRIANGLE_STRIP = 5,
300
- gl_SRC_ALPHA = 770,
301
- gl_ONE_MINUS_SRC_ALPHA = 771,
302
- gl_BLEND = 3042,
303
- gl_TEXTURE_2D = 3553,
304
- gl_UNSIGNED_BYTE = 5121,
305
- gl_FLOAT = 5126,
306
- gl_RGBA = 6408,
307
- gl_NEAREST = 9728,
308
- gl_LINEAR = 9729,
309
- gl_TEXTURE_MAG_FILTER = 10240,
310
- gl_TEXTURE_MIN_FILTER = 10241,
311
- gl_COLOR_BUFFER_BIT = 16384,
312
- gl_TEXTURE0 = 33984,
313
- gl_ARRAY_BUFFER = 34962,
314
- gl_STATIC_DRAW = 35044,
315
- gl_DYNAMIC_DRAW = 35048,
316
- gl_FRAGMENT_SHADER = 35632,
317
- gl_VERTEX_SHADER = 35633,
318
- gl_COMPILE_STATUS = 35713,
319
- gl_LINK_STATUS = 35714,
320
- gl_UNPACK_FLIP_Y_WEBGL = 37440,
321
-
322
- // constants for batch rendering
323
- gl_INDICIES_PER_INSTANCE = 11,
324
- gl_MAX_INSTANCES = 1e4,
325
- gl_INSTANCE_BYTE_STRIDE = gl_INDICIES_PER_INSTANCE * 4, // 11 * 4
326
- gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
304
+ }
@@ -1,107 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * LittleJS Build System
5
- */
6
-
7
- 'use strict';
8
-
9
- const PROGRAM_NAME = 'game';
10
- const BUILD_FOLDER = 'build';
11
- const sourceFiles =
12
- [
13
- '../../dist/littlejs.release.js',
14
- 'game.js',
15
- // add your game's files here
16
- ];
17
- const dataFiles =
18
- [
19
- 'tiles.png',
20
- // add your game's data files here
21
- ];
22
-
23
- console.log(`Building ${PROGRAM_NAME} with electron...`);
24
- const startTime = Date.now();
25
- const fs = require('node:fs');
26
- const child_process = require('node:child_process');
27
-
28
- // remove old files and setup build folder
29
- fs.rmSync(BUILD_FOLDER, { recursive: true, force: true });
30
- fs.rmSync(`${PROGRAM_NAME}.zip`, { force: true });
31
- fs.mkdirSync(BUILD_FOLDER);
32
-
33
- // copy data files
34
- for(const file of dataFiles)
35
- fs.copyFileSync(file, `${BUILD_FOLDER}/${file}`);
36
-
37
- Build
38
- (
39
- `${BUILD_FOLDER}/index.js`,
40
- sourceFiles,
41
- [closureCompilerStep, uglifyBuildStep, htmlBuildStep, electronBuildStep]
42
- );
43
-
44
- console.log(`Build Completed in ${((Date.now() - startTime)/1e3).toFixed(2)} seconds!`);
45
-
46
- ///////////////////////////////////////////////////////////////////////////////
47
-
48
- // A single build with its own source files, build steps, and output file
49
- // - each build step is a callback that accepts a single filename
50
- function Build(outputFile, files=[], buildSteps=[])
51
- {
52
- // copy files into a buffer
53
- let buffer = '';
54
- for (const file of files)
55
- buffer += fs.readFileSync(file) + '\n';
56
-
57
- // output file
58
- fs.writeFileSync(outputFile, buffer, {flag: 'w+'});
59
-
60
- // execute build steps in order
61
- for (const buildStep of buildSteps)
62
- buildStep(outputFile);
63
- }
64
-
65
- function closureCompilerStep(filename)
66
- {
67
- console.log(`Running closure compiler...`);
68
-
69
- const filenameTemp = filename + '.tmp';
70
- fs.copyFileSync(filename, filenameTemp);
71
- 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'});
72
- fs.rmSync(filenameTemp);
73
- };
74
-
75
- function uglifyBuildStep(filename)
76
- {
77
- console.log(`Running uglify...`);
78
- child_process.execSync(`npx uglifyjs ${filename} -c -m -o ${filename}`, {stdio: 'inherit'});
79
- };
80
-
81
- function htmlBuildStep(filename)
82
- {
83
- console.log(`Building html...`);
84
-
85
- // create html file
86
- let buffer = '<!DOCTYPE html>';
87
- buffer += '<script>';
88
- buffer += fs.readFileSync(filename) + '\n';
89
- buffer += '</script>';
90
-
91
- // output html file
92
- fs.writeFileSync(`${BUILD_FOLDER}/index.html`, buffer, {flag: 'w+'});
93
- };
94
-
95
- function electronBuildStep(filename)
96
- {
97
- console.log(`Building executable with electron...`);
98
-
99
- // delete intermediate files
100
- fs.rmSync(filename);
101
-
102
- // copy elecron files to build folder
103
- fs.copyFileSync('electron.js', `${BUILD_FOLDER}/electron.js`);
104
- fs.copyFileSync('package.json', `${BUILD_FOLDER}/package.json`);
105
-
106
- child_process.execSync(`npx electron-packager ./${BUILD_FOLDER} --overwrite`, {stdio: 'inherit'});
107
- };
@@ -1,43 +0,0 @@
1
- // Modules to control application life and create native browser window
2
- const { app, BrowserWindow } = require('electron')
3
-
4
- const createWindow = () => {
5
- // Create the browser window.
6
- const mainWindow = new BrowserWindow({
7
- width: 800,
8
- height: 600
9
- })
10
-
11
- // hide menu
12
- mainWindow.setMenu(null);
13
- //mainWindow.setFullScreen(true);
14
-
15
- // and load the index.html of the app.
16
- mainWindow.loadFile('index.html')
17
-
18
- // Open the DevTools.
19
- // mainWindow.webContents.openDevTools()
20
- }
21
-
22
- // This method will be called when Electron has finished
23
- // initialization and is ready to create browser windows.
24
- // Some APIs can only be used after this event occurs.
25
- app.whenReady().then(() => {
26
- createWindow()
27
-
28
- app.on('activate', () => {
29
- // On macOS it's common to re-create a window in the app when the
30
- // dock icon is clicked and there are no other windows open.
31
- if (BrowserWindow.getAllWindows().length === 0) createWindow()
32
- })
33
- })
34
-
35
- // Quit when all windows are closed, except on macOS. There, it's common
36
- // for applications and their menu bar to stay active until the user quits
37
- // explicitly with Cmd + Q.
38
- app.on('window-all-closed', () => {
39
- if (process.platform !== 'darwin') app.quit()
40
- })
41
-
42
- // In this file you can include the rest of your app's specific main process
43
- // code. You can also put them in separate files and require them here.