littlejsengine 1.6.6 → 1.7.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.
Files changed (59) hide show
  1. package/README.md +76 -53
  2. package/build/littlejs.d.ts +154 -136
  3. package/build/littlejs.esm.js +461 -305
  4. package/build/littlejs.esm.min.js +1 -1
  5. package/build/littlejs.js +452 -291
  6. package/build/littlejs.min.js +1 -1
  7. package/build/littlejs.release.js +2317 -2168
  8. package/examples/breakout/game.js +5 -1
  9. package/examples/breakout/index.html +5 -5
  10. package/examples/breakoutTutorial/README.md +6 -6
  11. package/examples/breakoutTutorial/game.js +3 -0
  12. package/examples/breakoutTutorial/index.html +3 -3
  13. package/examples/electron/build.js +105 -0
  14. package/examples/electron/game.js +4 -2
  15. package/examples/electron/index.html +13 -2
  16. package/examples/electron/package.json +5 -3
  17. package/examples/empty/game.js +3 -1
  18. package/examples/empty/index.html +1 -1
  19. package/examples/js13k/build.bat +2 -0
  20. package/examples/js13k/build.js +110 -0
  21. package/examples/js13k/game.js +109 -0
  22. package/examples/js13k/index.html +18 -0
  23. package/examples/js13k/tiles.png +0 -0
  24. package/examples/module/game.js +9 -3
  25. package/examples/module/index.html +2 -2
  26. package/examples/particles/index.html +7 -13
  27. package/examples/platformer/game.js +5 -2
  28. package/examples/platformer/gameEffects.js +12 -12
  29. package/examples/platformer/gamePlayer.js +2 -2
  30. package/examples/platformer/index.html +8 -8
  31. package/examples/puzzle/game.js +5 -3
  32. package/examples/puzzle/index.html +4 -4
  33. package/examples/starter/build.bat +2 -78
  34. package/examples/starter/build.js +109 -0
  35. package/examples/starter/game.js +4 -1
  36. package/examples/starter/index.html +15 -18
  37. package/examples/stress/index.html +5 -7
  38. package/examples/typescript/build.bat +2 -14
  39. package/examples/typescript/build.js +31 -0
  40. package/examples/typescript/game.js +94 -89
  41. package/examples/typescript/game.ts +9 -3
  42. package/examples/typescript/index.html +2 -2
  43. package/package.json +2 -2
  44. package/src/engine.js +3 -3
  45. package/src/engineAudio.js +44 -16
  46. package/src/engineBuild.bat +2 -132
  47. package/src/engineBuild.js +156 -0
  48. package/src/engineDebug.js +25 -15
  49. package/src/engineDraw.js +62 -53
  50. package/src/engineExport.js +7 -12
  51. package/src/engineInput.js +27 -35
  52. package/src/engineObject.js +15 -13
  53. package/src/engineParticles.js +6 -6
  54. package/src/engineRelease.js +1 -3
  55. package/src/engineSettings.js +1 -0
  56. package/src/engineTileLayer.js +31 -18
  57. package/src/engineUtilities.js +161 -93
  58. package/src/engineWebGL.js +63 -27
  59. package/examples/electron/build.bat +0 -52
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LittleJS Build System
5
+ * - Combine input files
6
+ * - Run custom build steps
7
+ * - Check for errors
8
+ * - Output to build folder
9
+ * @namespace Build
10
+ */
11
+
12
+ const ENGINE_NAME = 'littlejs';
13
+ const BUILD_FOLDER = 'build';
14
+ const SOURCE_FOLDER = 'src';
15
+ const engineSourceFiles =
16
+ [
17
+ `${SOURCE_FOLDER}/engineUtilities.js`,
18
+ `${SOURCE_FOLDER}/engineSettings.js`,
19
+ `${SOURCE_FOLDER}/engineObject.js`,
20
+ `${SOURCE_FOLDER}/engineDraw.js`,
21
+ `${SOURCE_FOLDER}/engineInput.js`,
22
+ `${SOURCE_FOLDER}/engineAudio.js`,
23
+ `${SOURCE_FOLDER}/engineTileLayer.js`,
24
+ `${SOURCE_FOLDER}/engineParticles.js`,
25
+ `${SOURCE_FOLDER}/engineMedals.js`,
26
+ `${SOURCE_FOLDER}/engineWebGL.js`,
27
+ `${SOURCE_FOLDER}/engine.js`,
28
+ ];
29
+ const asciiArt =`
30
+ ~~~~°°°°ooo°oOo°ooOooOooOo.
31
+ __________ ________ ____ '°OoO.
32
+ |LittleJS| |Engine| |[]|_._._Y
33
+ .|________|_._|______|_._|__|_|_|_|}
34
+ OOO OOO OO OO OO=OO---oo\\
35
+ `;
36
+ const license = '// LittleJS - MIT License - Copyright 2021 Frank Force\n'
37
+
38
+ console.log(asciiArt);
39
+ console.log('Choo Choo... Building LittleJS Engine!\n');
40
+ const startTime = Date.now();
41
+ const fs = require('node:fs');
42
+ const child_process = require('node:child_process');
43
+
44
+ try
45
+ {
46
+ // Setup build folder
47
+ fs.rmSync(BUILD_FOLDER, { recursive: true, force: true });
48
+ fs.mkdirSync(BUILD_FOLDER);
49
+ }
50
+ catch (e) { handleError(e, 'Failed to create build folder!'); }
51
+
52
+ Build
53
+ (
54
+ 'Build Engine -- all',
55
+ `${BUILD_FOLDER}/${ENGINE_NAME}.js`,
56
+ [`${SOURCE_FOLDER}/engineDebug.js`, ...engineSourceFiles],
57
+ [], license
58
+ );
59
+
60
+ Build
61
+ (
62
+ 'Build Engine -- release',
63
+ `${BUILD_FOLDER}/${ENGINE_NAME}.release.js`,
64
+ [`${SOURCE_FOLDER}/engineRelease.js`, ...engineSourceFiles],
65
+ [], license
66
+ );
67
+
68
+ Build
69
+ (
70
+ 'Build Engine -- minified',
71
+ `${BUILD_FOLDER}/${ENGINE_NAME}.min.js`,
72
+ [`${BUILD_FOLDER}/${ENGINE_NAME}.release.js`],
73
+ [closureCompilerStep, uglifyBuildStep]
74
+ );
75
+
76
+ Build
77
+ (
78
+ 'Build Engine -- ESM',
79
+ `${BUILD_FOLDER}/${ENGINE_NAME}.esm.js`,
80
+ [`${BUILD_FOLDER}/${ENGINE_NAME}.js`, `${SOURCE_FOLDER}/engineExport.js`],
81
+ [typeScriptBuildStep]
82
+ );
83
+
84
+ Build
85
+ (
86
+ 'Build Engine -- ESM minified release',
87
+ `${BUILD_FOLDER}/${ENGINE_NAME}.esm.min.js`,
88
+ [`${BUILD_FOLDER}/${ENGINE_NAME}.min.js`, `${SOURCE_FOLDER}/engineExport.js`],
89
+ [uglifyBuildStep]
90
+ );
91
+
92
+ console.log(`Engine built in ${((Date.now() - startTime)/1e3).toFixed(2)} seconds!`);
93
+
94
+ ///////////////////////////////////////////////////////////////////////////////
95
+
96
+ // A single build with its own source files, build steps, and output file
97
+ // - each build step is a callback that accepts a single filename
98
+ function Build(message, outputFile, files=[], buildSteps=[], topOfFileText)
99
+ {
100
+ console.log(message);
101
+
102
+ // copy files into a buffer
103
+ let buffer = '';
104
+ if (topOfFileText)
105
+ buffer += topOfFileText + '\n';
106
+ for (const file of files)
107
+ buffer += fs.readFileSync(file) + '\n';
108
+
109
+ // output file
110
+ fs.writeFileSync(outputFile, buffer, {flag: 'w+'});
111
+
112
+ // execute build steps in order
113
+ for (const buildStep of buildSteps)
114
+ buildStep(outputFile);
115
+ }
116
+
117
+ // Process with Closure Compiler to minify and check for errors
118
+ function closureCompilerStep(filename)
119
+ {
120
+ const filenameTemp = filename + '.tmp';
121
+ fs.copyFileSync(filename, filenameTemp);
122
+ try
123
+ {
124
+ child_process.execSync(`npx google-closure-compiler --js=${filenameTemp} --js_output_file=${filename} --language_out=ECMASCRIPT_2021 --warning_level=VERBOSE --jscomp_off=*`);
125
+ fs.rmSync(filenameTemp);
126
+ }
127
+ catch (e) { handleError(e, 'Failed to run Closure Compiler step!'); }
128
+ };
129
+
130
+ // Process with Uglify to minify
131
+ function uglifyBuildStep(filename)
132
+ {
133
+ try
134
+ {
135
+ child_process.execSync(`npx uglifyjs ${filename} -o ${filename}`);
136
+ }
137
+ catch (e) { handleError(e,'Failed to run Uglify minification step!'); }
138
+ };
139
+
140
+ // Build TypeScript definitions
141
+ function typeScriptBuildStep(filename)
142
+ {
143
+ try
144
+ {
145
+ child_process.execSync(`npx tsc ${filename} --declaration --allowJs --emitDeclarationOnly --outFile ${BUILD_FOLDER}/${ENGINE_NAME}.d.ts`);
146
+ }
147
+ catch (e) { handleError(e, 'Failed to run TypeScript build step!'); }
148
+ };
149
+
150
+ // display the error and exit
151
+ function handleError(e,message)
152
+ {
153
+ console.error(e);
154
+ console.error(message);
155
+ process.exit(1);
156
+ }
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * LittleJS Debug System
3
- * - Press ~ to show debug overlay with mouse pick
3
+ * - Press Esc to show debug overlay with mouse pick
4
4
  * - Number keys toggle debug functions
5
5
  * - +/- apply time scale
6
6
  * - Debug primitive rendering
7
- * - Save a 2d canvas as an image
7
+ * - Save a 2d canvas as a png image
8
8
  * @namespace Debug
9
9
  */
10
10
 
@@ -34,12 +34,6 @@ const debugPointSize = .5;
34
34
  * @memberof Debug */
35
35
  let showWatermark = 1;
36
36
 
37
- /** True if god mode is enabled, handle this however you want
38
- * @type {Boolean}
39
- * @default
40
- * @memberof Debug */
41
- let godMode = 0;
42
-
43
37
  /** Key code used to toggle debug mode, Esc by default
44
38
  * @type {Boolean}
45
39
  * @default
@@ -144,11 +138,27 @@ function debugClear() { debugPrimitives = []; }
144
138
  /** Save a canvas to disk
145
139
  * @param {HTMLCanvasElement} canvas
146
140
  * @param {String} [filename]
141
+ * @param {String} [type='image/png']
142
+ * @memberof Debug */
143
+ function debugSaveCanvas(canvas, filename=engineName, type='image/png')
144
+ { debugSaveDataURL(canvas.toDataURL(type), filename); }
145
+
146
+ /** Save a text file to disk
147
+ * @param {String} text
148
+ * @param {String} [filename]
149
+ * @param {String} [type='text/plain']
150
+ * @memberof Debug */
151
+ function debugSaveText(text, filename=engineName, type='text/plain')
152
+ { debugSaveDataURL(URL.createObjectURL(new Blob([text], {'type':type})), filename); }
153
+
154
+ /** Save a data url to disk
155
+ * @param {String} dataURL
156
+ * @param {String} filename
147
157
  * @memberof Debug */
148
- function debugSaveCanvas(canvas, filename = engineName + '.png')
158
+ function debugSaveDataURL(dataURL, filename)
149
159
  {
150
- downloadLink.download = 'screenshot.png';
151
- downloadLink.href = canvas.toDataURL('image/png').replace('image/png','image/octet-stream');
160
+ downloadLink.download = filename;
161
+ downloadLink.href = dataURL;
152
162
  downloadLink.click();
153
163
  }
154
164
 
@@ -180,7 +190,7 @@ function debugUpdate()
180
190
  if (keyWasPressed(51)) // 3
181
191
  debugGamepads = !debugGamepads;
182
192
  if (keyWasPressed(52)) // 4
183
- godMode = !godMode;
193
+ debugRaycast = !debugRaycast;
184
194
  if (keyWasPressed(53)) // 5
185
195
  debugTakeScreenshot = 1;
186
196
  //if (keyWasPressed(54)) // 6
@@ -359,8 +369,8 @@ function debugRender()
359
369
  overlayContext.fillText('2: Debug Particles', x, y += h);
360
370
  overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
361
371
  overlayContext.fillText('3: Debug Gamepads', x, y += h);
362
- overlayContext.fillStyle = godMode ? '#f00' : '#fff';
363
- overlayContext.fillText('4: God Mode', x, y += h);
372
+ overlayContext.fillStyle = debugRaycast ? '#f00' : '#fff';
373
+ overlayContext.fillText('4: Debug Raycasts', x, y += h);
364
374
  overlayContext.fillStyle = '#fff';
365
375
  overlayContext.fillText('5: Save Screenshot', x, y += h);
366
376
 
@@ -385,7 +395,7 @@ function debugRender()
385
395
  {
386
396
  overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
387
397
  overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
388
- overlayContext.fillText(godMode ? 'God Mode' : '', x, y += h);
398
+ overlayContext.fillText(debugRaycast ? 'Debug Raycasts' : '', x, y += h);
389
399
  overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
390
400
  }
391
401
 
package/src/engineDraw.js CHANGED
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * LittleJS Drawing System
3
- * - Hybrid with both Canvas2D and WebGL available
3
+ * - Hybrid system with both Canvas2D and WebGL available
4
4
  * - Super fast tile sheet rendering with WebGL
5
5
  * - Can apply rotation, mirror, color and additive color
6
+ * - Font rendering system with built in engine font
6
7
  * - Many useful utility functions
7
8
  *
8
9
  * LittleJS uses a hybrid rendering solution with the best of both Canvas2D and WebGL.
@@ -12,7 +13,6 @@
12
13
  * overlayCanvas - Another 2D canvas that appears on top of the other 2 canvases.
13
14
  *
14
15
  * The WebGL rendering system is very fast with some caveats...
15
- * - The default setup supports only 1 tile sheet, to support more call glCreateTexture and glSetTexture
16
16
  * - Switching blend modes (additive) or textures causes another draw call which is expensive in excess
17
17
  * - Group additive rendering together using renderOrder to mitigate this issue
18
18
  *
@@ -56,25 +56,29 @@ const tileImage = new Image;
56
56
  let tileImageSize, tileImageFixBleed, drawCount;
57
57
 
58
58
  /** Convert from screen to world space coordinates
59
- * - if calling outside of render, you may need to manually set mainCanvasSize
60
59
  * @param {Vector2} screenPos
61
60
  * @return {Vector2}
62
61
  * @memberof Draw */
63
62
  function screenToWorld(screenPos)
64
63
  {
65
- ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
66
- return screenPos.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos);
64
+ return new Vector2
65
+ (
66
+ (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale + cameraPos.x,
67
+ (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale + cameraPos.y
68
+ );
67
69
  }
68
70
 
69
71
  /** Convert from world to screen space coordinates
70
- * - if calling outside of render, you may need to manually set mainCanvasSize
71
72
  * @param {Vector2} worldPos
72
73
  * @return {Vector2}
73
74
  * @memberof Draw */
74
75
  function worldToScreen(worldPos)
75
76
  {
76
- ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
77
- return worldPos.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5));
77
+ return new Vector2
78
+ (
79
+ (worldPos.x - cameraPos.x) * cameraScale + mainCanvasSize.x/2 - .5,
80
+ (worldPos.y - cameraPos.y) * -cameraScale + mainCanvasSize.y/2 - .5
81
+ );
78
82
  }
79
83
 
80
84
  /** Draw textured tile centered in world space, with color applied if using WebGL
@@ -87,13 +91,21 @@ function worldToScreen(worldPos)
87
91
  * @param {Boolean} [mirror=0] - If true image is flipped along the Y axis
88
92
  * @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
89
93
  * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
94
+ * @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
90
95
  * @memberof Draw */
91
- function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color, angle=0, mirror,
92
- additiveColor=new Color(0,0,0,0), useWebGL=glEnable)
96
+ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color,
97
+ angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
93
98
  {
94
99
  showWatermark && ++drawCount;
100
+
95
101
  if (glEnable && useWebGL)
96
102
  {
103
+ if (screenSpace)
104
+ {
105
+ // convert to world space
106
+ pos = screenToWorld(pos);
107
+ size = size.scale(1/cameraScale);
108
+ }
97
109
  if (tileIndex < 0 || !tileImage.width)
98
110
  {
99
111
  // if negative tile index or image not found, force untextured
@@ -135,7 +147,7 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
135
147
  context.globalAlpha = color.a; // only alpha is supported
136
148
  context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
137
149
  }
138
- });
150
+ }, undefined, screenSpace);
139
151
  }
140
152
  }
141
153
 
@@ -145,38 +157,30 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
145
157
  * @param {Color} [color=Color()]
146
158
  * @param {Number} [angle=0]
147
159
  * @param {Boolean} [useWebGL=glEnable]
160
+ * @param {Boolean} [screenSpace=0]
148
161
  * @memberof Draw */
149
- function drawRect(pos, size, color, angle, useWebGL)
150
- {
151
- drawTile(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
152
- }
162
+ function drawRect(pos, size, color, angle, useWebGL, screenSpace)
163
+ { drawTile(pos, size, -1, tileSizeDefault, color, angle, 0, undefined, useWebGL, screenSpace); }
153
164
 
154
- /** Draw textured tile centered on pos in screen space
155
- * @param {Vector2} pos - Center of the tile
156
- * @param {Vector2} [size=Vector2(1,1)] - Size of the tile
157
- * @param {Number} [tileIndex=-1] - Tile index to use, negative is untextured
158
- * @param {Vector2} [tileSize=tileSizeDefault] - Tile size in source pixels
165
+ /** Draw colored polygon using passed in points
166
+ * @param {Array} points - Array of Vector2 points
159
167
  * @param {Color} [color=Color()]
160
- * @param {Number} [angle=0]
161
- * @param {Boolean} [mirror=0]
162
- * @param {Color} [additiveColor=Color(0,0,0,0)]
163
168
  * @param {Boolean} [useWebGL=glEnable]
169
+ * @param {Boolean} [screenSpace=0]
164
170
  * @memberof Draw */
165
- function drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angle, mirror, additiveColor, useWebGL)
171
+ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
166
172
  {
167
- drawTile(screenToWorld(pos), size.scale(1/cameraScale), tileIndex, tileSize, color, angle, mirror, additiveColor, useWebGL);
168
- }
169
-
170
- /** Draw colored rectangle in screen space
171
- * @param {Vector2} pos
172
- * @param {Vector2} [size=Vector2(1,1)]
173
- * @param {Color} [color=Color()]
174
- * @param {Number} [angle=0]
175
- * @param {Boolean} [useWebGL=glEnable]
176
- * @memberof Draw */
177
- function drawRectScreenSpace(pos, size, color, angle, useWebGL)
178
- {
179
- drawTileScreenSpace(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
173
+ if (useWebGL)
174
+ glDrawPoints(screenSpace ? points.map(screenToWorld) : points, color.rgbaInt());
175
+ else
176
+ {
177
+ // draw using canvas
178
+ mainContext.fillStyle = color;
179
+ mainContext.beginPath();
180
+ for (const point of screenSpace ? points : points.map(worldToScreen))
181
+ mainContext.lineTo(point.x, point.y);
182
+ mainContext.fill();
183
+ }
180
184
  }
181
185
 
182
186
  /** Draw colored line between two points
@@ -185,12 +189,13 @@ function drawRectScreenSpace(pos, size, color, angle, useWebGL)
185
189
  * @param {Number} [thickness=.1]
186
190
  * @param {Color} [color=Color()]
187
191
  * @param {Boolean} [useWebGL=glEnable]
192
+ * @param {Boolean} [screenSpace=0]
188
193
  * @memberof Draw */
189
194
  function drawLine(posA, posB, thickness=.1, color, useWebGL)
190
195
  {
191
196
  const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
192
197
  const size = vec2(thickness, halfDelta.length()*2);
193
- drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL);
198
+ drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
194
199
  }
195
200
 
196
201
  /** Draw directly to a 2d canvas context in world space
@@ -200,12 +205,16 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL)
200
205
  * @param {Boolean} mirror
201
206
  * @param {Function} drawFunction
202
207
  * @param {CanvasRenderingContext2D} [context=mainContext]
208
+ * @param {Boolean} [screenSpace=0]
203
209
  * @memberof Draw */
204
- function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainContext)
210
+ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainContext, screenSpace)
205
211
  {
206
- // create canvas transform from world space to screen space
207
- pos = worldToScreen(pos);
208
- size = size.scale(cameraScale);
212
+ if (!screenSpace)
213
+ {
214
+ // create canvas transform from world space to screen space
215
+ pos = worldToScreen(pos);
216
+ size = size.scale(cameraScale);
217
+ }
209
218
  context.save();
210
219
  context.translate(pos.x+.5|0, pos.y+.5|0);
211
220
  context.rotate(angle);
@@ -312,6 +321,17 @@ class FontImage
312
321
  this.context = context;
313
322
  }
314
323
 
324
+ /** Draw text in world space using the image font
325
+ * @param {String} text
326
+ * @param {Vector2} pos
327
+ * @param {Number} [scale=.25]
328
+ * @param {Boolean} [center]
329
+ */
330
+ drawText(text, pos, scale=1, center)
331
+ {
332
+ this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center);
333
+ }
334
+
315
335
  /** Draw text in screen space using the image font
316
336
  * @param {String} text
317
337
  * @param {Vector2} pos
@@ -349,17 +369,6 @@ class FontImage
349
369
 
350
370
  context.restore();
351
371
  }
352
-
353
- /** Draw text in world space using the image font
354
- * @param {String} text
355
- * @param {Vector2} pos
356
- * @param {Number} [scale=.25]
357
- * @param {Boolean} [center]
358
- */
359
- drawText(text, pos, scale=1, center)
360
- {
361
- this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center);
362
- }
363
372
  }
364
373
 
365
374
  ///////////////////////////////////////////////////////////////////////////////
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * LittleJS Module Export
3
- * - Export engine as a module with extra functions where necessary
3
+ * - Export engine as a module with functions where necessary
4
4
  */
5
5
 
6
6
  /** Set position of camera in world space
@@ -181,18 +181,13 @@ function setMedalDisplayIconSize(size) { medalDisplayIconSize = size; }
181
181
  /** Set to stop medals from being unlockable
182
182
  * @param {Boolean} preventUnlock
183
183
  * @memberof Settings */
184
- function setMedalsPreventUnlock(prevent) { medalsPreventUnlock = prevent; }
184
+ function setMedalsPreventUnlock(preventUnlock) { medalsPreventUnlock = preventUnlock; }
185
185
 
186
186
  /** Set if watermark with FPS should be shown
187
187
  * @param {Boolean} show
188
188
  * @memberof Debug */
189
189
  function setShowWatermark(show) { showWatermark = show; }
190
190
 
191
- /** Set if god mode is enabled
192
- * @param {Boolean} enable
193
- * @memberof Debug */
194
- function setGodMode(enable) { godMode = enable; }
195
-
196
191
  /** Set key code used to toggle debug mode, Esc by default
197
192
  * @param {Number} key
198
193
  * @memberof Debug */
@@ -237,7 +232,6 @@ export {
237
232
  setMedalDisplayIconSize,
238
233
  setMedalsPreventUnlock,
239
234
  setShowWatermark,
240
- setGodMode,
241
235
  setDebugKey,
242
236
 
243
237
  // Settings
@@ -280,7 +274,6 @@ export {
280
274
  // Globals
281
275
  debug,
282
276
  showWatermark,
283
- godMode,
284
277
 
285
278
  // Debug
286
279
  ASSERT,
@@ -302,6 +295,10 @@ export {
302
295
  mod,
303
296
  clamp,
304
297
  percent,
298
+ distanceWrap,
299
+ lerpWrap,
300
+ distanceAngle,
301
+ lerpAngle,
305
302
  lerp,
306
303
  smoothStep,
307
304
  nearestPowerOfTwo,
@@ -316,11 +313,9 @@ export {
316
313
  randInCircle,
317
314
  randVector,
318
315
  randColor,
319
- randSeed,
320
- setRandSeed,
321
- randSeeded,
322
316
 
323
317
  // Utility Classes
318
+ RandomGenerator,
324
319
  Vector2,
325
320
  Color,
326
321
  Timer,
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * LittleJS Input System
3
- * - Tracks key down, pressed, and released
4
- * - Also tracks mouse buttons, position, and wheel
5
- * - Supports multiple gamepads
6
- * - Virtual gamepad for touch devices with touchGamepadSize
3
+ * - Tracks keyboard down, pressed, and released
4
+ * - Tracks mouse buttons, position, and wheel
5
+ * - Tracks multiple analog gamepads
6
+ * - Virtual gamepad for touch devices
7
7
  * @namespace Input
8
8
  */
9
9
 
@@ -275,40 +275,32 @@ if (isTouchDevice)
275
275
  let wasTouching, mouseDown = onmousedown, mouseUp = onmouseup;
276
276
  onmousedown = onmouseup = ()=> 0;
277
277
 
278
- // setup touch input
279
- ontouchstart = (e)=>
278
+ // handle all touch events the same way
279
+ ontouchstart = ontouchmove = ontouchend = (e)=>
280
280
  {
281
- // fix mobile audio, force it to play a sound on first touch
282
- zzfx(0);
281
+ e.button = 0; // all touches are left click
283
282
 
284
- // handle all touch events the same way
285
- ontouchstart = ontouchmove = ontouchend = (e)=>
286
- {
287
- e.button = 0; // all touches are left click
288
-
289
- // check if touching and pass to mouse events
290
- const touching = e.touches.length;
291
- if (touching)
292
- {
293
- // set event pos and pass it along
294
- e.x = e.touches[0].clientX;
295
- e.y = e.touches[0].clientY;
296
- wasTouching ? onmousemove(e) : mouseDown(e);
297
- }
298
- else if (wasTouching)
299
- mouseUp(e);
300
-
301
- // set was touching
302
- wasTouching = touching;
283
+ // fix stalled audio on mobile
284
+ if (soundEnable)
285
+ audioContext ? audioContext.resume() : zzfx(0);
303
286
 
304
- // must return true so the document will get focus
305
- return true;
287
+ // check if touching and pass to mouse events
288
+ const touching = e.touches.length;
289
+ if (touching)
290
+ {
291
+ // set event pos and pass it along
292
+ e.x = e.touches[0].clientX;
293
+ e.y = e.touches[0].clientY;
294
+ wasTouching ? onmousemove(e) : mouseDown(e);
306
295
  }
296
+ else if (wasTouching)
297
+ mouseUp(e);
307
298
 
308
- // try to create touch game pad
309
- touchGamepadEnable && touchGamepadCreate();
299
+ // set was touching
300
+ wasTouching = touching;
310
301
 
311
- return ontouchstart(e);
302
+ // must return true so the document will get focus
303
+ return true;
312
304
  }
313
305
  }
314
306
 
@@ -319,13 +311,13 @@ if (isTouchDevice)
319
311
  let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
320
312
 
321
313
  // create the touch gamepad, called automatically by the engine
322
- function touchGamepadCreate()
314
+ if (touchGamepadEnable)
323
315
  {
324
316
  // touch input internal variables
325
317
  touchGamepadButtons = [];
326
318
  touchGamepadStick = vec2();
327
319
 
328
- let touchHandler = ontouchstart;
320
+ const touchHandler = ontouchstart;
329
321
  ontouchstart = ontouchmove = ontouchend = (e)=>
330
322
  {
331
323
  // clear touch gamepad input
@@ -431,7 +423,7 @@ function touchGamepadRender()
431
423
  const rightCenter = vec2(mainCanvasSize.x-touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
432
424
  for (let i=4; i--;)
433
425
  {
434
- const pos = rightCenter.add((new Vector2).setAngle(i*PI/2, touchGamepadSize/2));
426
+ const pos = rightCenter.add(vec2().setAngle(i*PI/2, touchGamepadSize/2));
435
427
  overlayContext.fillStyle = touchGamepadButtons[i] ? '#fff' : '#000';
436
428
  overlayContext.beginPath();
437
429
  overlayContext.arc(pos.x, pos.y, touchGamepadSize/4, 0,9);