littlejsengine 1.6.92 → 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.
- package/README.md +31 -24
- package/build/littlejs.d.ts +87 -60
- package/build/littlejs.esm.js +322 -189
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +316 -185
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +296 -182
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/index.html +2 -2
- package/examples/js13k/index.html +13 -13
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/gameEffects.js +11 -10
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +4 -4
- package/examples/typescript/index.html +1 -1
- package/package.json +1 -1
- package/src/engine.js +2 -2
- package/src/engineAudio.js +43 -15
- package/src/engineBuild.js +18 -5
- package/src/engineDebug.js +21 -5
- package/src/engineDraw.js +61 -60
- package/src/engineExport.js +6 -4
- package/src/engineInput.js +26 -34
- package/src/engineObject.js +2 -2
- package/src/engineRelease.js +1 -2
- package/src/engineSettings.js +1 -0
- package/src/engineUtilities.js +95 -40
- package/src/engineWebGL.js +63 -27
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,33 +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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
.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
|
+
);
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
/** Convert from world to screen space coordinates
|
|
74
|
-
* - if calling outside of render, you may need to manually set mainCanvasSize
|
|
75
72
|
* @param {Vector2} worldPos
|
|
76
73
|
* @return {Vector2}
|
|
77
74
|
* @memberof Draw */
|
|
78
75
|
function worldToScreen(worldPos)
|
|
79
76
|
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
.
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
.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
|
+
);
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
@@ -95,13 +91,21 @@ function worldToScreen(worldPos)
|
|
|
95
91
|
* @param {Boolean} [mirror=0] - If true image is flipped along the Y axis
|
|
96
92
|
* @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
|
|
97
93
|
* @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
94
|
+
* @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
|
|
98
95
|
* @memberof Draw */
|
|
99
96
|
function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, color=new Color,
|
|
100
|
-
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable)
|
|
97
|
+
angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
|
|
101
98
|
{
|
|
102
99
|
showWatermark && ++drawCount;
|
|
100
|
+
|
|
103
101
|
if (glEnable && useWebGL)
|
|
104
102
|
{
|
|
103
|
+
if (screenSpace)
|
|
104
|
+
{
|
|
105
|
+
// convert to world space
|
|
106
|
+
pos = screenToWorld(pos);
|
|
107
|
+
size = size.scale(1/cameraScale);
|
|
108
|
+
}
|
|
105
109
|
if (tileIndex < 0 || !tileImage.width)
|
|
106
110
|
{
|
|
107
111
|
// if negative tile index or image not found, force untextured
|
|
@@ -143,7 +147,7 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
143
147
|
context.globalAlpha = color.a; // only alpha is supported
|
|
144
148
|
context.drawImage(tileImage, sX, sY, sWidth, sHeight, -.5, -.5, 1, 1);
|
|
145
149
|
}
|
|
146
|
-
});
|
|
150
|
+
}, undefined, screenSpace);
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -153,38 +157,30 @@ function drawTile(pos, size=vec2(1), tileIndex=-1, tileSize=tileSizeDefault, col
|
|
|
153
157
|
* @param {Color} [color=Color()]
|
|
154
158
|
* @param {Number} [angle=0]
|
|
155
159
|
* @param {Boolean} [useWebGL=glEnable]
|
|
160
|
+
* @param {Boolean} [screenSpace=0]
|
|
156
161
|
* @memberof Draw */
|
|
157
|
-
function drawRect(pos, size, color, angle, useWebGL)
|
|
158
|
-
{
|
|
159
|
-
drawTile(pos, size, -1, tileSizeDefault, color, angle, 0, 0, useWebGL);
|
|
160
|
-
}
|
|
162
|
+
function drawRect(pos, size, color, angle, useWebGL, screenSpace)
|
|
163
|
+
{ drawTile(pos, size, -1, tileSizeDefault, color, angle, 0, undefined, useWebGL, screenSpace); }
|
|
161
164
|
|
|
162
|
-
/** Draw
|
|
163
|
-
* @param {
|
|
164
|
-
* @param {Vector2} [size=Vector2(1,1)] - Size of the tile
|
|
165
|
-
* @param {Number} [tileIndex=-1] - Tile index to use, negative is untextured
|
|
166
|
-
* @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
|
|
167
167
|
* @param {Color} [color=Color()]
|
|
168
|
-
* @param {Number} [angle=0]
|
|
169
|
-
* @param {Boolean} [mirror=0]
|
|
170
|
-
* @param {Color} [additiveColor=Color(0,0,0,0)]
|
|
171
168
|
* @param {Boolean} [useWebGL=glEnable]
|
|
169
|
+
* @param {Boolean} [screenSpace=0]
|
|
172
170
|
* @memberof Draw */
|
|
173
|
-
function
|
|
171
|
+
function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
|
|
174
172
|
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
{
|
|
187
|
-
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
|
+
}
|
|
188
184
|
}
|
|
189
185
|
|
|
190
186
|
/** Draw colored line between two points
|
|
@@ -193,12 +189,13 @@ function drawRectScreenSpace(pos, size, color, angle, useWebGL)
|
|
|
193
189
|
* @param {Number} [thickness=.1]
|
|
194
190
|
* @param {Color} [color=Color()]
|
|
195
191
|
* @param {Boolean} [useWebGL=glEnable]
|
|
192
|
+
* @param {Boolean} [screenSpace=0]
|
|
196
193
|
* @memberof Draw */
|
|
197
194
|
function drawLine(posA, posB, thickness=.1, color, useWebGL)
|
|
198
195
|
{
|
|
199
196
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
200
197
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
201
|
-
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL);
|
|
198
|
+
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
|
|
202
199
|
}
|
|
203
200
|
|
|
204
201
|
/** Draw directly to a 2d canvas context in world space
|
|
@@ -208,12 +205,16 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL)
|
|
|
208
205
|
* @param {Boolean} mirror
|
|
209
206
|
* @param {Function} drawFunction
|
|
210
207
|
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
208
|
+
* @param {Boolean} [screenSpace=0]
|
|
211
209
|
* @memberof Draw */
|
|
212
|
-
function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainContext)
|
|
210
|
+
function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainContext, screenSpace)
|
|
213
211
|
{
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
if (!screenSpace)
|
|
213
|
+
{
|
|
214
|
+
// create canvas transform from world space to screen space
|
|
215
|
+
pos = worldToScreen(pos);
|
|
216
|
+
size = size.scale(cameraScale);
|
|
217
|
+
}
|
|
217
218
|
context.save();
|
|
218
219
|
context.translate(pos.x+.5|0, pos.y+.5|0);
|
|
219
220
|
context.rotate(angle);
|
|
@@ -320,6 +321,17 @@ class FontImage
|
|
|
320
321
|
this.context = context;
|
|
321
322
|
}
|
|
322
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
|
+
|
|
323
335
|
/** Draw text in screen space using the image font
|
|
324
336
|
* @param {String} text
|
|
325
337
|
* @param {Vector2} pos
|
|
@@ -357,17 +369,6 @@ class FontImage
|
|
|
357
369
|
|
|
358
370
|
context.restore();
|
|
359
371
|
}
|
|
360
|
-
|
|
361
|
-
/** Draw text in world space using the image font
|
|
362
|
-
* @param {String} text
|
|
363
|
-
* @param {Vector2} pos
|
|
364
|
-
* @param {Number} [scale=.25]
|
|
365
|
-
* @param {Boolean} [center]
|
|
366
|
-
*/
|
|
367
|
-
drawText(text, pos, scale=1, center)
|
|
368
|
-
{
|
|
369
|
-
this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center);
|
|
370
|
-
}
|
|
371
372
|
}
|
|
372
373
|
|
|
373
374
|
///////////////////////////////////////////////////////////////////////////////
|
package/src/engineExport.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Module Export
|
|
3
|
-
* - Export engine as a module with
|
|
3
|
+
* - Export engine as a module with functions where necessary
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
/** Set position of camera in world space
|
|
@@ -295,6 +295,10 @@ export {
|
|
|
295
295
|
mod,
|
|
296
296
|
clamp,
|
|
297
297
|
percent,
|
|
298
|
+
distanceWrap,
|
|
299
|
+
lerpWrap,
|
|
300
|
+
distanceAngle,
|
|
301
|
+
lerpAngle,
|
|
298
302
|
lerp,
|
|
299
303
|
smoothStep,
|
|
300
304
|
nearestPowerOfTwo,
|
|
@@ -309,11 +313,9 @@ export {
|
|
|
309
313
|
randInCircle,
|
|
310
314
|
randVector,
|
|
311
315
|
randColor,
|
|
312
|
-
randSeed,
|
|
313
|
-
setRandSeed,
|
|
314
|
-
randSeeded,
|
|
315
316
|
|
|
316
317
|
// Utility Classes
|
|
318
|
+
RandomGenerator,
|
|
317
319
|
Vector2,
|
|
318
320
|
Color,
|
|
319
321
|
Timer,
|
package/src/engineInput.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS Input System
|
|
3
|
-
* - Tracks
|
|
4
|
-
* -
|
|
5
|
-
* -
|
|
6
|
-
* - Virtual gamepad for touch devices
|
|
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
|
-
//
|
|
279
|
-
ontouchstart = (e)=>
|
|
278
|
+
// handle all touch events the same way
|
|
279
|
+
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
280
280
|
{
|
|
281
|
-
|
|
282
|
-
zzfx(0);
|
|
281
|
+
e.button = 0; // all touches are left click
|
|
283
282
|
|
|
284
|
-
//
|
|
285
|
-
|
|
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
|
-
|
|
305
|
-
|
|
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
|
-
//
|
|
309
|
-
|
|
299
|
+
// set was touching
|
|
300
|
+
wasTouching = touching;
|
|
310
301
|
|
|
311
|
-
return
|
|
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
|
-
|
|
314
|
+
if (touchGamepadEnable)
|
|
323
315
|
{
|
|
324
316
|
// touch input internal variables
|
|
325
317
|
touchGamepadButtons = [];
|
|
326
318
|
touchGamepadStick = vec2();
|
|
327
319
|
|
|
328
|
-
|
|
320
|
+
const touchHandler = ontouchstart;
|
|
329
321
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
330
322
|
{
|
|
331
323
|
// clear touch gamepad input
|
package/src/engineObject.js
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* LittleJS Object Base Object Class
|
|
9
|
-
* -
|
|
9
|
+
* - Top level object class used by the engine
|
|
10
10
|
* - Automatically adds self to object list
|
|
11
11
|
* - Will be updated and rendered each frame
|
|
12
12
|
* - Renders as a sprite from a tilesheet by default
|
|
13
13
|
* - Can have color and addtive color applied
|
|
14
|
-
* -
|
|
14
|
+
* - 2D Physics and collision system
|
|
15
15
|
* - Sorted by renderOrder
|
|
16
16
|
* - Objects can have children attached
|
|
17
17
|
* - Parents are updated before children, and set child transform
|
package/src/engineRelease.js
CHANGED
package/src/engineSettings.js
CHANGED
package/src/engineUtilities.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* - Vector2 - fast, simple, easy 2D vector class
|
|
5
5
|
* - Color - holds a rgba color with some math functions
|
|
6
6
|
* - Timer - tracks time automatically
|
|
7
|
+
* - RandomGenerator - seeded random number generator
|
|
7
8
|
* @namespace Utilities
|
|
8
9
|
*/
|
|
9
10
|
|
|
@@ -54,25 +55,58 @@ function mod(dividend, divisor=1) { return ((dividend % divisor) + divisor) % di
|
|
|
54
55
|
* @param {Number} [max=1]
|
|
55
56
|
* @return {Number}
|
|
56
57
|
* @memberof Utilities */
|
|
57
|
-
function clamp(value, min=0, max=1)
|
|
58
|
-
{ return value < min ? min : value > max ? max : value; }
|
|
58
|
+
function clamp(value, min=0, max=1) { return value < min ? min : value > max ? max : value; }
|
|
59
59
|
|
|
60
|
-
/** Returns what percentage the value is between
|
|
60
|
+
/** Returns what percentage the value is between valueA and valueB
|
|
61
61
|
* @param {Number} value
|
|
62
|
-
* @param {Number}
|
|
63
|
-
* @param {Number}
|
|
62
|
+
* @param {Number} valueA
|
|
63
|
+
* @param {Number} valueB
|
|
64
64
|
* @return {Number}
|
|
65
65
|
* @memberof Utilities */
|
|
66
|
-
function percent(value,
|
|
67
|
-
{ return
|
|
66
|
+
function percent(value, valueA, valueB)
|
|
67
|
+
{ return valueB-valueA ? clamp((value-valueA) / (valueB-valueA)) : 0; }
|
|
68
68
|
|
|
69
|
-
/** Linearly interpolates
|
|
69
|
+
/** Linearly interpolates between values passed in using percent
|
|
70
70
|
* @param {Number} percent
|
|
71
|
-
* @param {Number}
|
|
72
|
-
* @param {Number}
|
|
71
|
+
* @param {Number} valueA
|
|
72
|
+
* @param {Number} valueB
|
|
73
73
|
* @return {Number}
|
|
74
74
|
* @memberof Utilities */
|
|
75
|
-
function lerp(percent,
|
|
75
|
+
function lerp(percent, valueA, valueB) { return valueA + clamp(percent) * (valueB-valueA); }
|
|
76
|
+
|
|
77
|
+
/** Returns signed wrapped distance between the two values passed in
|
|
78
|
+
* @param {Number} valueA
|
|
79
|
+
* @param {Number} valueB
|
|
80
|
+
* @param {Number} [wrapSize=1]
|
|
81
|
+
* @returns {Number}
|
|
82
|
+
* @memberof Utilities */
|
|
83
|
+
function distanceWrap(valueA, valueB, wrapSize=1)
|
|
84
|
+
{ const d = (valueA - valueB) % wrapSize; return d*2 % wrapSize - d; }
|
|
85
|
+
|
|
86
|
+
/** Linearly interpolates between values passed in with wrappping
|
|
87
|
+
* @param {Number} percent
|
|
88
|
+
* @param {Number} valueA
|
|
89
|
+
* @param {Number} valueB
|
|
90
|
+
* @param {Number} [wrapSize=1]
|
|
91
|
+
* @returns {Number}
|
|
92
|
+
* @memberof Utilities */
|
|
93
|
+
function lerpWrap(percent, valueA, valueB, wrapSize=1)
|
|
94
|
+
{ return valueB + clamp(percent) * distanceWrap(valueA, valueB, wrapSize); }
|
|
95
|
+
|
|
96
|
+
/** Returns signed wrapped distance between the two angles passed in
|
|
97
|
+
* @param {Number} angleA
|
|
98
|
+
* @param {Number} angleB
|
|
99
|
+
* @returns {Number}
|
|
100
|
+
* @memberof Utilities */
|
|
101
|
+
function distanceAngle(angleA, angleB) { distanceWrap(angleA, angleB, 2*PI); }
|
|
102
|
+
|
|
103
|
+
/** Linearly interpolates between the angles passed in with wrappping
|
|
104
|
+
* @param {Number} percent
|
|
105
|
+
* @param {Number} angleA
|
|
106
|
+
* @param {Number} angleB
|
|
107
|
+
* @returns {Number}
|
|
108
|
+
* @memberof Utilities */
|
|
109
|
+
function lerpAngle(percent, angleA, angleB) { return lerpWrap(percent, angleA, angleB, 2*PI); }
|
|
76
110
|
|
|
77
111
|
/** Applies smoothstep function to the percentage value
|
|
78
112
|
* @param {Number} percent
|
|
@@ -127,17 +161,23 @@ function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
|
|
|
127
161
|
function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valueB); }
|
|
128
162
|
|
|
129
163
|
/** Returns a floored random value the two values passed in
|
|
130
|
-
* @param {Number}
|
|
164
|
+
* @param {Number} valueA
|
|
131
165
|
* @param {Number} [valueB=0]
|
|
132
166
|
* @return {Number}
|
|
133
167
|
* @memberof Random */
|
|
134
|
-
function randInt(valueA
|
|
168
|
+
function randInt(valueA, valueB=0) { return Math.floor(rand(valueA,valueB)); }
|
|
135
169
|
|
|
136
170
|
/** Randomly returns either -1 or 1
|
|
137
171
|
* @return {Number}
|
|
138
172
|
* @memberof Random */
|
|
139
173
|
function randSign() { return randInt(2) * 2 - 1; }
|
|
140
174
|
|
|
175
|
+
/** Returns a random Vector2 with the passed in length
|
|
176
|
+
* @param {Number} [length=1]
|
|
177
|
+
* @return {Vector2}
|
|
178
|
+
* @memberof Random */
|
|
179
|
+
function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length); }
|
|
180
|
+
|
|
141
181
|
/** Returns a random Vector2 within a circular shape
|
|
142
182
|
* @param {Number} [radius=1]
|
|
143
183
|
* @param {Number} [minRadius=0]
|
|
@@ -146,12 +186,6 @@ function randSign() { return randInt(2) * 2 - 1; }
|
|
|
146
186
|
function randInCircle(radius=1, minRadius=0)
|
|
147
187
|
{ return radius > 0 ? randVector(radius * rand(minRadius / radius, 1)**.5) : new Vector2; }
|
|
148
188
|
|
|
149
|
-
/** Returns a random Vector2 with the passed in length
|
|
150
|
-
* @param {Number} [length=1]
|
|
151
|
-
* @return {Vector2}
|
|
152
|
-
* @memberof Random */
|
|
153
|
-
function randVector(length=1) { return new Vector2().setAngle(rand(2*PI), length); }
|
|
154
|
-
|
|
155
189
|
/** Returns a random color between the two passed in colors, combine components if linear
|
|
156
190
|
* @param {Color} [colorA=Color()]
|
|
157
191
|
* @param {Color} [colorB=Color(0,0,0,1)]
|
|
@@ -164,29 +198,50 @@ function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear)
|
|
|
164
198
|
new Color(rand(colorA.r,colorB.r), rand(colorA.g,colorB.g), rand(colorA.b,colorB.b), rand(colorA.a,colorB.a));
|
|
165
199
|
}
|
|
166
200
|
|
|
167
|
-
|
|
168
|
-
* @type {Number}
|
|
169
|
-
* @default
|
|
170
|
-
* @memberof Random */
|
|
171
|
-
let randSeed = 1;
|
|
172
|
-
|
|
173
|
-
/** Set seed used by the randSeeded function, should not be 0
|
|
174
|
-
* @param {Number} seed
|
|
175
|
-
* @memberof Random */
|
|
176
|
-
function setRandSeed(seed) { randSeed = seed; }
|
|
201
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
177
202
|
|
|
178
|
-
/**
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Seeded random number generator
|
|
205
|
+
* - Can be used to create a deterministic random number sequence
|
|
206
|
+
* @example
|
|
207
|
+
* let r = new RandomGenerator(123); // random number generator with seed 123
|
|
208
|
+
* let a = r.rand(); // random value between 0 and 1
|
|
209
|
+
* let b = r.randInt(10); // random integer between 0 and 9
|
|
210
|
+
* r.seed = 123; // reset the seed
|
|
211
|
+
* let c = r.rand(); // the same value as a
|
|
212
|
+
*/
|
|
213
|
+
class RandomGenerator
|
|
184
214
|
{
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
215
|
+
/** Create a random number generator with the seed passed in
|
|
216
|
+
* @param {Number} seed - Starting seed */
|
|
217
|
+
constructor(seed)
|
|
218
|
+
{
|
|
219
|
+
/** @property {Number} - random seed */
|
|
220
|
+
this.seed = seed;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Returns a seeded random value between the two values passed in
|
|
224
|
+
* @param {Number} [valueA=1]
|
|
225
|
+
* @param {Number} [valueB=0]
|
|
226
|
+
* @return {Number} */
|
|
227
|
+
float(valueA=1, valueB=0)
|
|
228
|
+
{
|
|
229
|
+
// xorshift algorithm
|
|
230
|
+
this.seed ^= this.seed << 13;
|
|
231
|
+
this.seed ^= this.seed >>> 17;
|
|
232
|
+
this.seed ^= this.seed << 5;
|
|
233
|
+
return valueB + (valueA - valueB) * abs(this.seed % 1e9) / 1e9;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** Returns a floored seeded random value the two values passed in
|
|
237
|
+
* @param {Number} valueA
|
|
238
|
+
* @param {Number} [valueB=0]
|
|
239
|
+
* @return {Number} */
|
|
240
|
+
int(valueA, valueB=0) { return Math.floor(this.rand(valueA, valueB)); }
|
|
241
|
+
|
|
242
|
+
/** Randomly returns either -1 or 1 deterministically
|
|
243
|
+
* @return {Number} */
|
|
244
|
+
sign() { return this.randInt(2) * 2 - 1; }
|
|
190
245
|
}
|
|
191
246
|
|
|
192
247
|
///////////////////////////////////////////////////////////////////////////////
|