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/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
- ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
66
- return screenPos
67
- .add(vec2(.5))
68
- .subtract(mainCanvasSize.scale(.5))
69
- .multiply(vec2(1/cameraScale,-1/cameraScale))
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
- ASSERT(mainCanvasSize.x && mainCanvasSize.y, 'mainCanvasSize is invalid');
81
- return worldPos
82
- .subtract(cameraPos)
83
- .multiply(vec2(cameraScale,-cameraScale))
84
- .add(mainCanvasSize.scale(.5))
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 textured tile centered on pos in screen space
163
- * @param {Vector2} pos - Center of the tile
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 drawTileScreenSpace(pos, size=vec2(1), tileIndex, tileSize, color, angle, mirror, additiveColor, useWebGL)
171
+ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
174
172
  {
175
- drawTile(screenToWorld(pos), size.scale(1/cameraScale), tileIndex, tileSize, color, angle, mirror, additiveColor, useWebGL);
176
- }
177
-
178
- /** Draw colored rectangle in screen space
179
- * @param {Vector2} pos
180
- * @param {Vector2} [size=Vector2(1,1)]
181
- * @param {Color} [color=Color()]
182
- * @param {Number} [angle=0]
183
- * @param {Boolean} [useWebGL=glEnable]
184
- * @memberof Draw */
185
- function drawRectScreenSpace(pos, size, color, angle, useWebGL)
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
- // create canvas transform from world space to screen space
215
- pos = worldToScreen(pos);
216
- 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
+ }
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
  ///////////////////////////////////////////////////////////////////////////////
@@ -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
@@ -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,
@@ -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
@@ -6,12 +6,12 @@
6
6
 
7
7
  /**
8
8
  * LittleJS Object Base Object Class
9
- * - Base object class used by the engine
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
- * - 2d Physics and collision system
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
@@ -1,6 +1,5 @@
1
1
  /**
2
- * LittleJS - Release Build
3
- * MIT License - Copyright 2021 Frank Force
2
+ * LittleJS - Release Mode
4
3
  * - This file is used for release builds in place of engineDebug.js
5
4
  * - Debug functionality is disabled to reduce size and increase performance
6
5
  */
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * LittleJS Engine Settings
3
+ * - All settings for the engine are here
3
4
  * @namespace Settings
4
5
  */
5
6
 
@@ -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 max and min
60
+ /** Returns what percentage the value is between valueA and valueB
61
61
  * @param {Number} value
62
- * @param {Number} [min=0]
63
- * @param {Number} [max=1]
62
+ * @param {Number} valueA
63
+ * @param {Number} valueB
64
64
  * @return {Number}
65
65
  * @memberof Utilities */
66
- function percent(value, min=0, max=1)
67
- { return max-min ? clamp((value-min) / (max-min)) : 0; }
66
+ function percent(value, valueA, valueB)
67
+ { return valueB-valueA ? clamp((value-valueA) / (valueB-valueA)) : 0; }
68
68
 
69
- /** Linearly interpolates the percent value between max and min
69
+ /** Linearly interpolates between values passed in using percent
70
70
  * @param {Number} percent
71
- * @param {Number} [min=0]
72
- * @param {Number} [max=1]
71
+ * @param {Number} valueA
72
+ * @param {Number} valueB
73
73
  * @return {Number}
74
74
  * @memberof Utilities */
75
- function lerp(percent, min=0, max=1){ return min + clamp(percent) * (max-min); }
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} [valueA=1]
164
+ * @param {Number} valueA
131
165
  * @param {Number} [valueB=0]
132
166
  * @return {Number}
133
167
  * @memberof Random */
134
- function randInt(valueA=1, valueB=0) { return Math.floor(rand(valueA,valueB)); }
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
- /** Seed used by the randSeeded function
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
- /** Returns a seeded random value between the two values passed in using randSeed
179
- * @param {Number} [valueA=1]
180
- * @param {Number} [valueB=0]
181
- * @return {Number}
182
- * @memberof Random */
183
- function randSeeded(valueA=1, valueB=0)
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
- // xorshift algorithm
186
- randSeed ^= randSeed << 13;
187
- randSeed ^= randSeed >>> 17;
188
- randSeed ^= randSeed << 5;
189
- return valueB + (valueA-valueB) * abs(randSeed % 1e9) / 1e9;
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
  ///////////////////////////////////////////////////////////////////////////////