littlejsengine 1.15.3 → 1.15.9

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.
@@ -134,7 +134,7 @@ class EngineObject
134
134
  child.updateTransforms();
135
135
  }
136
136
 
137
- /** Update the object physics, called automatically by engine once each frame */
137
+ /** Update the object physics, called automatically by engine once each frame. Can be overridden to stop or change how physics works for an object. */
138
138
  updatePhysics()
139
139
  {
140
140
  // child objects do not have physics
@@ -167,7 +167,7 @@ class EngineObject
167
167
  if (!enablePhysicsSolver || !this.mass) // don't do collision for static objects
168
168
  return;
169
169
 
170
- const wasMovingDown = this.velocity.y < 0;
170
+ const wasFalling = this.velocity.y < 0 && gravity.y < 0 || this.velocity.y > 0 && gravity.y > 0;
171
171
  if (this.groundObject)
172
172
  {
173
173
  // apply friction in local space of ground object
@@ -223,10 +223,10 @@ class EngineObject
223
223
  {
224
224
  // push outside object collision
225
225
  this.pos.y = o.pos.y + (sizeBoth.y/2 + epsilon) * sign(oldPos.y - o.pos.y);
226
- if ((o.groundObject && wasMovingDown) || !o.mass)
226
+ if ((o.groundObject && wasFalling) || !o.mass)
227
227
  {
228
228
  // set ground object if landed on something
229
- if (wasMovingDown)
229
+ if (wasFalling)
230
230
  this.groundObject = o;
231
231
 
232
232
  // bounce if other object is fixed or grounded
@@ -313,12 +313,15 @@ class EngineObject
313
313
  const restitution = max(this.restitution, hitLayer.restitution);
314
314
  this.velocity.y *= -restitution;
315
315
 
316
- if (wasMovingDown)
316
+ if (wasFalling)
317
317
  {
318
- // adjust position to slightly above nearest tile boundary
318
+ // adjust position to slightly away from nearest tile
319
319
  // this prevents gap between object and ground
320
320
  const epsilon = .0001;
321
- this.pos.y = (oldPos.y-this.size.y/2|0)+this.size.y/2+epsilon;
321
+ const offset = this.size.y/2 + epsilon;
322
+ this.pos.y = gravity.y < 0 ?
323
+ floor(oldPos.y-this.size.y/2) + offset :
324
+ ceil( oldPos.y+this.size.y/2) - offset;
322
325
 
323
326
  // set ground object for tile collision
324
327
  this.groundObject = hitLayer;
@@ -487,21 +490,20 @@ class EngineObject
487
490
  * @return {string} */
488
491
  toString()
489
492
  {
490
- if (debug)
491
- {
492
- let text = 'type = ' + this.constructor.name;
493
- if (this.pos.x || this.pos.y)
494
- text += '\npos = ' + this.pos;
495
- if (this.velocity.x || this.velocity.y)
496
- text += '\nvelocity = ' + this.velocity;
497
- if (this.size.x || this.size.y)
498
- text += '\nsize = ' + this.size;
499
- if (this.angle)
500
- text += '\nangle = ' + this.angle.toFixed(3);
501
- if (this.color)
502
- text += '\ncolor = ' + this.color;
503
- return text;
504
- }
493
+ if (!debug) return;
494
+
495
+ let text = 'type = ' + this.constructor.name;
496
+ if (this.pos.x || this.pos.y)
497
+ text += '\npos = ' + this.pos;
498
+ if (this.velocity.x || this.velocity.y)
499
+ text += '\nvelocity = ' + this.velocity;
500
+ if (this.size.x || this.size.y)
501
+ text += '\nsize = ' + this.size;
502
+ if (this.angle)
503
+ text += '\nangle = ' + this.angle.toFixed(3);
504
+ if (this.color)
505
+ text += '\ncolor = ' + this.color;
506
+ return text;
505
507
  }
506
508
 
507
509
  /** Render debug info for this object */
@@ -109,9 +109,9 @@ class ParticleEmitter extends EngineObject
109
109
  /** @property {Color} - Color at start of life 2, randomized between start colors */
110
110
  this.colorStartB = colorStartB.copy();
111
111
  /** @property {Color} - Color at end of life 1, randomized between end colors */
112
- this.colorEndA = colorEndA.copy();
112
+ this.colorEndA = colorEndA.copy();
113
113
  /** @property {Color} - Color at end of life 2, randomized between end colors */
114
- this.colorEndB = colorEndB.copy();
114
+ this.colorEndB = colorEndB.copy();
115
115
  /** @property {boolean} - Should color be randomized linearly or across each component */
116
116
  this.randomColorLinear = randomColorLinear;
117
117
 
@@ -195,8 +195,10 @@ class ParticleEmitter extends EngineObject
195
195
  if (debugParticles)
196
196
  {
197
197
  // show emitter bounds
198
- const emitSize = typeof this.emitSize === 'number' ? vec2(this.emitSize) : this.emitSize;
199
- debugRect(this.pos, emitSize, '#0f0', 0, this.angle);
198
+ if (typeof this.emitSize === 'number')
199
+ debugCircle(this.pos, this.emitSize/2, '#0f0');
200
+ else
201
+ debugRect(this.pos, this.emitSize, '#0f0', 0, this.angle);
200
202
  }
201
203
  }
202
204
 
@@ -206,8 +208,8 @@ class ParticleEmitter extends EngineObject
206
208
  {
207
209
  // spawn a particle
208
210
  let pos = typeof this.emitSize === 'number' ? // check if number was used
209
- randInCircle(this.emitSize/2) // circle emitter
210
- : vec2(rand(-.5,.5), rand(-.5,.5)) // box emitter
211
+ randInCircle(this.emitSize/2) // circle emitter
212
+ : vec2(rand(-.5,.5), rand(-.5,.5)) // box emitter
211
213
  .multiply(this.emitSize).rotate(this.angle)
212
214
  let angle = rand(this.particleConeAngle, -this.particleConeAngle);
213
215
  if (!this.localSpace)
@@ -48,6 +48,20 @@ let canvasClearColor = CLEAR_BLACK;
48
48
  * @memberof Settings */
49
49
  let canvasMaxSize = vec2(1920, 1080);
50
50
 
51
+ /** Minimum aspect ratio of the canvas (width/height), unused if 0
52
+ * Can be used with canvasMaxAspect to limit aspect ratio
53
+ * @type {number}
54
+ * @default
55
+ * @memberof Settings */
56
+ let canvasMinAspect = 0;
57
+
58
+ /** Maximum aspect ratio of the canvas (width/height), unused if 0
59
+ * Can be used with canvasMinAspect to limit aspect ratio
60
+ * @type {number}
61
+ * @default
62
+ * @memberof Settings */
63
+ let canvasMaxAspect = 0;
64
+
51
65
  /** Fixed size of the canvas, if enabled canvas size never changes
52
66
  * - you may also need to set mainCanvasSize if using screen space coords in startup
53
67
  * @type {Vector2}
@@ -224,17 +238,17 @@ let touchGamepadEnable = false;
224
238
  * @memberof Settings */
225
239
  let touchGamepadCenterButton = true;
226
240
 
227
- /** True if touch gamepad should be analog stick or false to use if 8 way dpad
228
- * @type {boolean}
241
+ /** Number of buttons on touch gamepad (0-4), if 1 also acts as right analog stick
242
+ * @type {number}
229
243
  * @default
230
244
  * @memberof Settings */
231
- let touchGamepadAnalog = true;
245
+ let touchGamepadButtonCount = 4;
232
246
 
233
- /** Number of buttons on touch gamepad
234
- * @type {number}
247
+ /** True if touch gamepad should be analog stick or false to use if 8 way dpad
248
+ * @type {boolean}
235
249
  * @default
236
250
  * @memberof Settings */
237
- let touchGamepadButtonCount = 4;
251
+ let touchGamepadAnalog = true;
238
252
 
239
253
  /** Size of virtual gamepad for touch devices in pixels
240
254
  * @type {number}
@@ -344,6 +358,16 @@ function setCanvasClearColor(color) { canvasClearColor = color.copy(); }
344
358
  * @memberof Settings */
345
359
  function setCanvasMaxSize(size) { canvasMaxSize = size.copy(); }
346
360
 
361
+ /** Set minimum aspect ratio of the canvas (width/height), unused if 0
362
+ * @param {number} aspect
363
+ * @memberof Settings */
364
+ function setCanvasMinAspect(aspect) { canvasMinAspect = aspect; }
365
+
366
+ /** Set maximum aspect ratio of the canvas (width/height), unused if 0
367
+ * @param {number} aspect
368
+ * @memberof Settings */
369
+ function setCanvasMaxAspect(aspect) { canvasMaxAspect = aspect; }
370
+
347
371
  /** Set fixed size of the canvas
348
372
  * @param {Vector2} size
349
373
  * @memberof Settings */
@@ -500,6 +524,11 @@ function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
500
524
  * @memberof Settings */
501
525
  function setTouchGamepadCenterButton(enable) { touchGamepadCenterButton = enable; }
502
526
 
527
+ /** Set number of buttons on touch gamepad (0-4), if 1 also acts as right analog stick
528
+ * @param {number} count
529
+ * @memberof Settings */
530
+ function setTouchGamepadButtonCount(count) { touchGamepadButtonCount = count; }
531
+
503
532
  /** Set if touch gamepad should be analog stick or 8 way dpad
504
533
  * @param {boolean} analog
505
534
  * @memberof Settings */
@@ -47,7 +47,7 @@ function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
47
47
  }
48
48
  }
49
49
 
50
- /** Return the exact position of the boudnary of first tile hit, undefined if nothing was hit.
50
+ /** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
51
51
  * The point will be inside the colliding tile if it hits (may have a tiny shift)
52
52
  * @param {Vector2} posStart
53
53
  * @param {Vector2} posEnd
@@ -211,8 +211,7 @@ class CanvasLayer extends EngineObject
211
211
  /** Destroy this canvas layer */
212
212
  destroy()
213
213
  {
214
- if (this.destroyed)
215
- return;
214
+ if (this.destroyed) return;
216
215
 
217
216
  this.textureInfo.destroyWebGLTexture();
218
217
  super.destroy();
@@ -621,7 +620,7 @@ class TileCollisionLayer extends TileLayer
621
620
  return false;
622
621
  }
623
622
 
624
- /** Return the exact position of the boudnary of first tile hit, undefined if nothing was hit.
623
+ /** Return the exact position of the boundary of first tile hit, undefined if nothing was hit.
625
624
  * The point will be inside the colliding tile if it hits (may have a tiny shift)
626
625
  * @param {Vector2} posStart
627
626
  * @param {Vector2} posEnd
@@ -623,9 +623,15 @@ class Vector2
623
623
  {
624
624
  this.x = x;
625
625
  this.y = y;
626
+ ASSERT_VECTOR2_VALID(this);
626
627
  return this;
627
628
  }
628
629
 
630
+ /** Sets this vector from another vector and returns self
631
+ * @param {Vector2} v - other vector
632
+ * @return {Vector2} */
633
+ setFrom(v) { return this.set(v.x, v.y); }
634
+
629
635
  /** Returns a new vector that is a copy of this
630
636
  * @return {Vector2} */
631
637
  copy() { return new Vector2(this.x, this.y); }
@@ -688,7 +694,7 @@ class Vector2
688
694
  clampLength(length=1)
689
695
  {
690
696
  const l = this.length();
691
- return l > length ? this.scale(length/l) : this;
697
+ return l > length ? this.scale(length/l) : this.copy();
692
698
  }
693
699
 
694
700
  /** Returns the dot product of this and the vector passed in
@@ -775,6 +781,10 @@ class Vector2
775
781
  * @return {number} */
776
782
  area() { return abs(this.x * this.y); }
777
783
 
784
+ /** Returns true if this vector is (0,0)
785
+ * @return {boolean} */
786
+ isZero() { return !this.x && !this.y; }
787
+
778
788
  /** Returns a new vector that is p percent between this and the vector passed in
779
789
  * @param {Vector2} v - other vector
780
790
  * @param {number} percent
@@ -885,9 +895,15 @@ class Color
885
895
  this.g = g;
886
896
  this.b = b;
887
897
  this.a = a;
898
+ ASSERT_COLOR_VALID(this);
888
899
  return this;
889
900
  }
890
901
 
902
+ /** Sets this color from another color and returns self
903
+ * @param {Color} c - other color
904
+ * @return {Color} */
905
+ setFrom(c) { return this.set(c.r, c.g, c.b, c.a); }
906
+
891
907
  /** Returns a new color that is a copy of this
892
908
  * @return {Color} */
893
909
  copy() { return new Color(this.r, this.g, this.b, this.a); }