melonjs 10.12.0 → 13.0.0

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 (50) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +6 -6
  3. package/dist/melonjs.js +22651 -22529
  4. package/dist/melonjs.min.js +5 -6
  5. package/dist/melonjs.module.d.ts +195 -195
  6. package/dist/melonjs.module.js +22107 -21977
  7. package/package.json +14 -14
  8. package/src/application/application.js +231 -0
  9. package/src/audio/audio.js +13 -7
  10. package/src/camera/camera2d.js +6 -6
  11. package/src/game.js +9 -232
  12. package/src/index.js +3 -3
  13. package/src/input/keyboard.js +2 -2
  14. package/src/input/pointer.js +4 -5
  15. package/src/input/pointerevent.js +8 -8
  16. package/src/lang/deprecated.js +0 -29
  17. package/src/level/level.js +2 -2
  18. package/src/level/tiled/TMXLayer.js +2 -2
  19. package/src/level/tiled/TMXTileMap.js +3 -3
  20. package/src/loader/loader.js +64 -28
  21. package/src/loader/loadingscreen.js +28 -115
  22. package/src/loader/melonjs_logo.png +0 -0
  23. package/src/physics/body.js +27 -51
  24. package/src/physics/detector.js +3 -3
  25. package/src/physics/quadtree.js +58 -29
  26. package/src/physics/world.js +32 -3
  27. package/src/polyfill/index.js +4 -0
  28. package/src/renderable/container.js +2 -2
  29. package/src/renderable/imagelayer.js +8 -8
  30. package/src/renderable/light2d.js +40 -11
  31. package/src/renderable/trigger.js +4 -4
  32. package/src/state/stage.js +1 -1
  33. package/src/state/state.js +50 -3
  34. package/src/system/device.js +808 -1039
  35. package/src/system/dom.js +69 -0
  36. package/src/system/event.js +13 -1
  37. package/src/system/platform.js +32 -0
  38. package/src/system/save.js +23 -14
  39. package/src/system/timer.js +12 -35
  40. package/src/text/bitmaptext.js +1 -2
  41. package/src/text/text.js +10 -14
  42. package/src/text/textmetrics.js +1 -2
  43. package/src/tweens/tween.js +6 -6
  44. package/src/utils/string.js +13 -24
  45. package/src/video/canvas/canvas_renderer.js +3 -2
  46. package/src/video/renderer.js +2 -2
  47. package/src/video/texture/canvas_texture.js +36 -2
  48. package/src/video/video.js +15 -9
  49. package/src/video/webgl/glshader.js +1 -1
  50. package/src/video/webgl/webgl_renderer.js +1 -1
@@ -7,8 +7,6 @@ import collision from "./collision.js";
7
7
  import * as arrayUtil from "./../utils/array.js";
8
8
  import timer from "./../system/timer.js";
9
9
  import { clamp } from "./../math/math.js";
10
- import { world } from "./../game.js";
11
-
12
10
 
13
11
  /**
14
12
  * @classdesc
@@ -74,7 +72,9 @@ class Body {
74
72
 
75
73
  if (typeof this.vel === "undefined") {
76
74
  /**
77
- * body velocity
75
+ * The current velocity of the body.
76
+ * See to apply a force if you need to modify a body velocity
77
+ * @see Body.force
78
78
  * @public
79
79
  * @type {Vector2d}
80
80
  * @default <0,0>
@@ -85,15 +85,15 @@ class Body {
85
85
 
86
86
  if (typeof this.force === "undefined") {
87
87
  /**
88
- * body force or acceleration (automatically) applied to the body.
89
- * when defining a force, user should also define a max velocity
88
+ * body force to apply to this the body in the current step.
89
+ * (any positive or negative force will be cancelled after every world/body update cycle)
90
90
  * @public
91
91
  * @type {Vector2d}
92
92
  * @default <0,0>
93
93
  * @see Body.setMaxVelocity
94
94
  * @example
95
95
  * // define a default maximum acceleration, initial force and friction
96
- * this.body.force.set(0, 0);
96
+ * this.body.force.set(1, 0);
97
97
  * this.body.friction.set(0.4, 0);
98
98
  * this.body.setMaxVelocity(3, 15);
99
99
  *
@@ -103,8 +103,6 @@ class Body {
103
103
  * this.body.force.x = -this.body.maxVel.x;
104
104
  * } else if (me.input.isKeyPressed("right")) {
105
105
  * this.body.force.x = this.body.maxVel.x;
106
- * } else {
107
- * this.body.force.x = 0;
108
106
  * }
109
107
  * }
110
108
  */
@@ -463,10 +461,12 @@ class Body {
463
461
  this.vel.y *= -this.bounce;
464
462
  }
465
463
 
466
- // cancel the falling an jumping flags if necessary
467
- var dir = Math.sign(world.gravity.y * this.gravityScale) || 1;
468
- this.falling = overlap.y >= dir;
469
- this.jumping = overlap.y <= -dir;
464
+ if (!this.ignoreGravity) {
465
+ // cancel the falling an jumping flags if necessary
466
+ var dir = this.falling === true ? 1 : this.jumping === true ? -1 : 0;
467
+ this.falling = overlap.y >= dir;
468
+ this.jumping = overlap.y <= -dir;
469
+ }
470
470
  }
471
471
  }
472
472
 
@@ -507,14 +507,12 @@ class Body {
507
507
  }
508
508
  }
509
509
 
510
-
511
510
  /**
512
511
  * Returns true if the any of the shape composing the body contains the given point.
513
512
  * @method Body#contains
514
513
  * @param {Vector2d} point
515
514
  * @returns {boolean} true if contains
516
515
  */
517
-
518
516
  /**
519
517
  * Returns true if the any of the shape composing the body contains the given point.
520
518
  * @param {number} x x coordinate
@@ -591,27 +589,23 @@ class Body {
591
589
  }
592
590
 
593
591
  /**
594
- * compute the new velocity value
595
- * @ignore
592
+ * Updates the parent's position as well as computes the new body's velocity based
593
+ * on the values of force/friction. Velocity chages are proportional to the
594
+ * me.timer.tick value (which can be used to scale velocities). The approach to moving the
595
+ * parent renderable is to compute new values of the Body.vel property then add them to
596
+ * the parent.pos value thus changing the postion the amount of Body.vel each time the
597
+ * update call is made. <br>
598
+ * Updates to Body.vel are bounded by maxVel (which defaults to viewport size if not set) <br>
599
+ * At this time a call to Body.Update does not call the onBodyUpdate callback that is listed in the constructor arguments.
600
+ * @protected
601
+ * @param {number} dt time since the last update in milliseconds.
602
+ * @returns {boolean} true if resulting velocity is different than 0
596
603
  */
597
- computeVelocity(/* dt */) {
604
+ update(dt) { // eslint-disable-line no-unused-vars
598
605
  // apply timer.tick to delta time for linear interpolation (when enabled)
599
606
  // #761 add delta time in body update
600
607
  var deltaTime = /* dt * */ timer.tick;
601
608
 
602
- // apply gravity to the current velocity
603
- if (!this.ignoreGravity) {
604
- var worldGravity = world.gravity;
605
-
606
- // apply gravity if defined
607
- this.vel.x += worldGravity.x * this.gravityScale * deltaTime;
608
- this.vel.y += worldGravity.y * this.gravityScale * deltaTime;
609
-
610
- // check if falling / jumping
611
- this.falling = (this.vel.y * Math.sign(worldGravity.y * this.gravityScale)) > 0;
612
- this.jumping = (this.falling ? false : this.jumping);
613
- }
614
-
615
609
  // apply force if defined
616
610
  if (this.force.x !== 0) {
617
611
  this.vel.x += this.force.x * deltaTime;
@@ -649,28 +643,10 @@ class Body {
649
643
  if (this.vel.x !== 0) {
650
644
  this.vel.x = clamp(this.vel.x, -this.maxVel.x, this.maxVel.x);
651
645
  }
652
- }
653
646
 
654
- /**
655
- * Updates the parent's position as well as computes the new body's velocity based
656
- * on the values of force/friction/gravity. Velocity chages are proportional to the
657
- * me.timer.tick value (which can be used to scale velocities). The approach to moving the
658
- * parent renderable is to compute new values of the Body.vel property then add them to
659
- * the parent.pos value thus changing the postion the amount of Body.vel each time the
660
- * update call is made. <br>
661
- * Updates to Body.vel are bounded by maxVel (which defaults to viewport size if not set) <br>
662
- *
663
- * In addition, when the gravity calcuation is made, if the Body.vel.y > 0 then the Body.falling
664
- * property is set to true and Body.jumping is set to !Body.falling.
665
- *
666
- * At this time a call to Body.Update does not call the onBodyUpdate callback that is listed in the constructor arguments.
667
- * @protected
668
- * @param {number} dt time since the last update in milliseconds.
669
- * @returns {boolean} true if resulting velocity is different than 0
670
- */
671
- update(dt) {
672
- // update the velocity
673
- this.computeVelocity(dt);
647
+ // check if falling / jumping
648
+ this.falling = (this.vel.y * Math.sign(this.force.y)) > 0;
649
+ this.jumping = (this.falling ? false : this.jumping);
674
650
 
675
651
  // update the body ancestor position
676
652
  this.ancestor.pos.add(this.vel);
@@ -1,7 +1,7 @@
1
1
  import * as SAT from "./sat.js";
2
2
  import ResponseObject from "./response.js";
3
3
  import Vector2d from "./../math/vector2.js";
4
- import { world } from "./../game.js";
4
+ import game from "./../game.js";
5
5
 
6
6
  // a dummy object when using Line for raycasting
7
7
  let dummyObj = {
@@ -50,7 +50,7 @@ function shouldCollide(a, b) {
50
50
  export function collisionCheck(objA, response = globalResponse) {
51
51
  var collisionCounter = 0;
52
52
  // retreive a list of potential colliding objects from the game world
53
- var candidates = world.broadphase.retrieve(objA);
53
+ var candidates = game.world.broadphase.retrieve(objA);
54
54
 
55
55
  for (var i = candidates.length, objB; i--, (objB = candidates[i]);) {
56
56
 
@@ -139,7 +139,7 @@ export function rayCast(line, result = []) {
139
139
  var collisionCounter = 0;
140
140
 
141
141
  // retrieve a list of potential colliding objects from the game world
142
- var candidates = world.broadphase.retrieve(line);
142
+ var candidates = game.world.broadphase.retrieve(line);
143
143
 
144
144
  for (var i = candidates.length, objB; i--, (objB = candidates[i]);) {
145
145
 
@@ -1,7 +1,6 @@
1
1
  import Vector2d from "./../math/vector2.js";
2
2
  import Container from "./../renderable/container.js";
3
3
  import * as arrayUtil from "./../utils/array.js";
4
- import { viewport } from "./../game.js";
5
4
 
6
5
  /*
7
6
  * A QuadTree implementation in JavaScript, a 2d spatial subdivision algorithm.
@@ -21,16 +20,17 @@ var QT_ARRAY = [];
21
20
  * or create a new one if the array is empty
22
21
  * @ignore
23
22
  */
24
- function QT_ARRAY_POP(bounds, max_objects = 4, max_levels = 4, level = 0) {
23
+ function QT_ARRAY_POP(world, bounds, max_objects = 4, max_levels = 4, level = 0) {
25
24
  if (QT_ARRAY.length > 0) {
26
25
  var _qt = QT_ARRAY.pop();
26
+ _qt.world = world;
27
27
  _qt.bounds = bounds;
28
28
  _qt.max_objects = max_objects;
29
29
  _qt.max_levels = max_levels;
30
30
  _qt.level = level;
31
31
  return _qt;
32
32
  } else {
33
- return new QuadTree(bounds, max_objects, max_levels, level);
33
+ return new QuadTree(world, bounds, max_objects, max_levels, level);
34
34
  }
35
35
  };
36
36
 
@@ -55,12 +55,17 @@ var QT_VECTOR = new Vector2d();
55
55
  */
56
56
  class QuadTree {
57
57
  /**
58
+ * @param {World} world the physic world this QuadTree belongs to
58
59
  * @param {Bounds} bounds bounds of the node
59
60
  * @param {number} [max_objects=4] max objects a node can hold before splitting into 4 subnodes
60
61
  * @param {number} [max_levels=4] total max levels inside root Quadtree
61
62
  * @param {number} [level] deepth level, required for subnodes
62
63
  */
63
- constructor(bounds, max_objects = 4, max_levels = 4, level = 0) {
64
+ constructor(world, bounds, max_objects = 4, max_levels = 4, level = 0) {
65
+
66
+ this.world = world;
67
+ this.bounds = bounds;
68
+
64
69
  this.max_objects = max_objects;
65
70
  this.max_levels = max_levels;
66
71
 
@@ -82,36 +87,60 @@ class QuadTree {
82
87
  top = this.bounds.top;
83
88
 
84
89
  //top right node
85
- this.nodes[0] = QT_ARRAY_POP({
86
- left : left + subWidth,
87
- top : top,
88
- width : subWidth,
89
- height : subHeight
90
- }, this.max_objects, this.max_levels, nextLevel);
90
+ this.nodes[0] = QT_ARRAY_POP(
91
+ this.world,
92
+ this.bounds, {
93
+ left : left + subWidth,
94
+ top : top,
95
+ width : subWidth,
96
+ height : subHeight
97
+ },
98
+ this.max_objects,
99
+ this.max_levels,
100
+ nextLevel
101
+ );
91
102
 
92
103
  //top left node
93
- this.nodes[1] = QT_ARRAY_POP({
94
- left : left,
95
- top: top,
96
- width : subWidth,
97
- height : subHeight
98
- }, this.max_objects, this.max_levels, nextLevel);
104
+ this.nodes[1] = QT_ARRAY_POP(
105
+ this.world,
106
+ this.bounds, {
107
+ left : left,
108
+ top: top,
109
+ width : subWidth,
110
+ height : subHeight
111
+ },
112
+ this.max_objects,
113
+ this.max_levels,
114
+ nextLevel
115
+ );
99
116
 
100
117
  //bottom left node
101
- this.nodes[2] = QT_ARRAY_POP({
102
- left : left,
103
- top : top + subHeight,
104
- width : subWidth,
105
- height : subHeight
106
- }, this.max_objects, this.max_levels, nextLevel);
118
+ this.nodes[2] = QT_ARRAY_POP(
119
+ this.world,
120
+ this.bounds, {
121
+ left : left,
122
+ top : top + subHeight,
123
+ width : subWidth,
124
+ height : subHeight
125
+ },
126
+ this.max_objects,
127
+ this.max_levels,
128
+ nextLevel
129
+ );
107
130
 
108
131
  //bottom right node
109
- this.nodes[3] = QT_ARRAY_POP({
110
- left : left + subWidth,
111
- top : top + subHeight,
112
- width : subWidth,
113
- height : subHeight
114
- }, this.max_objects, this.max_levels, nextLevel);
132
+ this.nodes[3] = QT_ARRAY_POP(
133
+ this.world,
134
+ this.bounds, {
135
+ left : left + subWidth,
136
+ top : top + subHeight,
137
+ width : subWidth,
138
+ height : subHeight
139
+ },
140
+ this.max_objects,
141
+ this.max_levels,
142
+ nextLevel
143
+ );
115
144
  }
116
145
 
117
146
  /*
@@ -125,7 +154,7 @@ class QuadTree {
125
154
 
126
155
  // use game world coordinates for floating items
127
156
  if (item.isFloating === true) {
128
- pos = viewport.localToWorld(bounds.left, bounds.top, QT_VECTOR);
157
+ pos = this.world.app.viewport.localToWorld(bounds.left, bounds.top, QT_VECTOR);
129
158
  } else {
130
159
  pos = QT_VECTOR.set(item.left, item.top);
131
160
  }
@@ -28,6 +28,13 @@ class World extends Container {
28
28
  // to mimic the previous behavior
29
29
  this.anchorPoint.set(0, 0);
30
30
 
31
+ /**
32
+ * the application (game) this physic world belong to
33
+ * @public
34
+ * @type {Application}
35
+ */
36
+ this.app = null;
37
+
31
38
  /**
32
39
  * the rate at which the game world is updated,
33
40
  * may be greater than or lower than the display fps
@@ -80,7 +87,7 @@ class World extends Container {
80
87
  * @public
81
88
  * @type {QuadTree}
82
89
  */
83
- this.broadphase = new QuadTree(this.getBounds().clone(), collision.maxChildren, collision.maxDepth);
90
+ this.broadphase = new QuadTree(this, this.getBounds().clone(), collision.maxChildren, collision.maxDepth);
84
91
 
85
92
  // reset the world container on the game reset signal
86
93
  event.on(event.GAME_RESET, this.reset, this);
@@ -140,6 +147,24 @@ class World extends Container {
140
147
  return this;
141
148
  }
142
149
 
150
+ /**
151
+ * Apply gravity to the given body
152
+ * @name bodyApplyVelocity
153
+ * @memberof World
154
+ * @private
155
+ * @param {Body} body
156
+ */
157
+ bodyApplyGravity(body) {
158
+ // apply gravity to the current velocity
159
+ if (!body.ignoreGravity && body.gravityScale !== 0) {
160
+ var gravity = this.gravity;
161
+
162
+ // apply gravity if defined
163
+ body.force.x += (body.mass * gravity.x) * body.gravityScale;
164
+ body.force.y += (body.mass * gravity.y) * body.gravityScale;
165
+ }
166
+ }
167
+
143
168
  /**
144
169
  * update the game world
145
170
  * @name reset
@@ -147,7 +172,7 @@ class World extends Container {
147
172
  * @param {number} dt the time passed since the last frame update
148
173
  * @returns {boolean} true if the word is dirty
149
174
  */
150
- update (dt) {
175
+ update(dt) {
151
176
  var isPaused = state.isPaused();
152
177
 
153
178
  // clear the quadtree
@@ -163,13 +188,17 @@ class World extends Container {
163
188
  // if the game is not paused, and ancestor can be updated
164
189
  if (!(isPaused && (!ancestor.updateWhenPaused)) &&
165
190
  (ancestor.inViewport || ancestor.alwaysUpdate)) {
166
- // apply physics to the body (this moves it)
191
+ // apply gravity to this body
192
+ this.bodyApplyGravity(body);
193
+ // body update function (this moves it)
167
194
  if (body.update(dt) === true) {
168
195
  // mark ancestor as dirty
169
196
  ancestor.isDirty = true;
170
197
  };
171
198
  // handle collisions against other objects
172
199
  collisionCheck(ancestor);
200
+ // clear body force
201
+ body.force.set(0, 0);
173
202
  }
174
203
  }
175
204
  });
@@ -1,6 +1,10 @@
1
1
  // https://github.com/melonjs/melonJS/issues/1092
2
2
  import "core-js/proposals/global-this";
3
3
 
4
+ // es10 string trim functions
5
+ import "core-js/es/string/trim-left";
6
+ import "core-js/es/string/trim-right";
7
+
4
8
  // "built-in" polyfills
5
9
  import "./console.js";
6
10
  import "./performance.js";
@@ -1,5 +1,5 @@
1
1
  import utils from "./../utils/utils.js";
2
- import * as game from "./../game.js";
2
+ import game from "./../game.js";
3
3
  import * as event from "./../system/event.js";
4
4
  import pool from "./../system/pooling.js";
5
5
  import state from "./../state/state.js";
@@ -638,7 +638,7 @@ class Container extends Renderable {
638
638
  * @memberof Container
639
639
  * @public
640
640
  * @param {Renderable} child
641
- * @param {boolean} [keepalive=False] True to prevent calling child.destroy()
641
+ * @param {boolean} [keepalive=false] true to prevent calling child.destroy()
642
642
  */
643
643
  removeChild(child, keepalive) {
644
644
  if (this.hasChild(child)) {
@@ -1,7 +1,7 @@
1
1
  import { renderer } from "./../video/video.js";
2
2
  import * as event from "./../system/event.js";
3
3
  import pool from "./../system/pooling.js";
4
- import { viewport } from "./../game.js";
4
+ import game from "./../game.js";
5
5
  import Sprite from "./sprite.js";
6
6
  import * as stringUtil from "./../utils/string.js";
7
7
 
@@ -134,7 +134,7 @@ class ImageLayer extends Sprite {
134
134
  this.repeatY = true;
135
135
  break;
136
136
  }
137
- this.resize(viewport.width, viewport.height);
137
+ this.resize(game.viewport.width, game.viewport.height);
138
138
  this.createPattern();
139
139
  }
140
140
 
@@ -146,13 +146,13 @@ class ImageLayer extends Sprite {
146
146
  event.on(event.VIEWPORT_ONRESIZE, this.resize, this);
147
147
  // force a first refresh when the level is loaded
148
148
  event.once(event.LEVEL_LOADED, () => {
149
- this.updateLayer(viewport.pos);
149
+ this.updateLayer(game.viewport.pos);
150
150
  });
151
151
  // in case the level is not added to the root container,
152
152
  // the onActivateEvent call happens after the LEVEL_LOADED event
153
153
  // so we need to force a first update
154
154
  if (this.ancestor.root !== true) {
155
- this.updateLayer(viewport.pos);
155
+ this.updateLayer(game.viewport.pos);
156
156
  }
157
157
  }
158
158
 
@@ -193,8 +193,8 @@ class ImageLayer extends Sprite {
193
193
 
194
194
  var width = this.width,
195
195
  height = this.height,
196
- bw = viewport.bounds.width,
197
- bh = viewport.bounds.height,
196
+ bw = game.viewport.bounds.width,
197
+ bh = game.viewport.bounds.height,
198
198
  ax = this.anchorPoint.x,
199
199
  ay = this.anchorPoint.y,
200
200
 
@@ -204,8 +204,8 @@ class ImageLayer extends Sprite {
204
204
  * See https://github.com/melonjs/melonJS/issues/741#issuecomment-138431532
205
205
  * for a thorough description of how this works.
206
206
  */
207
- x = ax * (rx - 1) * (bw - viewport.width) + this.offset.x - rx * vpos.x,
208
- y = ay * (ry - 1) * (bh - viewport.height) + this.offset.y - ry * vpos.y;
207
+ x = ax * (rx - 1) * (bw - game.viewport.width) + this.offset.x - rx * vpos.x,
208
+ y = ay * (ry - 1) * (bh - game.viewport.height) + this.offset.y - ry * vpos.y;
209
209
 
210
210
 
211
211
  // Repeat horizontally; start drawing from left boundary
@@ -4,19 +4,41 @@ import Renderable from "./renderable.js";
4
4
  /** @ignore */
5
5
  function createGradient(light) {
6
6
  var context = light.texture.context;
7
- var x1 = light.texture.width / 2;
8
- var y1 = light.texture.height / 2;
9
- var gradient = context.createRadialGradient(x1, y1, 0, x1, y1, light.radius);
7
+
8
+ var x1 = light.texture.width / 2,
9
+ y1 = light.texture.height / 2;
10
+
11
+ var radiusX = light.radiusX,
12
+ radiusY = light.radiusY;
13
+
14
+ var scaleX, scaleY, invScaleX, invScaleY;
15
+ var gradient;
16
+
10
17
 
11
18
  light.texture.clear();
12
19
 
20
+ if (radiusX >= radiusY) {
21
+ scaleX = 1;
22
+ invScaleX = 1;
23
+ scaleY = radiusY/radiusX;
24
+ invScaleY = radiusX/radiusY;
25
+ gradient = context.createRadialGradient(x1, y1 * invScaleY, 0, x1, radiusY * invScaleY, radiusX);
26
+ }
27
+ else {
28
+ scaleY = 1;
29
+ invScaleY = 1;
30
+ scaleX = radiusX/radiusY;
31
+ invScaleX = radiusY/radiusX;
32
+ gradient = context.createRadialGradient(x1 * invScaleX, y1, 0, x1 * invScaleX, y1, radiusY);
33
+ }
34
+
13
35
  gradient.addColorStop( 0, light.color.toRGBA(light.intensity));
14
36
  gradient.addColorStop( 1, light.color.toRGBA(0.0));
15
37
 
16
- context.beginPath();
17
38
  context.fillStyle = gradient;
18
- context.arc(x1, y1, light.radius, 0, Math.PI * 2, false);
19
- context.fill();
39
+
40
+ context.setTransform(scaleX, 0, 0, scaleY, 0, 0);
41
+ context.fillRect(0, 0, light.texture.width * invScaleX, light.texture.height * invScaleY);
20
42
  }
21
43
 
22
44
  /**
@@ -31,13 +53,14 @@ class Light2d extends Renderable {
31
53
  /**
32
54
  * @param {number} x - The horizontal position of the light.
33
55
  * @param {number} y - The vertical position of the light.
34
- * @param {number} radius - The radius of the light.
56
+ * @param {number} radiusX - The horizontal radius of the light.
57
+ * @param {number} [radiusY=radiusX] - The vertical radius of the light.
35
58
  * @param {Color|string} [color="#FFF"] the color of the light
36
59
  * @param {number} [intensity=0.7] - The intensity of the light.
37
60
  */
38
- constructor(x, y, radius, color = "#FFF", intensity = 0.7) {
61
+ constructor(x, y, radiusX, radiusY = radiusX, color = "#FFF", intensity = 0.7) {
39
62
  // call the parent constructor
40
- super(x, y, radius * 2, radius * 2);
63
+ super(x, y, radiusX * 2, radiusY * 2);
41
64
 
42
65
  /**
43
66
  * the color of the light
@@ -47,10 +70,16 @@ class Light2d extends Renderable {
47
70
  this.color = pool.pull("Color").parseCSS(color);
48
71
 
49
72
  /**
50
- * The radius of the light
73
+ * The horizontal radius of the light
74
+ * @type {number}
75
+ */
76
+ this.radiusX = radiusX;
77
+
78
+ /**
79
+ * The vertical radius of the light
51
80
  * @type {number}
52
81
  */
53
- this.radius = radius;
82
+ this.radiusY = radiusY;
54
83
 
55
84
  /**
56
85
  * The intensity of the light
@@ -2,7 +2,7 @@ import Renderable from "./renderable.js";
2
2
  import collision from "./../physics/collision.js";
3
3
  import Body from "./../physics/body.js";
4
4
  import level from "./../level/level.js";
5
- import { world, viewport } from "./../game.js";
5
+ import game from "./../game.js";
6
6
  import pool from "./../system/pooling.js";
7
7
 
8
8
  /**
@@ -89,7 +89,7 @@ class Trigger extends Renderable {
89
89
  getTriggerSettings() {
90
90
  // Lookup for the container instance
91
91
  if (typeof(this.triggerSettings.container) === "string") {
92
- this.triggerSettings.container = world.getChildByName(this.triggerSettings.container)[0];
92
+ this.triggerSettings.container = game.world.getChildByName(this.triggerSettings.container)[0];
93
93
  }
94
94
  return this.triggerSettings;
95
95
  }
@@ -99,7 +99,7 @@ class Trigger extends Renderable {
99
99
  */
100
100
  onFadeComplete() {
101
101
  level.load(this.gotolevel, this.getTriggerSettings());
102
- viewport.fadeOut(this.fade, this.duration);
102
+ game.viewport.fadeOut(this.fade, this.duration);
103
103
  }
104
104
 
105
105
  /**
@@ -118,7 +118,7 @@ class Trigger extends Renderable {
118
118
  if (this.fade && this.duration) {
119
119
  if (!this.fading) {
120
120
  this.fading = true;
121
- viewport.fadeIn(this.fade, this.duration,
121
+ game.viewport.fadeIn(this.fade, this.duration,
122
122
  this.onFadeComplete.bind(this));
123
123
  }
124
124
  } else {
@@ -1,5 +1,5 @@
1
1
  import { renderer } from "./../video/video.js";
2
- import * as game from "./../game.js";
2
+ import game from "./../game.js";
3
3
  import Camera2d from "./../camera/camera2d.js";
4
4
  import Color from "./../math/color.js";
5
5
 
@@ -1,7 +1,8 @@
1
1
  import { pauseTrack, resumeTrack } from "./../audio/audio.js";
2
2
  import * as fctUtil from "./../utils/function.js";
3
3
  import * as event from "./../system/event.js";
4
- import * as game from "./../game.js";
4
+ import game from "./../game.js";
5
+ import * as device from "./../system/device.js";
5
6
  import Stage from "./../state/stage.js";
6
7
  import DefaultLoadingScreen from "./../loader/loadingscreen.js";
7
8
 
@@ -140,14 +141,60 @@ event.on(event.BOOT, () => {
140
141
  event.on(event.VIDEO_INIT, () => {
141
142
  state.change(state.DEFAULT, true);
142
143
  });
143
- });
144
144
 
145
+ if (typeof globalThis.addEventListener === "function") {
146
+ // set pause/stop action on losing focus
147
+ globalThis.addEventListener("blur", () => {
148
+ if (device.stopOnBlur) {
149
+ state.stop(true);
150
+ }
151
+ if (device.pauseOnBlur) {
152
+ state.pause(true);
153
+ }
154
+ }, false);
155
+ // set restart/resume action on gaining focus
156
+ globalThis.addEventListener("focus", () => {
157
+ if (device.stopOnBlur) {
158
+ state.restart(true);
159
+ }
160
+ if (device.resumeOnFocus) {
161
+ state.resume(true);
162
+ }
163
+ // force focus if autofocus is on
164
+ if (device.autoFocus) {
165
+ device.focus();
166
+ }
167
+ }, false);
168
+ }
169
+
170
+ if (typeof globalThis.document !== "undefined") {
171
+ if (typeof globalThis.document.addEventListener === "function") {
172
+ // register on the visibilitychange event if supported
173
+ globalThis.document.addEventListener("visibilitychange", () => {
174
+ if (globalThis.document.visibilityState === "visible") {
175
+ if (device.stopOnBlur) {
176
+ state.restart(true);
177
+ }
178
+ if (device.resumeOnFocus) {
179
+ state.resume(true);
180
+ }
181
+ } else {
182
+ if (device.stopOnBlur) {
183
+ state.stop(true);
184
+ }
185
+ if (device.pauseOnBlur) {
186
+ state.pause(true);
187
+ }
188
+ }
189
+ }, false );
190
+ }
191
+ }
192
+ });
145
193
 
146
194
  /**
147
195
  * a State Manager (state machine)
148
196
  * @namespace state
149
197
  */
150
-
151
198
  var state = {
152
199
 
153
200
  /**