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.
- package/README.md +15 -11
- package/copyToGithub.bat +28 -0
- package/dist/littlejs.d.ts +430 -304
- package/dist/littlejs.esm.js +1745 -982
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1716 -965
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1673 -922
- package/examples/box2d/game.js +2 -2
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/box2d/scenes.js +1 -1
- package/examples/breakout/game.js +30 -25
- package/examples/breakoutTutorial/README.md +44 -41
- package/examples/breakoutTutorial/game.js +2 -2
- package/examples/electron/build.bat +7 -0
- package/examples/electron/build.js +124 -0
- package/examples/electron/electron.js +35 -0
- package/examples/electron/game.js +140 -0
- package/examples/electron/index.html +13 -0
- package/examples/electron/package.json +12 -0
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/game.js +1 -0
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +332 -160
- package/examples/module/game.js +5 -2
- package/examples/particles/index.html +12 -3
- package/examples/platformer/gameEffects.js +20 -19
- package/examples/platformer/gameLevel.js +6 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/blending.js +9 -5
- package/examples/shorts/box2d.js +1 -1
- package/examples/shorts/box2dCar.js +1 -1
- package/examples/shorts/clock.js +1 -1
- package/examples/shorts/colors.js +2 -2
- package/examples/shorts/flappyGame.js +2 -1
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/maze.js +1 -1
- package/examples/shorts/music.js +106 -0
- package/examples/shorts/nineSlice.js +9 -9
- package/examples/shorts/parallax.js +71 -0
- package/examples/shorts/piano.js +9 -10
- package/examples/shorts/postProcess.js +25 -8
- package/examples/shorts/raycasting.js +2 -2
- package/examples/shorts/shapes.js +7 -15
- package/examples/shorts/slidingPuzzle.js +2 -2
- package/examples/shorts/song.mp3 +0 -0
- package/examples/shorts/starfield.js +5 -7
- package/examples/shorts/systemFont.js +1 -1
- package/examples/shorts/uiSystem.js +16 -8
- package/examples/starter/build.js +9 -8
- package/examples/starter/game.js +5 -2
- package/examples/starter/index.html +2 -2
- package/examples/stress/index.html +13 -8
- package/examples/style.css +19 -6
- package/examples/typescript/build.js +1 -1
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/game.ts +5 -2
- package/examples/uiSystem/game.js +13 -12
- package/package.json +2 -2
- package/plugins/box2d.js +24 -97
- package/plugins/drawUtilities.js +29 -23
- package/plugins/newgrounds.js +6 -6
- package/plugins/pluginExport.js +1 -1
- package/plugins/postProcess.js +7 -0
- package/plugins/uiSystem.js +106 -82
- package/plugins/zzfxm.js +10 -10
- package/reference.md +90 -54
- package/src/engine.js +28 -23
- package/src/engineAudio.js +285 -110
- package/src/engineBuild.js +9 -9
- package/src/engineDebug.js +28 -28
- package/src/engineDraw.js +346 -202
- package/src/engineExport.js +28 -16
- package/src/engineInput.js +58 -68
- package/src/engineMedals.js +29 -29
- package/src/engineObject.js +28 -25
- package/src/engineParticles.js +67 -60
- package/src/engineRelease.js +1 -1
- package/src/engineSettings.js +70 -16
- package/src/engineTileLayer.js +34 -34
- package/src/engineUtilities.js +69 -62
- package/src/engineWebGL.js +467 -65
- /package/examples/shorts/{playSound.js → sound.js} +0 -0
package/src/engineTileLayer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
2
|
* LittleJS Tile Layer System
|
|
3
3
|
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
4
4
|
* - Unlimited numbers of layers, allocates canvases as needed
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
// Tile Layer System
|
|
15
15
|
|
|
16
16
|
/** Keep track of all tile layers with collision
|
|
17
|
-
* @type {Array<TileCollisionLayer>}
|
|
17
|
+
* @type {Array<TileCollisionLayer>}
|
|
18
18
|
* @memberof TileCollision */
|
|
19
|
-
|
|
19
|
+
const tileCollisionLayers = [];
|
|
20
20
|
|
|
21
21
|
/** Get tile collision data for a given cell in the grid
|
|
22
22
|
* @param {Vector2} pos
|
|
@@ -70,7 +70,7 @@ function tileCollisionRaycast(posStart, posEnd, object, solidOnly=true)
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
///////////////////////////////////////////////////////////////////////////////
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
74
|
* Load tile layers from exported data
|
|
75
75
|
* @param {Object} tileMapData - Level data from exported data
|
|
76
76
|
* @param {TileInfo} [tileInfo] - Default tile info (used for size and texture)
|
|
@@ -103,13 +103,13 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
103
103
|
{
|
|
104
104
|
const dataLayer = tileMapData.layers[layerIndex];
|
|
105
105
|
ASSERT(dataLayer.data && dataLayer.data.length);
|
|
106
|
-
ASSERT(levelSize.area()
|
|
106
|
+
ASSERT(levelSize.area() === dataLayer.data.length);
|
|
107
107
|
|
|
108
108
|
const layerRenderOrder = renderOrder - (layerCount - 1 - layerIndex);
|
|
109
109
|
const tileLayer = new TileCollisionLayer(vec2(), levelSize, tileInfo, layerRenderOrder);
|
|
110
110
|
tileLayers[layerIndex] = tileLayer;
|
|
111
111
|
|
|
112
|
-
for (let x=levelSize.x; x--;)
|
|
112
|
+
for (let x=levelSize.x; x--;)
|
|
113
113
|
for (let y=levelSize.y; y--;)
|
|
114
114
|
{
|
|
115
115
|
const pos = vec2(x, levelSize.y-1-y);
|
|
@@ -168,7 +168,7 @@ class TileLayerData
|
|
|
168
168
|
/**
|
|
169
169
|
* Canvas Layer - cached off screen rendering system
|
|
170
170
|
* - Contains an offscreen canvas that can be rendered to
|
|
171
|
-
* -
|
|
171
|
+
* - WebGL rendering is optional, call useWebGL to enable
|
|
172
172
|
* @extends EngineObject
|
|
173
173
|
* @example
|
|
174
174
|
* const canvasLayer = new CanvasLayer(vec2(), vec2(200,100));
|
|
@@ -190,18 +190,18 @@ class CanvasLayer extends EngineObject
|
|
|
190
190
|
this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
191
191
|
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
|
|
192
192
|
this.context = headlessMode ? undefined : this.canvas.getContext('2d');
|
|
193
|
-
/** @property {WebGLTexture} - Texture if using
|
|
193
|
+
/** @property {WebGLTexture} - Texture if using WebGL for this layer, call useWebGL to enable */
|
|
194
194
|
this.glTexture = undefined;
|
|
195
195
|
this.gravityScale = 0; // disable gravity by default for canvas layers
|
|
196
196
|
}
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
/** Destroy this canvas layer */
|
|
199
199
|
destroy()
|
|
200
200
|
{
|
|
201
201
|
if (this.destroyed)
|
|
202
202
|
return;
|
|
203
203
|
|
|
204
|
-
// free up the
|
|
204
|
+
// free up the WebGL texture
|
|
205
205
|
if (this.glTexture)
|
|
206
206
|
glDeleteTexture(this.glTexture);
|
|
207
207
|
super.destroy();
|
|
@@ -226,12 +226,12 @@ class CanvasLayer extends EngineObject
|
|
|
226
226
|
draw(pos, size, angle=0, color=WHITE, mirror=false, additiveColor, screenSpace=false, context)
|
|
227
227
|
{
|
|
228
228
|
// draw the canvas layer as a single tile that uses the whole texture
|
|
229
|
-
const
|
|
229
|
+
const useWebGL = glEnable && this.glTexture !== undefined;
|
|
230
230
|
const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
|
|
231
|
-
drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor,
|
|
231
|
+
drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
/** Draw onto the layer canvas in world space (bypass
|
|
234
|
+
/** Draw onto the layer canvas in world space (bypass WebGL)
|
|
235
235
|
* @param {Vector2} pos
|
|
236
236
|
* @param {Vector2} size
|
|
237
237
|
* @param {number} angle
|
|
@@ -265,8 +265,8 @@ class CanvasLayer extends EngineObject
|
|
|
265
265
|
if (textureInfo)
|
|
266
266
|
{
|
|
267
267
|
context.globalAlpha = color.a; // only alpha is supported
|
|
268
|
-
context.drawImage(textureInfo.image,
|
|
269
|
-
tileInfo.pos.x, tileInfo.pos.y,
|
|
268
|
+
context.drawImage(textureInfo.image,
|
|
269
|
+
tileInfo.pos.x, tileInfo.pos.y,
|
|
270
270
|
tileInfo.size.x, tileInfo.size.y, -.5, -.5, 1, 1);
|
|
271
271
|
context.globalAlpha = 1;
|
|
272
272
|
}
|
|
@@ -284,11 +284,11 @@ class CanvasLayer extends EngineObject
|
|
|
284
284
|
* @param {Vector2} [size=(1,1)]
|
|
285
285
|
* @param {Color} [color=(1,1,1,1)]
|
|
286
286
|
* @param {number} [angle=0] */
|
|
287
|
-
drawRect(pos, size, color, angle)
|
|
287
|
+
drawRect(pos, size, color, angle)
|
|
288
288
|
{ this.drawTile(pos, size, undefined, color, angle); }
|
|
289
289
|
|
|
290
|
-
/** Create or update the
|
|
291
|
-
* @param {boolean} [enable] - enable
|
|
290
|
+
/** Create or update the WebGL texture for this layer
|
|
291
|
+
* @param {boolean} [enable] - enable WebGL rendering and update the texture */
|
|
292
292
|
useWebGL(enable=true)
|
|
293
293
|
{
|
|
294
294
|
if (glEnable && enable)
|
|
@@ -334,7 +334,7 @@ class TileLayer extends CanvasLayer
|
|
|
334
334
|
this.canvas = new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
335
335
|
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this tile layer */
|
|
336
336
|
this.context = this.canvas.getContext('2d');
|
|
337
|
-
/** @property {WebGLTexture} - Texture if using
|
|
337
|
+
/** @property {WebGLTexture} - Texture if using WebGL for this layer */
|
|
338
338
|
this.glTexture = useWebGL ? glCreateTexture(this.canvas) : undefined;
|
|
339
339
|
// set no friction by default, applied friction is max of both objects
|
|
340
340
|
this.friction = 0;
|
|
@@ -359,7 +359,7 @@ class TileLayer extends CanvasLayer
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
/** Set data at a given position in the array
|
|
362
|
+
/** Set data at a given position in the array
|
|
363
363
|
* @param {Vector2} layerPos - Local position in array
|
|
364
364
|
* @param {TileLayerData} data - Data to set
|
|
365
365
|
* @param {boolean} [redraw] - Force the tile to redraw if true */
|
|
@@ -371,26 +371,26 @@ class TileLayer extends CanvasLayer
|
|
|
371
371
|
redraw && this.drawTileData(layerPos);
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
-
|
|
375
|
-
/** Get data at a given position in the array
|
|
374
|
+
|
|
375
|
+
/** Get data at a given position in the array
|
|
376
376
|
* @param {Vector2} layerPos - Local position in array
|
|
377
377
|
* @return {TileLayerData} */
|
|
378
378
|
getData(layerPos)
|
|
379
379
|
{ return layerPos.arrayCheck(this.size) && this.data[(layerPos.y|0)*this.size.x+layerPos.x|0]; }
|
|
380
|
-
|
|
380
|
+
|
|
381
381
|
// Render the tile layer, called automatically by the engine
|
|
382
382
|
render()
|
|
383
383
|
{
|
|
384
|
-
ASSERT(drawContext
|
|
385
|
-
|
|
384
|
+
ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
|
|
385
|
+
|
|
386
386
|
// draw the tile layer as a single tile
|
|
387
387
|
const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
|
|
388
388
|
const pos = this.pos.add(this.size.scale(.5));
|
|
389
|
-
const
|
|
390
|
-
drawTile(pos, this.size, tileInfo, WHITE, 0, false, CLEAR_BLACK,
|
|
389
|
+
const useWebGL = glEnable && this.glTexture !== undefined;
|
|
390
|
+
drawTile(pos, this.size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
/** Draw all the tile data to an offscreen canvas
|
|
393
|
+
/** Draw all the tile data to an offscreen canvas
|
|
394
394
|
* - This may be slow in some browsers but only needs to be done once */
|
|
395
395
|
redraw()
|
|
396
396
|
{
|
|
@@ -400,7 +400,7 @@ class TileLayer extends CanvasLayer
|
|
|
400
400
|
this.drawTileData(vec2(x,y), false);
|
|
401
401
|
this.redrawEnd();
|
|
402
402
|
if (this.glTexture)
|
|
403
|
-
this.useWebGL(); // update
|
|
403
|
+
this.useWebGL(); // update WebGL texture
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
/** Call to start the redraw process
|
|
@@ -436,7 +436,7 @@ class TileLayer extends CanvasLayer
|
|
|
436
436
|
/** Call to end the redraw process */
|
|
437
437
|
redrawEnd()
|
|
438
438
|
{
|
|
439
|
-
ASSERT(drawContext
|
|
439
|
+
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
440
440
|
glCopyToContext(drawContext);
|
|
441
441
|
//debugSaveCanvas(this.canvas);
|
|
442
442
|
|
|
@@ -447,7 +447,7 @@ class TileLayer extends CanvasLayer
|
|
|
447
447
|
/** Draw the tile at a given position in the tile grid
|
|
448
448
|
* This can be used to clear out tiles when they are destroyed
|
|
449
449
|
* Tiles can also be redrawn if inside a redrawStart/End block
|
|
450
|
-
* @param {Vector2} layerPos
|
|
450
|
+
* @param {Vector2} layerPos
|
|
451
451
|
* @param {boolean} [clear] - should the old tile be cleared out
|
|
452
452
|
*/
|
|
453
453
|
drawTileData(layerPos, clear=true)
|
|
@@ -462,9 +462,9 @@ class TileLayer extends CanvasLayer
|
|
|
462
462
|
|
|
463
463
|
// draw the tile if it has layer data
|
|
464
464
|
const d = this.getData(layerPos);
|
|
465
|
-
if (d.tile
|
|
465
|
+
if (d.tile !== undefined)
|
|
466
466
|
{
|
|
467
|
-
ASSERT(drawContext
|
|
467
|
+
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
468
468
|
const pos = layerPos.add(vec2(.5));
|
|
469
469
|
const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex, this.tileInfo.padding);
|
|
470
470
|
drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
@@ -477,7 +477,7 @@ class TileLayer extends CanvasLayer
|
|
|
477
477
|
* Tile Collision Layer - a tile layer with collision
|
|
478
478
|
* - adds collision data and functions to TileLayer
|
|
479
479
|
* - there can be multiple tile collision layers
|
|
480
|
-
* - tile
|
|
480
|
+
* - tile collision layers should not overlap each other
|
|
481
481
|
* @extends TileLayer
|
|
482
482
|
*/
|
|
483
483
|
class TileCollisionLayer extends TileLayer
|
package/src/engineUtilities.js
CHANGED
|
@@ -75,7 +75,19 @@ function lerp(valueA, valueB, percent)
|
|
|
75
75
|
if (valueA >= 0 && valueA <= 1 && ((valueB < 0 || valueB > 1) && (percent < 0 || percent > 1)))
|
|
76
76
|
console.warn('lerp() parameter order changed! use lerp(start, end, p)');
|
|
77
77
|
return valueA + clamp(percent) * (valueB-valueA);
|
|
78
|
-
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Gets percent between percentA and percentB and linearly interpolates between lerpA and lerpB
|
|
81
|
+
* A shortcut for lerp(lerpA, lerpB, percent(value, percentA, percentB))
|
|
82
|
+
* @param {number} value
|
|
83
|
+
* @param {number} percentA
|
|
84
|
+
* @param {number} percentB
|
|
85
|
+
* @param {number} lerpA
|
|
86
|
+
* @param {number} lerpB
|
|
87
|
+
* @return {number}
|
|
88
|
+
* @memberof Utilities */
|
|
89
|
+
function percentLerp(value, percentA, percentB, lerpA, lerpB)
|
|
90
|
+
{ return lerp(lerpA, lerpB, percent(value, percentA, percentB)); }
|
|
79
91
|
|
|
80
92
|
/** Returns signed wrapped distance between the two values passed in
|
|
81
93
|
* @param {number} valueA
|
|
@@ -127,22 +139,23 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
127
139
|
* @memberof Utilities */
|
|
128
140
|
function isPowerOfTwo(value) { return !(value & (value - 1)); }
|
|
129
141
|
|
|
130
|
-
/** Returns the nearest power of two not less
|
|
142
|
+
/** Returns the nearest power of two not less than the value
|
|
131
143
|
* @param {number} value
|
|
132
144
|
* @return {number}
|
|
133
145
|
* @memberof Utilities */
|
|
134
146
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
135
147
|
|
|
136
|
-
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
148
|
+
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
149
|
+
* this can be used for simple collision detection between objects
|
|
137
150
|
* @param {Vector2} posA - Center of box A
|
|
138
151
|
* @param {Vector2} sizeA - Size of box A
|
|
139
152
|
* @param {Vector2} posB - Center of box B
|
|
140
|
-
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
153
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, uses a point if undefined
|
|
141
154
|
* @return {boolean} - True if overlapping
|
|
142
155
|
* @memberof Utilities */
|
|
143
156
|
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
144
|
-
{
|
|
145
|
-
return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
|
|
157
|
+
{
|
|
158
|
+
return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
|
|
146
159
|
&& abs(posA.y - posB.y)*2 < sizeA.y + sizeB.y;
|
|
147
160
|
}
|
|
148
161
|
|
|
@@ -191,12 +204,13 @@ function isIntersecting(start, end, pos, size)
|
|
|
191
204
|
* @param {number} [frequency] - Frequency of the wave in Hz
|
|
192
205
|
* @param {number} [amplitude] - Amplitude (max height) of the wave
|
|
193
206
|
* @param {number} [t=time] - Value to use for time of the wave
|
|
207
|
+
* @param {number} [offset] - Value to use for time offset of the wave
|
|
194
208
|
* @return {number} - Value waving between 0 and amplitude
|
|
195
209
|
* @memberof Utilities */
|
|
196
|
-
function wave(frequency=1, amplitude=1, t=time)
|
|
197
|
-
{ return amplitude/2 * (1 - Math.cos(t*frequency*2*PI)); }
|
|
210
|
+
function wave(frequency=1, amplitude=1, t=time, offset=0)
|
|
211
|
+
{ return amplitude/2 * (1 - Math.cos(offset + t*frequency*2*PI)); }
|
|
198
212
|
|
|
199
|
-
/** Formats seconds to mm:ss style for display purposes
|
|
213
|
+
/** Formats seconds to mm:ss style for display purposes
|
|
200
214
|
* @param {number} t - time in seconds
|
|
201
215
|
* @return {string}
|
|
202
216
|
* @memberof Utilities */
|
|
@@ -212,13 +226,12 @@ async function fetchJSON(url)
|
|
|
212
226
|
return response.json();
|
|
213
227
|
}
|
|
214
228
|
|
|
215
|
-
/**
|
|
229
|
+
/**
|
|
216
230
|
* Check if object is a valid number, not NaN or undefined, but it may be infinite
|
|
217
231
|
* @param {any} n
|
|
218
232
|
* @return {boolean}
|
|
219
|
-
* @memberof Utilities
|
|
220
|
-
|
|
221
|
-
function isNumber(n) { return typeof n == 'number' && !isNaN(n); }
|
|
233
|
+
* @memberof Utilities */
|
|
234
|
+
function isNumber(n) { return typeof n === 'number' && !isNaN(n); }
|
|
222
235
|
|
|
223
236
|
///////////////////////////////////////////////////////////////////////////////
|
|
224
237
|
|
|
@@ -273,13 +286,13 @@ function randInCircle(radius=1, minRadius=0)
|
|
|
273
286
|
* @memberof Random */
|
|
274
287
|
function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear=false)
|
|
275
288
|
{
|
|
276
|
-
return linear ? colorA.lerp(colorB, rand()) :
|
|
289
|
+
return linear ? colorA.lerp(colorB, rand()) :
|
|
277
290
|
new Color(rand(colorA.r,colorB.r), rand(colorA.g,colorB.g), rand(colorA.b,colorB.b), rand(colorA.a,colorB.a));
|
|
278
291
|
}
|
|
279
292
|
|
|
280
293
|
///////////////////////////////////////////////////////////////////////////////
|
|
281
294
|
|
|
282
|
-
/**
|
|
295
|
+
/**
|
|
283
296
|
* Seeded random number generator
|
|
284
297
|
* - Can be used to create a deterministic random number sequence
|
|
285
298
|
* @example
|
|
@@ -306,8 +319,8 @@ class RandomGenerator
|
|
|
306
319
|
float(valueA=1, valueB=0)
|
|
307
320
|
{
|
|
308
321
|
// xorshift algorithm
|
|
309
|
-
this.seed ^= this.seed << 13;
|
|
310
|
-
this.seed ^= this.seed >>> 17;
|
|
322
|
+
this.seed ^= this.seed << 13;
|
|
323
|
+
this.seed ^= this.seed >>> 17;
|
|
311
324
|
this.seed ^= this.seed << 5;
|
|
312
325
|
return valueB + (valueA - valueB) * ((this.seed >>> 0) / 2**32);
|
|
313
326
|
}
|
|
@@ -356,16 +369,14 @@ class RandomGenerator
|
|
|
356
369
|
* let a = vec2(0, 1); // vector with coordinates (0, 1)
|
|
357
370
|
* a = vec2(5); // set a to (5, 5)
|
|
358
371
|
* b = vec2(); // set b to (0, 0)
|
|
359
|
-
* @memberof Utilities
|
|
360
|
-
*/
|
|
372
|
+
* @memberof Utilities */
|
|
361
373
|
function vec2(x=0, y) { return new Vector2(x, y === undefined ? x : y); }
|
|
362
374
|
|
|
363
|
-
/**
|
|
375
|
+
/**
|
|
364
376
|
* Check if object is a valid Vector2
|
|
365
377
|
* @param {any} v
|
|
366
378
|
* @return {boolean}
|
|
367
|
-
* @memberof Utilities
|
|
368
|
-
*/
|
|
379
|
+
* @memberof Utilities */
|
|
369
380
|
function isVector2(v) { return v instanceof Vector2; }
|
|
370
381
|
|
|
371
382
|
// vector2 asserts
|
|
@@ -374,10 +385,10 @@ function ASSERT_NUMBER_VALID(n) { ASSERT(isNumber(n), 'Number is invalid.', n);
|
|
|
374
385
|
function ASSERT_VECTOR2_NORMAL(v)
|
|
375
386
|
{
|
|
376
387
|
ASSERT_VECTOR2_VALID(v);
|
|
377
|
-
ASSERT(abs(v.lengthSquared()-1) < .01, 'Vector2 is not normal.', v);
|
|
388
|
+
ASSERT(abs(v.lengthSquared()-1) < .01, 'Vector2 is not normal.', v);
|
|
378
389
|
}
|
|
379
390
|
|
|
380
|
-
/**
|
|
391
|
+
/**
|
|
381
392
|
* 2D Vector object with vector math library
|
|
382
393
|
* - Functions do not change this so they can be chained together
|
|
383
394
|
* @example
|
|
@@ -501,7 +512,7 @@ class Vector2
|
|
|
501
512
|
* @param {number} [angle]
|
|
502
513
|
* @param {number} [length]
|
|
503
514
|
* @return {Vector2} */
|
|
504
|
-
setAngle(angle=0, length=1)
|
|
515
|
+
setAngle(angle=0, length=1)
|
|
505
516
|
{
|
|
506
517
|
ASSERT_NUMBER_VALID(angle);
|
|
507
518
|
ASSERT_NUMBER_VALID(length);
|
|
@@ -516,7 +527,7 @@ class Vector2
|
|
|
516
527
|
rotate(angle)
|
|
517
528
|
{
|
|
518
529
|
ASSERT_NUMBER_VALID(angle);
|
|
519
|
-
const c = Math.cos(-angle), s = Math.sin(-angle);
|
|
530
|
+
const c = Math.cos(-angle), s = Math.sin(-angle);
|
|
520
531
|
return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
|
|
521
532
|
}
|
|
522
533
|
|
|
@@ -528,9 +539,9 @@ class Vector2
|
|
|
528
539
|
ASSERT_NUMBER_VALID(direction);
|
|
529
540
|
ASSERT_NUMBER_VALID(length);
|
|
530
541
|
direction = mod(direction, 4);
|
|
531
|
-
ASSERT(direction
|
|
542
|
+
ASSERT(direction===0 || direction===1 || direction===2 || direction===3,
|
|
532
543
|
'Vector2.setDirection() direction must be an integer between 0 and 3.');
|
|
533
|
-
return vec2(direction%2 ? direction-1 ? -length : length : 0,
|
|
544
|
+
return vec2(direction%2 ? direction-1 ? -length : length : 0,
|
|
534
545
|
direction%2 ? 0 : direction ? -length : length);
|
|
535
546
|
}
|
|
536
547
|
|
|
@@ -582,7 +593,7 @@ class Vector2
|
|
|
582
593
|
/** Returns this vector expressed as a string
|
|
583
594
|
* @param {number} digits - precision to display
|
|
584
595
|
* @return {string} */
|
|
585
|
-
toString(digits=3)
|
|
596
|
+
toString(digits=3)
|
|
586
597
|
{
|
|
587
598
|
ASSERT_NUMBER_VALID(digits);
|
|
588
599
|
if (debug)
|
|
@@ -601,7 +612,7 @@ class Vector2
|
|
|
601
612
|
|
|
602
613
|
///////////////////////////////////////////////////////////////////////////////
|
|
603
614
|
|
|
604
|
-
/**
|
|
615
|
+
/**
|
|
605
616
|
* Create a color object with RGBA values, white by default
|
|
606
617
|
* @param {number} [r=1] - red
|
|
607
618
|
* @param {number} [g=1] - green
|
|
@@ -612,29 +623,27 @@ class Vector2
|
|
|
612
623
|
*/
|
|
613
624
|
function rgb(r, g, b, a) { return new Color(r, g, b, a); }
|
|
614
625
|
|
|
615
|
-
/**
|
|
626
|
+
/**
|
|
616
627
|
* Create a color object with HSLA values, white by default
|
|
617
628
|
* @param {number} [h=0] - hue
|
|
618
629
|
* @param {number} [s=0] - saturation
|
|
619
630
|
* @param {number} [l=1] - lightness
|
|
620
631
|
* @param {number} [a=1] - alpha
|
|
621
632
|
* @return {Color}
|
|
622
|
-
* @memberof Utilities
|
|
623
|
-
*/
|
|
633
|
+
* @memberof Utilities */
|
|
624
634
|
function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
625
635
|
|
|
626
|
-
/**
|
|
636
|
+
/**
|
|
627
637
|
* Check if object is a valid Color
|
|
628
638
|
* @param {any} c
|
|
629
639
|
* @return {boolean}
|
|
630
|
-
* @memberof Utilities
|
|
631
|
-
*/
|
|
640
|
+
* @memberof Utilities */
|
|
632
641
|
function isColor(c) { return c instanceof Color; }
|
|
633
642
|
|
|
634
643
|
// color asserts
|
|
635
644
|
function ASSERT_COLOR_VALID(c) { ASSERT(isColor(c) && c.isValid(), 'Color is invalid.', c); }
|
|
636
645
|
|
|
637
|
-
/**
|
|
646
|
+
/**
|
|
638
647
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
639
648
|
* @example
|
|
640
649
|
* let a = new Color; // white
|
|
@@ -706,7 +715,7 @@ class Color
|
|
|
706
715
|
* @param {number} scale
|
|
707
716
|
* @param {number} [alphaScale=scale]
|
|
708
717
|
* @return {Color} */
|
|
709
|
-
scale(scale, alphaScale=scale)
|
|
718
|
+
scale(scale, alphaScale=scale)
|
|
710
719
|
{ return new Color(this.r*scale, this.g*scale, this.b*scale, this.a*alphaScale); }
|
|
711
720
|
|
|
712
721
|
/** Returns a copy of this color clamped to the valid range between 0 and 1
|
|
@@ -723,9 +732,9 @@ class Color
|
|
|
723
732
|
ASSERT_NUMBER_VALID(percent);
|
|
724
733
|
const p = clamp(percent);
|
|
725
734
|
return new Color(
|
|
726
|
-
c.r*p + this.r*(1-p),
|
|
727
|
-
c.g*p + this.g*(1-p),
|
|
728
|
-
c.b*p + this.b*(1-p),
|
|
735
|
+
c.r*p + this.r*(1-p),
|
|
736
|
+
c.g*p + this.g*(1-p),
|
|
737
|
+
c.b*p + this.b*(1-p),
|
|
729
738
|
c.a*p + this.a*(1-p));
|
|
730
739
|
}
|
|
731
740
|
|
|
@@ -765,15 +774,15 @@ class Color
|
|
|
765
774
|
const minC = min(r, g, b);
|
|
766
775
|
const l = (maxC + minC) / 2;
|
|
767
776
|
let h = 0, s = 0;
|
|
768
|
-
if (maxC
|
|
777
|
+
if (maxC !== minC)
|
|
769
778
|
{
|
|
770
779
|
let d = maxC - minC;
|
|
771
780
|
s = l > .5 ? d / (2 - maxC - minC) : d / (maxC + minC);
|
|
772
|
-
if (r
|
|
781
|
+
if (r === maxC)
|
|
773
782
|
h = (g - b) / d + (g < b ? 6 : 0);
|
|
774
|
-
else if (g
|
|
783
|
+
else if (g === maxC)
|
|
775
784
|
h = (b - r) / d + 2;
|
|
776
|
-
else if (b
|
|
785
|
+
else if (b === maxC)
|
|
777
786
|
h = (r - g) / d + 4;
|
|
778
787
|
}
|
|
779
788
|
return [h / 6, s, l, a];
|
|
@@ -783,7 +792,7 @@ class Color
|
|
|
783
792
|
* @param {number} [amount]
|
|
784
793
|
* @param {number} [alphaAmount]
|
|
785
794
|
* @return {Color} */
|
|
786
|
-
mutate(amount=.05, alphaAmount=0)
|
|
795
|
+
mutate(amount=.05, alphaAmount=0)
|
|
787
796
|
{
|
|
788
797
|
ASSERT_NUMBER_VALID(amount);
|
|
789
798
|
ASSERT_NUMBER_VALID(alphaAmount);
|
|
@@ -799,47 +808,47 @@ class Color
|
|
|
799
808
|
/** Returns this color expressed as a hex color code
|
|
800
809
|
* @param {boolean} [useAlpha] - if alpha should be included in result
|
|
801
810
|
* @return {string} */
|
|
802
|
-
toString(useAlpha = true)
|
|
811
|
+
toString(useAlpha = true)
|
|
803
812
|
{
|
|
804
|
-
ASSERT(typeof useAlpha
|
|
813
|
+
ASSERT(typeof useAlpha === 'boolean', 'Use alpha boolean is invalid.', useAlpha);
|
|
805
814
|
if (debug && !this.isValid())
|
|
806
815
|
return `#000`;
|
|
807
816
|
const toHex = (c)=> ((c=clamp(c)*255|0)<16 ? '0' : '') + c.toString(16);
|
|
808
817
|
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
809
818
|
}
|
|
810
|
-
|
|
819
|
+
|
|
811
820
|
/** Set this color from a hex code
|
|
812
821
|
* @param {string} hex - html hex code
|
|
813
822
|
* @return {Color} */
|
|
814
823
|
setHex(hex)
|
|
815
824
|
{
|
|
816
|
-
ASSERT(typeof hex
|
|
825
|
+
ASSERT(typeof hex === 'string' && hex[0] === '#', 'Color hex code must be a string starting with #');
|
|
817
826
|
ASSERT([4,5,7,9].includes(hex.length), 'Invalid hex');
|
|
818
827
|
|
|
819
828
|
if (hex.length < 6)
|
|
820
829
|
{
|
|
821
830
|
const fromHex = (c)=> clamp(parseInt(hex[c],16)/15);
|
|
822
831
|
this.r = fromHex(1);
|
|
823
|
-
this.g = fromHex(2)
|
|
832
|
+
this.g = fromHex(2);
|
|
824
833
|
this.b = fromHex(3);
|
|
825
|
-
this.a = hex.length
|
|
834
|
+
this.a = hex.length === 5 ? fromHex(4) : 1;
|
|
826
835
|
}
|
|
827
836
|
else
|
|
828
837
|
{
|
|
829
838
|
const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
|
|
830
839
|
this.r = fromHex(1);
|
|
831
|
-
this.g = fromHex(3)
|
|
840
|
+
this.g = fromHex(3);
|
|
832
841
|
this.b = fromHex(5);
|
|
833
|
-
this.a = hex.length
|
|
842
|
+
this.a = hex.length === 9 ? fromHex(7) : 1;
|
|
834
843
|
}
|
|
835
844
|
|
|
836
845
|
ASSERT_COLOR_VALID(this);
|
|
837
846
|
return this;
|
|
838
847
|
}
|
|
839
|
-
|
|
848
|
+
|
|
840
849
|
/** Returns this color expressed as 32 bit RGBA value
|
|
841
850
|
* @return {number} */
|
|
842
|
-
rgbaInt()
|
|
851
|
+
rgbaInt()
|
|
843
852
|
{
|
|
844
853
|
const r = clamp(this.r)*255|0;
|
|
845
854
|
const g = clamp(this.g)*255<<8;
|
|
@@ -851,9 +860,7 @@ class Color
|
|
|
851
860
|
/** Checks if this is a valid color
|
|
852
861
|
* @return {boolean} */
|
|
853
862
|
isValid()
|
|
854
|
-
{
|
|
855
|
-
return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a);
|
|
856
|
-
}
|
|
863
|
+
{ return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a); }
|
|
857
864
|
}
|
|
858
865
|
|
|
859
866
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -862,7 +869,7 @@ class Color
|
|
|
862
869
|
/** Color - White #ffffff
|
|
863
870
|
* @type {Color}
|
|
864
871
|
* @memberof Utilities */
|
|
865
|
-
const WHITE = rgb();
|
|
872
|
+
const WHITE = rgb();
|
|
866
873
|
|
|
867
874
|
/** Color - Clear White #ffffff with 0 alpha
|
|
868
875
|
* @type {Color}
|
|
@@ -977,11 +984,11 @@ class Timer
|
|
|
977
984
|
/** Get percentage elapsed based on time it was set to, returns 0 if not set
|
|
978
985
|
* @return {number} */
|
|
979
986
|
getPercent() { return this.isSet()? 1-percent(this.time - time, 0, this.setTime) : 0; }
|
|
980
|
-
|
|
987
|
+
|
|
981
988
|
/** Returns this timer expressed as a string
|
|
982
989
|
* @return {string} */
|
|
983
990
|
toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
|
|
984
|
-
|
|
991
|
+
|
|
985
992
|
/** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
|
|
986
993
|
* @return {number} */
|
|
987
994
|
valueOf() { return this.get(); }
|