melonjs 10.6.1 → 10.7.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.
@@ -1,334 +1,69 @@
1
1
  import { createCanvas } from "./../video/video.js";
2
2
  import * as pool from "./../system/pooling.js";
3
- import Renderable from "./../renderable/renderable.js";
4
- import ParticleContainer from "./particlecontainer.js";
3
+ import ParticleEmitterSettings from "./settings.js";
5
4
  import { randomFloat } from "./../math/math.js";
5
+ import Container from "./../renderable/container.js";
6
6
 
7
7
 
8
-
9
- // generate a default image for the particles
10
- var pixel = (function () {
11
- var canvas = createCanvas(1, 1);
12
- var context = canvas.getContext("2d");
13
- context.fillStyle = "#fff";
14
- context.fillRect(0, 0, 1, 1);
15
- return canvas;
16
- })();
8
+ // default texture used when no sprite is defined
9
+ let defaultParticleTexture;
17
10
 
18
11
  /**
19
- * me.ParticleEmitterSettings contains the default settings for me.ParticleEmitter
20
12
  * @ignore
21
- * @class
22
- * @see ParticleEmitter
23
13
  */
24
- var ParticleEmitterSettings = {
25
- /**
26
- * Width of the particle spawn area.<br>
27
- * @public
28
- * @type {number}
29
- * @name width
30
- * @memberof ParticleEmitterSettings
31
- * @default 0
32
- */
33
- width : 0,
34
-
35
- /**
36
- * Height of the particle spawn area
37
- * @public
38
- * @type {number}
39
- * @name height
40
- * @memberof ParticleEmitterSettings
41
- * @default 0
42
- */
43
- height : 0,
44
-
45
- /**
46
- * Image used for particles
47
- * @public
48
- * @type {CanvasImageSource}
49
- * @name image
50
- * @memberof ParticleEmitterSettings
51
- * @default 1x1 white pixel
52
- * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#canvasimagesource
53
- */
54
- image : pixel,
55
-
56
- /**
57
- * Total number of particles in the emitter
58
- * @public
59
- * @type {number}
60
- * @name totalParticles
61
- * @default 50
62
- * @memberof ParticleEmitterSettings
63
- */
64
- totalParticles : 50,
65
-
66
- /**
67
- * Start angle for particle launch in Radians
68
- * @public
69
- * @type {number}
70
- * @name angle
71
- * @default Math.PI / 2
72
- * @memberof ParticleEmitterSettings
73
- */
74
- angle : Math.PI / 2,
75
-
76
- /**
77
- * Variation in the start angle for particle launch in Radians
78
- * @public
79
- * @type {number}
80
- * @name angleVariation
81
- * @default 0
82
- * @memberof ParticleEmitterSettings
83
- */
84
- angleVariation : 0,
85
-
86
- /**
87
- * Minimum time each particle lives once it is emitted in ms
88
- * @public
89
- * @type {number}
90
- * @name minLife
91
- * @default 1000
92
- * @memberof ParticleEmitterSettings
93
- */
94
- minLife : 1000,
95
-
96
- /**
97
- * Maximum time each particle lives once it is emitted in ms
98
- * @public
99
- * @type {number}
100
- * @name maxLife
101
- * @default 3000
102
- * @memberof ParticleEmitterSettings
103
- */
104
- maxLife : 3000,
105
-
106
- /**
107
- * Start speed of particles.<br>
108
- * @public
109
- * @type {number}
110
- * @name speed
111
- * @default 2
112
- * @memberof ParticleEmitterSettings
113
- */
114
- speed : 2,
115
-
116
- /**
117
- * Variation in the start speed of particles
118
- * @public
119
- * @type {number}
120
- * @name speedVariation
121
- * @default 1
122
- * @memberof ParticleEmitterSettings
123
- */
124
- speedVariation : 1,
125
-
126
- /**
127
- * Minimum start rotation for particles sprites in Radians
128
- * @public
129
- * @type {number}
130
- * @name minRotation
131
- * @default 0
132
- * @memberof ParticleEmitterSettings
133
- */
134
- minRotation : 0,
135
-
136
- /**
137
- * Maximum start rotation for particles sprites in Radians
138
- * @public
139
- * @type {number}
140
- * @name maxRotation
141
- * @default 0
142
- * @memberof ParticleEmitterSettings
143
- */
144
- maxRotation : 0,
145
-
146
- /**
147
- * Minimum start scale ratio for particles (1 = no scaling)
148
- * @public
149
- * @type {number}
150
- * @name minStartScale
151
- * @default 1
152
- * @memberof ParticleEmitterSettings
153
- */
154
- minStartScale : 1,
155
-
156
- /**
157
- * Maximum start scale ratio for particles (1 = no scaling)
158
- * @public
159
- * @type {number}
160
- * @name maxStartScale
161
- * @default 1
162
- * @memberof ParticleEmitterSettings
163
- */
164
- maxStartScale : 1,
165
-
166
- /**
167
- * Minimum end scale ratio for particles
168
- * @public
169
- * @type {number}
170
- * @name minEndScale
171
- * @default 0
172
- * @memberof ParticleEmitterSettings
173
- */
174
- minEndScale : 0,
175
-
176
- /**
177
- * Maximum end scale ratio for particles
178
- * @public
179
- * @type {number}
180
- * @name maxEndScale
181
- * @default 0
182
- * @memberof ParticleEmitterSettings
183
- */
184
- maxEndScale : 0,
185
-
186
- /**
187
- * Vertical force (Gravity) for each particle
188
- * @public
189
- * @type {number}
190
- * @name gravity
191
- * @default 0
192
- * @memberof ParticleEmitterSettings
193
- * @see game.world.gravity
194
- */
195
- gravity : 0,
196
-
197
- /**
198
- * Horizontal force (like a Wind) for each particle
199
- * @public
200
- * @type {number}
201
- * @name wind
202
- * @default 0
203
- * @memberof ParticleEmitterSettings
204
- */
205
- wind : 0,
206
-
207
- /**
208
- * Update the rotation of particle in accordance the particle trajectory.<br>
209
- * The particle sprite should aim at zero angle (draw from left to right).<br>
210
- * Override the particle minRotation and maxRotation.<br>
211
- * @public
212
- * @type {boolean}
213
- * @name followTrajectory
214
- * @default false
215
- * @memberof ParticleEmitterSettings
216
- */
217
- followTrajectory : false,
218
-
219
- /**
220
- * Enable the Texture Additive by canvas composite operation (lighter).<br>
221
- * WARNING: Composite Operation may decreases performance!.<br>
222
- * @public
223
- * @type {boolean}
224
- * @name textureAdditive
225
- * @default false
226
- * @memberof ParticleEmitterSettings
227
- */
228
- textureAdditive : false,
229
-
230
- /**
231
- * Update particles only in the viewport, remove it when out of viewport.<br>
232
- * @public
233
- * @type {boolean}
234
- * @name onlyInViewport
235
- * @default true
236
- * @memberof ParticleEmitterSettings
237
- */
238
- onlyInViewport : true,
239
-
240
- /**
241
- * Render particles in screen space. <br>
242
- * @public
243
- * @type {boolean}
244
- * @name floating
245
- * @default false
246
- * @memberof ParticleEmitterSettings
247
- */
248
- floating : false,
249
-
250
- /**
251
- * Maximum number of particles launched each time in this emitter (used only if emitter is Stream).<br>
252
- * @public
253
- * @type {number}
254
- * @name maxParticles
255
- * @default 10
256
- * @memberof ParticleEmitterSettings
257
- */
258
- maxParticles : 10,
259
-
260
- /**
261
- * How often a particle is emitted in ms (used only if emitter is Stream).<br>
262
- * Necessary that value is greater than zero.<br>
263
- * @public
264
- * @type {number}
265
- * @name frequency
266
- * @default 100
267
- * @memberof ParticleEmitterSettings
268
- */
269
- frequency : 100,
270
-
271
- /**
272
- * Duration that the emitter releases particles in ms (used only if emitter is Stream).<br>
273
- * After this period, the emitter stop the launch of particles.<br>
274
- * @public
275
- * @type {number}
276
- * @name duration
277
- * @default Infinity
278
- * @memberof ParticleEmitterSettings
279
- */
280
- duration : Infinity,
281
-
282
- /**
283
- * Skip n frames after updating the particle system once. <br>
284
- * This can be used to reduce the performance impact of emitters with many particles.<br>
285
- * @public
286
- * @type {number}
287
- * @name framesToSkip
288
- * @default 0
289
- * @memberof ParticleEmitterSettings
290
- */
291
- framesToSkip : 0
14
+ function createDefaultParticleTexture(w = 8, h = 8) {
15
+ if (typeof defaultParticleTexture === "undefined") {
16
+ defaultParticleTexture = createCanvas(w, h, true);
17
+ var context = defaultParticleTexture.getContext("2d");
18
+ context.fillStyle = "#fff";
19
+ context.fillRect(0, 0, w, h);
20
+ }
21
+ return defaultParticleTexture;
292
22
  };
293
23
 
294
24
  /**
25
+ * @classdesc
295
26
  * Particle Emitter Object.
296
- * @class
297
- * @augments Rect
298
- * @param {number} x x-position of the particle emitter
299
- * @param {number} y y-position of the particle emitter
300
- * @param {object} settings An object containing the settings for the particle emitter. See {@link ParticleEmitterSettings}
301
- * @example
302
- * // Create a basic emitter at position 100, 100
303
- * var emitter = new me.ParticleEmitter(100, 100);
304
- *
305
- * // Adjust the emitter properties
306
- * emitter.totalParticles = 200;
307
- * emitter.minLife = 1000;
308
- * emitter.maxLife = 3000;
309
- * emitter.z = 10;
310
- *
311
- * // Add the emitter to the game world
312
- * me.game.world.addChild(emitter);
313
- *
314
- * // Launch all particles one time and stop, like a explosion
315
- * emitter.burstParticles();
316
- *
317
- * // Launch constantly the particles, like a fountain
318
- * emitter.streamParticles();
319
- *
320
- * // At the end, remove emitter from the game world
321
- * // call this in onDestroyEvent function
322
- * me.game.world.removeChild(emitter);
27
+ * @augments Container
323
28
  */
324
- class ParticleEmitter extends Renderable {
325
-
326
- /**
327
- * @ignore
328
- */
329
- constructor(x, y, settings) {
29
+ class ParticleEmitter extends Container {
30
+ /**
31
+ * @param {number} x x position of the particle emitter
32
+ * @param {number} y y position of the particle emitter
33
+ * @param {ParticleEmitterSettings} [settings=ParticleEmitterSettings] the settings for the particle emitter.
34
+ * @example
35
+ * // Create a basic emitter at position 100, 100
36
+ * var emitter = new ParticleEmitter(100, 100);
37
+ *
38
+ * // Adjust the emitter properties
39
+ * emitter.totalParticles = 200;
40
+ * emitter.minLife = 1000;
41
+ * emitter.maxLife = 3000;
42
+ * emitter.z = 10;
43
+ *
44
+ * // Add the emitter to the game world
45
+ * me.game.world.addChild(emitter);
46
+ *
47
+ * // Launch all particles one time and stop, like a explosion
48
+ * emitter.burstParticles();
49
+ *
50
+ * // Launch constantly the particles, like a fountain
51
+ * emitter.streamParticles();
52
+ *
53
+ * // At the end, remove emitter from the game world
54
+ * // call this in onDestroyEvent function
55
+ * me.game.world.removeChild(emitter);
56
+ */
57
+ constructor(x, y, settings = {}) {
330
58
  // call the super constructor
331
- super(x, y, Infinity, Infinity);
59
+ super(
60
+ x, y,
61
+ settings.width | 1,
62
+ settings.height | 1
63
+ );
64
+
65
+ // center the emitter around the given coordinates
66
+ this.centerOn(x, y);
332
67
 
333
68
  // Emitter is Stream, launch particles constantly
334
69
  /** @ignore */
@@ -354,109 +89,52 @@ class ParticleEmitter extends Renderable {
354
89
  // don't sort the particles by z-index
355
90
  this.autoSort = false;
356
91
 
357
- this.container = new ParticleContainer(this);
92
+ // count the updates
93
+ this._updateCount = 0;
358
94
 
359
- // Reset the emitter to defaults
360
- this.reset(settings);
361
- }
362
-
363
- /**
364
- * @ignore
365
- */
366
- get z() {
367
- return this.container.pos.z;
368
- }
95
+ // the emitter settings
96
+ this.settings = {};
369
97
 
370
- /**
371
- * @ignore
372
- */
373
- set z(value) {
374
- this.container.pos.z = value;
375
- }
98
+ // internally store how much time was skipped when frames are skipped
99
+ this._dt = 0;
376
100
 
377
- /**
378
- * Floating property for particles, value is forwarded to the particle container <br>
379
- * @type {boolean}
380
- * @name floating
381
- * @memberof ParticleEmitter
382
- */
383
- get floating() {
384
- return this.container.floating;
385
- }
101
+ //this.anchorPoint.set(0, 0);
386
102
 
387
- set floating(value) {
388
- this.container.floating = value;
103
+ // Reset the emitter to defaults
104
+ this.reset(settings);
389
105
  }
390
106
 
391
107
  /**
392
- * @ignore
108
+ * Reset the emitter with particle emitter settings.
109
+ * @param {object} settings [optional] object with emitter settings. See {@link ParticleEmitterSettings}
393
110
  */
394
- onActivateEvent() {
395
- this.ancestor.addChild(this.container);
396
- this.container.pos.z = this.pos.z;
397
- if (!this.ancestor.autoSort) {
398
- this.ancestor.sort();
399
- }
400
- }
111
+ reset(settings = {}) {
112
+ Object.assign(this.settings, ParticleEmitterSettings, settings);
401
113
 
402
- /**
403
- * @ignore
404
- */
405
- onDeactivateEvent() {
406
- if (this.ancestor.hasChild(this.container)) {
407
- this.ancestor.removeChildNow(this.container);
114
+ // Cache the image reference
115
+ if (typeof this.settings.image === "undefined") {
116
+ this.settings.image = createDefaultParticleTexture(settings.textureSize, settings.textureSize);
408
117
  }
409
- }
410
118
 
411
- /**
412
- * @ignore
413
- */
414
- destroy() {
415
- this.reset();
119
+ this.floating = this.settings.floating;
120
+
121
+ this.isDirty = true;
416
122
  }
417
123
 
418
124
  /**
419
- * returns a random point inside the bounds x axis of this emitter
420
- * @name getRandomPointX
421
- * @memberof ParticleEmitter
422
- * @function
125
+ * returns a random point on the x axis within the bounds of this emitter
423
126
  * @returns {number}
424
127
  */
425
128
  getRandomPointX() {
426
- return this.pos.x + randomFloat(0, this.width);
129
+ return randomFloat(0, this.getBounds().width);
427
130
  }
428
131
 
429
132
  /**
430
- * returns a random point inside the bounds y axis of this emitter
431
- * @name getRandomPointY
432
- * @memberof ParticleEmitter
433
- * @function
133
+ * returns a random point on the y axis within the bounds this emitter
434
134
  * @returns {number}
435
135
  */
436
136
  getRandomPointY() {
437
- return this.pos.y + randomFloat(0, this.height);
438
- }
439
-
440
- /**
441
- * Reset the emitter with default values.<br>
442
- * @function
443
- * @param {object} settings [optional] object with emitter settings. See {@link ParticleEmitterSettings}
444
- * @name reset
445
- * @memberof ParticleEmitter
446
- */
447
- reset(settings) {
448
- // check if settings exists and create a dummy object if necessary
449
- settings = settings || {};
450
- var defaults = ParticleEmitterSettings;
451
-
452
- var width = (typeof settings.width === "number") ? settings.width : defaults.width;
453
- var height = (typeof settings.height === "number") ? settings.height : defaults.height;
454
- this.resize(width, height);
455
-
456
- Object.assign(this, defaults, settings);
457
-
458
- // reset particle container values
459
- this.container.reset();
137
+ return randomFloat(0, this.getBounds().height);
460
138
  }
461
139
 
462
140
  // Add count particles in the game world
@@ -464,59 +142,45 @@ class ParticleEmitter extends Renderable {
464
142
  addParticles(count) {
465
143
  for (var i = 0; i < ~~count; i++) {
466
144
  // Add particle to the container
467
- var particle = pool.pull("Particle", this);
468
- this.container.addChild(particle);
145
+ this.addChild(pool.pull("Particle", this), this.pos.z);
469
146
  }
147
+ this.isDirty = true;
470
148
  }
471
149
 
472
150
  /**
473
- * Emitter is of type stream and is launching particles <br>
474
- * @function
151
+ * Emitter is of type stream and is launching particles
475
152
  * @returns {boolean} Emitter is Stream and is launching particles
476
- * @name isRunning
477
- * @memberof ParticleEmitter
478
153
  */
479
154
  isRunning() {
480
155
  return this._enabled && this._stream;
481
156
  }
482
157
 
483
158
  /**
484
- * Launch particles from emitter constantly <br>
485
- * Particles example: Fountains
159
+ * Launch particles from emitter constantly (e.g. for stream)
486
160
  * @param {number} duration [optional] time that the emitter releases particles in ms
487
- * @function
488
- * @name streamParticles
489
- * @memberof ParticleEmitter
490
161
  */
491
162
  streamParticles(duration) {
492
163
  this._enabled = true;
493
164
  this._stream = true;
494
- this.frequency = Math.max(this.frequency, 1);
495
- this._durationTimer = (typeof duration === "number") ? duration : this.duration;
165
+ this.settings.frequency = Math.max(1, this.settings.frequency);
166
+ this._durationTimer = (typeof duration === "number") ? duration : this.settings.duration;
496
167
  }
497
168
 
498
169
  /**
499
- * Stop the emitter from generating new particles (used only if emitter is Stream) <br>
500
- * @function
501
- * @name stopStream
502
- * @memberof ParticleEmitter
170
+ * Stop the emitter from generating new particles (used only if emitter is Stream)
503
171
  */
504
172
  stopStream() {
505
173
  this._enabled = false;
506
174
  }
507
175
 
508
176
  /**
509
- * Launch all particles from emitter and stop <br>
510
- * Particles example: Explosions <br>
177
+ * Launch all particles from emitter and stop (e.g. for explosion)
511
178
  * @param {number} total [optional] number of particles to launch
512
- * @function
513
- * @name burstParticles
514
- * @memberof ParticleEmitter
515
179
  */
516
180
  burstParticles(total) {
517
181
  this._enabled = true;
518
182
  this._stream = false;
519
- this.addParticles((typeof total === "number") ? total : this.totalParticles);
183
+ this.addParticles((typeof total === "number") ? total : this.settings.totalParticles);
520
184
  this._enabled = false;
521
185
  }
522
186
 
@@ -524,6 +188,22 @@ class ParticleEmitter extends Renderable {
524
188
  * @ignore
525
189
  */
526
190
  update(dt) {
191
+ // skip frames if necessary
192
+ if (++this._updateCount > this.settings.framesToSkip) {
193
+ this._updateCount = 0;
194
+ }
195
+ if (this._updateCount > 0) {
196
+ this._dt += dt;
197
+ return this.isDirty;
198
+ }
199
+
200
+ // apply skipped delta time
201
+ dt += this._dt;
202
+ this._dt = 0;
203
+
204
+ // Update particles
205
+ this.isDirty |= super.update(dt);
206
+
527
207
  // Launch new particles, if emitter is Stream
528
208
  if ((this._enabled) && (this._stream)) {
529
209
  // Check if the emitter has duration set
@@ -532,7 +212,7 @@ class ParticleEmitter extends Renderable {
532
212
 
533
213
  if (this._durationTimer <= 0) {
534
214
  this.stopStream();
535
- return false;
215
+ return this.isDirty;
536
216
  }
537
217
  }
538
218
 
@@ -540,21 +220,32 @@ class ParticleEmitter extends Renderable {
540
220
  this._frequencyTimer += dt;
541
221
 
542
222
  // Check for new particles launch
543
- var particlesCount = this.container.children.length;
544
- if ((particlesCount < this.totalParticles) && (this._frequencyTimer >= this.frequency)) {
545
- if ((particlesCount + this.maxParticles) <= this.totalParticles) {
546
- this.addParticles(this.maxParticles);
223
+ var particlesCount = this.children.length;
224
+ if ((particlesCount < this.settings.totalParticles) && (this._frequencyTimer >= this.settings.frequency)) {
225
+ if ((particlesCount + this.settings.maxParticles) <= this.settings.totalParticles) {
226
+ this.addParticles(this.settings.maxParticles);
547
227
  }
548
228
  else {
549
- this.addParticles(this.totalParticles - particlesCount);
229
+ this.addParticles(this.settings.totalParticles - particlesCount);
550
230
  }
551
-
552
231
  this._frequencyTimer = 0;
232
+ this.isDirty = true;
553
233
  }
554
234
  }
555
- return true;
235
+ return this.isDirty;
556
236
  }
557
237
 
238
+ /**
239
+ * Destroy function
240
+ * @ignore
241
+ */
242
+ destroy() {
243
+ // call the parent destroy method
244
+ super.destroy(arguments);
245
+ // clean emitter specific Properties
246
+ this.settings.image = undefined;
247
+ this.settings = undefined;
248
+ }
558
249
  };
559
250
 
560
- export { ParticleEmitterSettings, ParticleEmitter };
251
+ export default ParticleEmitter;