littlejsengine 1.9.0 → 1.9.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlejsengine",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "LittleJS - Tiny and Fast HTML5 Game Engine",
5
5
  "main": "build/littlejs.esm.js",
6
6
  "types": "build/littlejs.esm.js",
package/src/engine.js CHANGED
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
30
30
  * @type {String}
31
31
  * @default
32
32
  * @memberof Engine */
33
- const engineVersion = '1.9.0';
33
+ const engineVersion = '1.9.1';
34
34
 
35
35
  /** Frames per second to update objects
36
36
  * @type {Number}
package/src/engineDraw.js CHANGED
@@ -61,7 +61,7 @@ let drawCount;
61
61
  * Create a tile info object
62
62
  * - This can take vecs or floats for easier use and conversion
63
63
  * - If an index is passed in, the tile size and index will determine the position
64
- * @param {(Number|Vector2)} [pos=Vector2()] - Top left corner of tile in pixels or index
64
+ * @param {(Number|Vector2)} [pos=(0,0)] - Top left corner of tile in pixels or index
65
65
  * @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
66
66
  * @param {Number} [textureIndex] - Texture index to use
67
67
  * @return {TileInfo}
@@ -104,7 +104,7 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
104
104
  class TileInfo
105
105
  {
106
106
  /** Create a tile info object
107
- * @param {Vector2} [pos=Vector2()] - Top left corner of tile in pixels
107
+ * @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
108
108
  * @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
109
109
  * @param {Number} [textureIndex] - Texture index to use
110
110
  */
@@ -181,16 +181,16 @@ function worldToScreen(worldPos)
181
181
  }
182
182
 
183
183
  /** Draw textured tile centered in world space, with color applied if using WebGL
184
- * @param {Vector2} pos - Center of the tile in world space
185
- * @param {Vector2} [size=Vector2(1,1)] - Size of the tile in world space
186
- * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
187
- * @param {Color} [color=Color()] - Color to modulate with
188
- * @param {Number} [angle] - Angle to rotate by
189
- * @param {Boolean} [mirror] - If true image is flipped along the Y axis
190
- * @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
191
- * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
192
- * @param {Boolean} [screenSpace] - If true the pos and size are in screen space
193
- * @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
184
+ * @param {Vector2} pos - Center of the tile in world space
185
+ * @param {Vector2} [size=(1,1)] - Size of the tile in world space
186
+ * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
187
+ * @param {Color} [color=(1,1,1,1)] - Color to modulate with
188
+ * @param {Number} [angle] - Angle to rotate by
189
+ * @param {Boolean} [mirror] - If true image is flipped along the Y axis
190
+ * @param {Color} [additiveColor=(0,0,0,0)] - Additive color to be applied
191
+ * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
192
+ * @param {Boolean} [screenSpace=false] - If true the pos and size are in screen space
193
+ * @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
194
194
  * @memberof Draw */
195
195
  function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
196
196
  angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
@@ -258,11 +258,11 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
258
258
 
259
259
  /** Draw colored rect centered on pos
260
260
  * @param {Vector2} pos
261
- * @param {Vector2} [size=Vector2(1,1)]
262
- * @param {Color} [color=Color()]
261
+ * @param {Vector2} [size=(1,1)]
262
+ * @param {Color} [color=(1,1,1,1)]
263
263
  * @param {Number} [angle]
264
264
  * @param {Boolean} [useWebGL=glEnable]
265
- * @param {Boolean} [screenSpace]
265
+ * @param {Boolean} [screenSpace=false]
266
266
  * @param {CanvasRenderingContext2D} [context]
267
267
  * @memberof Draw */
268
268
  function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
@@ -272,8 +272,8 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
272
272
 
273
273
  /** Draw colored polygon using passed in points
274
274
  * @param {Array} points - Array of Vector2 points
275
- * @param {Color} [color=Color()]
276
- * @param {Boolean} [screenSpace]
275
+ * @param {Color} [color=(1,1,1,1)]
276
+ * @param {Boolean} [screenSpace=false]
277
277
  * @param {CanvasRenderingContext2D} [context=mainContext]
278
278
  * @memberof Draw */
279
279
  function drawPoly(points, color=new Color, screenSpace, context=mainContext)
@@ -289,9 +289,9 @@ function drawPoly(points, color=new Color, screenSpace, context=mainContext)
289
289
  * @param {Vector2} posA
290
290
  * @param {Vector2} posB
291
291
  * @param {Number} [thickness]
292
- * @param {Color} [color=Color()]
292
+ * @param {Color} [color=(1,1,1,1)]
293
293
  * @param {Boolean} [useWebGL=glEnable]
294
- * @param {Boolean} [screenSpace]
294
+ * @param {Boolean} [screenSpace=false]
295
295
  * @param {CanvasRenderingContext2D} [context]
296
296
  * @memberof Draw */
297
297
  function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
@@ -307,7 +307,7 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, contex
307
307
  * @param {Number} angle
308
308
  * @param {Boolean} mirror
309
309
  * @param {Function} drawFunction
310
- * @param {Boolean} [screenSpace]
310
+ * @param {Boolean} [screenSpace=false]
311
311
  * @param {CanvasRenderingContext2D} [context=mainContext]
312
312
  * @memberof Draw */
313
313
  function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
@@ -349,9 +349,9 @@ function setBlendMode(additive, useWebGL=glEnable, context)
349
349
  * @param {String} text
350
350
  * @param {Vector2} pos
351
351
  * @param {Number} [size]
352
- * @param {Color} [color=Color()]
352
+ * @param {Color} [color=(1,1,1,1)]
353
353
  * @param {Number} [lineWidth]
354
- * @param {Color} [lineColor=Color(0,0,0)]
354
+ * @param {Color} [lineColor=(0,0,0,1)]
355
355
  * @param {CanvasTextAlign} [textAlign='center']
356
356
  * @param {String} [font=fontDefault]
357
357
  * @param {CanvasRenderingContext2D} [context=overlayContext]
@@ -366,9 +366,9 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
366
366
  * @param {String} text
367
367
  * @param {Vector2} pos
368
368
  * @param {Number} [size]
369
- * @param {Color} [color=Color()]
369
+ * @param {Color} [color=(1,1,1,1)]
370
370
  * @param {Number} [lineWidth]
371
- * @param {Color} [lineColor=Color(0,0,0)]
371
+ * @param {Color} [lineColor=(0,0,0,1)]
372
372
  * @param {CanvasTextAlign} [textAlign]
373
373
  * @param {String} [font=fontDefault]
374
374
  * @param {CanvasRenderingContext2D} [context=overlayContext]
@@ -411,9 +411,9 @@ let engineFontImage;
411
411
  class FontImage
412
412
  {
413
413
  /** Create an image font
414
- * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
415
- * @param {Vector2} [tileSize=Vector2(8)] - Size of the font source tiles
416
- * @param {Vector2} [paddingSize=Vector2(0,1)] - How much extra space to add between characters
414
+ * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
415
+ * @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
416
+ * @param {Vector2} [paddingSize=(0,1)] - How much extra space to add between characters
417
417
  * @param {CanvasRenderingContext2D} [context=overlayContext] - context to draw to
418
418
  */
419
419
  constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
@@ -191,10 +191,10 @@ function inputUpdatePost()
191
191
  ///////////////////////////////////////////////////////////////////////////////
192
192
  // Mouse event handlers
193
193
 
194
- onmousedown = (e)=> {isUsingGamepad = false; inputData[0][e.button] = 3; window.onmousemove(e); e.button && e.preventDefault();}
194
+ onmousedown = (e)=> {isUsingGamepad = false; inputData[0][e.button] = 3; mousePosScreen = mouseToScreen(e); e.button && e.preventDefault();}
195
195
  onmouseup = (e)=> inputData[0][e.button] = inputData[0][e.button] & 2 | 4;
196
196
  onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
197
- onwheel = (e)=> e.ctrlKey || (mouseWheel = sign(e.deltaY));
197
+ onwheel = (e)=> mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
198
198
  oncontextmenu = (e)=> false; // prevent right click menu
199
199
 
200
200
  // convert a mouse or touch event position to screen space
@@ -288,7 +288,7 @@ function gamepadsUpdate()
288
288
  ///////////////////////////////////////////////////////////////////////////////
289
289
 
290
290
  /** Pulse the vibration hardware if it exists
291
- * @param {Number} [pattern] - a single value in miliseconds or vibration interval array
291
+ * @param {Number|Array} [pattern] - single value in ms or vibration interval array
292
292
  * @memberof Input */
293
293
  function vibrate(pattern=100)
294
294
  { vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern); }
@@ -32,12 +32,12 @@
32
32
  class EngineObject
33
33
  {
34
34
  /** Create an engine object and adds it to the list of objects
35
- * @param {Vector2} [pos=Vector2()] - World space position of the object
36
- * @param {Vector2} [size=Vector2(1,1)] - World space size of the object
37
- * @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
38
- * @param {Number} [angle] - Angle the object is rotated by
39
- * @param {Color} [color=Color()] - Color to apply to tile when rendered
40
- * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
35
+ * @param {Vector2} [pos=(0,0)] - World space position of the object
36
+ * @param {Vector2} [size=(1,1)] - World space size of the object
37
+ * @param {TileInfo} [tileInfo] - Tile info to render object (undefined is untextured)
38
+ * @param {Number} [angle] - Angle the object is rotated by
39
+ * @param {Color} [color=(1,1,1,1)] - Color to apply to tile when rendered
40
+ * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
41
41
  */
42
42
  constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
43
43
  {
@@ -337,7 +337,7 @@ class EngineObject
337
337
 
338
338
  /** Attaches a child to this with a given local transform
339
339
  * @param {EngineObject} child
340
- * @param {Vector2} [localPos=Vector2()]
340
+ * @param {Vector2} [localPos=(0,0)]
341
341
  * @param {Number} [localAngle] */
342
342
  addChild(child, localPos=vec2(), localAngle=0)
343
343
  {
@@ -31,10 +31,10 @@ class ParticleEmitter extends EngineObject
31
31
  * @param {Number} [emitRate] - How many particles per second to spawn, does not emit if 0
32
32
  * @param {Number} [emitConeAngle=PI] - Local angle to apply velocity to particles from emitter
33
33
  * @param {TileInfo} [tileInfo] - Tile info to render particles (undefined is untextured)
34
- * @param {Color} [colorStartA=Color()] - Color at start of life 1, randomized between start colors
35
- * @param {Color} [colorStartB=Color()] - Color at start of life 2, randomized between start colors
36
- * @param {Color} [colorEndA=Color(1,1,1,0)] - Color at end of life 1, randomized between end colors
37
- * @param {Color} [colorEndB=Color(1,1,1,0)] - Color at end of life 2, randomized between end colors
34
+ * @param {Color} [colorStartA=(1,1,1,1)] - Color at start of life 1, randomized between start colors
35
+ * @param {Color} [colorStartB=(1,1,1,1)] - Color at start of life 2, randomized between start colors
36
+ * @param {Color} [colorEndA=(1,1,1,0)] - Color at end of life 1, randomized between end colors
37
+ * @param {Color} [colorEndB=(1,1,1,0)] - Color at end of life 2, randomized between end colors
38
38
  * @param {Number} [particleTime] - How long particles live
39
39
  * @param {Number} [sizeStart] - How big are particles at start
40
40
  * @param {Number} [sizeEnd] - How big are particles at end
@@ -53,7 +53,7 @@ function getTileCollisionData(pos)
53
53
 
54
54
  /** Check if collision with another object should occur
55
55
  * @param {Vector2} pos
56
- * @param {Vector2} [size=Vector2(1,1)]
56
+ * @param {Vector2} [size=(1,1)]
57
57
  * @param {EngineObject} [object]
58
58
  * @return {Boolean}
59
59
  * @memberof TileCollision */
@@ -169,11 +169,11 @@ class TileLayerData
169
169
  class TileLayer extends EngineObject
170
170
  {
171
171
  /** Create a tile layer object
172
- * @param {Vector2} [position=Vector2()] - World space position
172
+ * @param {Vector2} [position=(0,0)] - World space position
173
173
  * @param {Vector2} [size=tileCollisionSize] - World space size
174
- * @param {TileInfo} [tileInfo] - Tile info for layer
175
- * @param {Vector2} [scale=Vector2(1,1)] - How much to scale this layer when rendered
176
- * @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
174
+ * @param {TileInfo} [tileInfo] - Tile info for layer
175
+ * @param {Vector2} [scale=(1,1)] - How much to scale this layer when rendered
176
+ * @param {Number} [renderOrder] - Objects are sorted by renderOrder
177
177
  */
178
178
  constructor(position, size=tileCollisionSize, tileInfo=tile(), scale=vec2(1), renderOrder=0)
179
179
  {
@@ -234,16 +234,18 @@ class TileLayer extends EngineObject
234
234
  }
235
235
 
236
236
  /** Draw all the tile data to an offscreen canvas
237
- * - This may be slow in some browsers
238
- */
237
+ * - This may be slow in some browsers but only needs to be done once */
239
238
  redraw()
240
239
  {
241
240
  this.redrawStart(true);
242
- this.drawAllTileData();
241
+ for (let x = this.size.x; x--;)
242
+ for (let y = this.size.y; y--;)
243
+ this.drawTileData(vec2(x,y), false);
243
244
  this.redrawEnd();
244
245
  }
245
246
 
246
247
  /** Call to start the redraw process
248
+ * - This can be used to manually update small parts of the level
247
249
  * @param {Boolean} [clear] - Should it clear the canvas before drawing */
248
250
  redrawStart(clear=false)
249
251
  {
@@ -251,17 +253,19 @@ class TileLayer extends EngineObject
251
253
  /** @type {[HTMLCanvasElement, CanvasRenderingContext2D, Vector2, Vector2, number]} */
252
254
  this.savedRenderSettings = [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale];
253
255
 
254
- // hack: use normal rendering system to render the tiles
256
+ // use webgl rendering system to render the tiles if enabled
257
+ // this works by temporally taking control of the rendering system
255
258
  mainCanvas = this.canvas;
256
259
  mainContext = this.context;
260
+ mainCanvasSize = this.size.multiply(this.tileInfo.size);
257
261
  cameraPos = this.size.scale(.5);
258
262
  cameraScale = this.tileInfo.size.x;
259
263
 
260
264
  if (clear)
261
265
  {
262
266
  // clear and set size
263
- mainCanvas.width = this.size.x * this.tileInfo.size.x;
264
- mainCanvas.height = this.size.y * this.tileInfo.size.y;
267
+ mainCanvas.width = mainCanvasSize.x;
268
+ mainCanvas.height = mainCanvasSize.y;
265
269
  }
266
270
 
267
271
  // begin a new render for the tile canvas
@@ -279,32 +283,33 @@ class TileLayer extends EngineObject
279
283
  [mainCanvas, mainContext, mainCanvasSize, cameraPos, cameraScale] = this.savedRenderSettings;
280
284
  }
281
285
 
282
- /** Draw the tile at a given position
283
- * @param {Vector2} layerPos */
284
- drawTileData(layerPos)
286
+ /** Draw the tile at a given position in the tile grid
287
+ * This can be used to clear out tiles when they are destroyed
288
+ * Tiles can also be redrawn if isinde a redrawStart/End block
289
+ * @param {Vector2} layerPos
290
+ * @param {Boolean} [clear] - should the old tile be cleared out
291
+ */
292
+ drawTileData(layerPos, clear=true)
285
293
  {
286
- // first clear out where the tile was
287
- const pos = layerPos.floor().add(this.pos).add(vec2(.5));
288
- this.drawCanvas2D(pos, vec2(1), 0, false, (context)=>context.clearRect(-.5, -.5, 1, 1));
294
+ // clear out where the tile was, for full opaque tiles this can be skipped
295
+ const s = this.tileInfo.size;
296
+ if (clear)
297
+ {
298
+ const pos = layerPos.multiply(s);
299
+ this.context.clearRect(pos.x, this.canvas.height-pos.y, s.x, -s.y);
300
+ }
289
301
 
290
302
  // draw the tile if not undefined
291
303
  const d = this.getData(layerPos);
292
304
  if (d.tile != undefined)
293
305
  {
306
+ const pos = this.pos.add(layerPos).add(vec2(.5));
294
307
  ASSERT(mainContext == this.context, 'must call redrawStart() before drawing tiles');
295
- const tileInfo = tile(d.tile, this.tileInfo.size, this.tileInfo.textureIndex);
308
+ const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex);
296
309
  drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
297
310
  }
298
311
  }
299
312
 
300
- /** Draw all the tiles in this layer */
301
- drawAllTileData()
302
- {
303
- for (let x = this.size.x; x--;)
304
- for (let y = this.size.y; y--;)
305
- this.drawTileData(vec2(x,y));
306
- }
307
-
308
313
  /** Draw directly to the 2D canvas in world space (bipass webgl)
309
314
  * @param {Vector2} pos
310
315
  * @param {Vector2} size
@@ -324,11 +329,11 @@ class TileLayer extends EngineObject
324
329
  context.restore();
325
330
  }
326
331
 
327
- /** Draw a tile directly onto the layer canvas
332
+ /** Draw a tile directly onto the layer canvas in world space
328
333
  * @param {Vector2} pos
329
- * @param {Vector2} [size=Vector2(1,1)]
334
+ * @param {Vector2} [size=(1,1)]
330
335
  * @param {TileInfo} [tileInfo]
331
- * @param {Color} [color=Color()]
336
+ * @param {Color} [color=(1,1,1,1)]
332
337
  * @param {Number} [angle=0]
333
338
  * @param {Boolean} [mirror=0] */
334
339
  drawTile(pos, size=vec2(1), tileInfo, color=new Color, angle, mirror)
@@ -353,10 +358,10 @@ class TileLayer extends EngineObject
353
358
  });
354
359
  }
355
360
 
356
- /** Draw a rectangle directly onto the layer canvas
361
+ /** Draw a rectangle directly onto the layer canvas in world space
357
362
  * @param {Vector2} pos
358
- * @param {Vector2} [size=Vector2(1,1)]
359
- * @param {Color} [color=Color()]
363
+ * @param {Vector2} [size=(1,1)]
364
+ * @param {Color} [color=(1,1,1,1)]
360
365
  * @param {Number} [angle=0] */
361
366
  drawRect(pos, size, color, angle)
362
367
  { this.drawTile(pos, size, undefined, color, angle); }
@@ -121,11 +121,11 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
121
121
  function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
122
122
 
123
123
  /** Returns true if two axis aligned bounding boxes are overlapping
124
- * @param {Vector2} pointA - Center of box A
125
- * @param {Vector2} sizeA - Size of box A
126
- * @param {Vector2} pointB - Center of box B
127
- * @param {Vector2} sizeB - Size of box B
128
- * @return {Boolean} - True if overlapping
124
+ * @param {Vector2} pointA - Center of box A
125
+ * @param {Vector2} sizeA - Size of box A
126
+ * @param {Vector2} pointB - Center of box B
127
+ * @param {Vector2} sizeB - Size of box B
128
+ * @return {Boolean} - True if overlapping
129
129
  * @memberof Utilities */
130
130
  function isOverlapping(pointA, sizeA, pointB, sizeB)
131
131
  {
@@ -248,6 +248,8 @@ function glCopyToContext(context, forceDraw=false)
248
248
  * @memberof WebGL */
249
249
  function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdditive=0)
250
250
  {
251
+ ASSERT(typeof rgba == 'number' && typeof rgbaAdditive == 'number', 'invalid color');
252
+
251
253
  // flush if there is not enough room or if different blend mode
252
254
  if (glInstanceCount >= gl_MAX_INSTANCES-1 || glBatchAdditive != glAdditive)
253
255
  glFlush();
@@ -276,7 +278,7 @@ let glPostShader, glPostArrayBuffer, glPostTexture, glPostIncludeOverlay;
276
278
  * @param {String} shaderCode
277
279
  * @param {Boolean} includeOverlay
278
280
  * @memberof WebGL */
279
- function glInitPostProcess(shaderCode, includeOverlay)
281
+ function glInitPostProcess(shaderCode, includeOverlay=false)
280
282
  {
281
283
  ASSERT(!glPostShader, 'can only have 1 post effects shader');
282
284
 
@@ -312,6 +314,8 @@ function glInitPostProcess(shaderCode, includeOverlay)
312
314
 
313
315
  // hide the original 2d canvas
314
316
  mainCanvas.style.visibility = 'hidden';
317
+ if (glPostIncludeOverlay)
318
+ overlayCanvas.style.visibility = 'hidden';
315
319
  }
316
320
 
317
321
  // Render the post processing shader, called automatically by the engine
@@ -332,14 +336,8 @@ function glRenderPostProcess()
332
336
  glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
333
337
  }
334
338
 
335
- if (glPostIncludeOverlay)
336
- {
337
- // copy overlay canvas so it will be included in post processing
338
- mainContext.drawImage(overlayCanvas, 0, 0);
339
-
340
- // clear overlay canvas
341
- overlayCanvas.width = mainCanvas.width;
342
- }
339
+ // copy overlay canvas so it will be included in post processing
340
+ glPostIncludeOverlay && mainContext.drawImage(overlayCanvas, 0, 0);
343
341
 
344
342
  // setup shader program to draw one triangle
345
343
  glContext.useProgram(glPostShader);