Skip to content

Commit c2c3f84

Browse files
committed
convert Particle to TS and the new pooling system
also fix the legacy pool system not reporting instances from the new pool implementation (temporary while the 2 co-exists)
1 parent 5634eee commit c2c3f84

File tree

5 files changed

+74
-27
lines changed

5 files changed

+74
-27
lines changed

packages/melonjs/src/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import Container from "./renderable/container.js";
4848
import World from "./physics/world.js";
4949
import ParticleEmitterSettings from "./particles/settings.js";
5050
import ParticleEmitter from "./particles/emitter.js";
51-
import Particle from "./particles/particle.js";
51+
import Particle from "./particles/particle.ts";
5252
import Entity from "./renderable/entity/entity.js";
5353
import Application from "./application/application.js";
5454

packages/melonjs/src/particles/emitter.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import pool from "../system/legacy_pool.js";
1+
import { particlePool } from "./particle.ts";
22
import ParticleEmitterSettings from "./settings.js";
33
import { randomFloat } from "./../math/math.ts";
44
import Container from "./../renderable/container.js";
@@ -142,7 +142,7 @@ export default class ParticleEmitter extends Container {
142142
addParticles(count) {
143143
for (let i = 0; i < count; i++) {
144144
// Add particle to the container
145-
this.addChild(pool.pull("Particle", this), this.pos.z);
145+
this.addChild(particlePool.get(this), this.pos.z);
146146
}
147147
this.isDirty = true;
148148
}
@@ -252,7 +252,7 @@ export default class ParticleEmitter extends Container {
252252
super.destroy(arguments);
253253
// clean emitter specific Properties
254254
if (typeof this._defaultParticle !== "undefined") {
255-
pool.push(this._defaultParticle);
255+
this._defaultParticle.destroy();
256256
this._defaultParticle = undefined;
257257
}
258258
this.settings.image = undefined;

packages/melonjs/src/particles/particle.js renamed to packages/melonjs/src/particles/particle.ts

+57-22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import timer from "./../system/timer.ts";
2-
import { randomFloat, clamp } from "./../math/math.ts";
3-
import Renderable from "./../renderable/renderable.js";
4-
import { vector2dPool } from "../math/vector2d.ts";
1+
import timer from "../system/timer.ts";
2+
import { randomFloat, clamp } from "../math/math.ts";
3+
import Renderable from "../renderable/renderable.js";
4+
import { Vector2d, vector2dPool } from "../math/vector2d.ts";
5+
import { createPool } from "../pool.ts";
6+
import ParticleEmitter from "./emitter.js";
7+
import CanvasRenderer from "../video/canvas/canvas_renderer.js";
8+
import WebGLRenderer from "../video/webgl/webgl_renderer.js";
9+
import Container from "../renderable/container.js";
510

611
/**
712
* @import ParticleEmitter from "./emitter.js";
@@ -11,31 +16,44 @@ import { vector2dPool } from "../math/vector2d.ts";
1116
* Single Particle Object.
1217
*/
1318
export default class Particle extends Renderable {
19+
vel: Vector2d;
20+
image: any;
21+
life: number;
22+
startLife: number;
23+
startScale: number;
24+
endScale: number;
25+
gravity: number;
26+
wind: number;
27+
followTrajectory: boolean;
28+
onlyInViewport: boolean;
29+
_deltaInv: number;
30+
_angle: number;
31+
alive: boolean;
32+
1433
/**
15-
* @param {ParticleEmitter} emitter - the particle emitter
34+
* @param emitter - the particle emitter
1635
*/
17-
constructor(emitter) {
36+
constructor(emitter: ParticleEmitter) {
1837
// Call the super constructor
1938
super(
2039
emitter.getRandomPointX(),
2140
emitter.getRandomPointY(),
2241
emitter.settings.image.width,
2342
emitter.settings.image.height,
2443
);
44+
// particle velocity
45+
this.vel = vector2dPool.get();
2546
this.onResetEvent(emitter, true);
2647
}
2748

2849
/**
2950
* @ignore
3051
*/
31-
onResetEvent(emitter, newInstance = false) {
32-
if (newInstance === false) {
52+
onResetEvent(emitter: ParticleEmitter, newInstance: boolean = false) {
53+
if (!newInstance) {
3354
this.pos.set(emitter.getRandomPointX(), emitter.getRandomPointY());
3455
this.resize(emitter.settings.image.width, emitter.settings.image.height);
3556
this.currentTransform.identity();
36-
} else {
37-
// particle velocity
38-
this.vel = vector2dPool.get();
3957
}
4058

4159
this.image = emitter.settings.image;
@@ -44,12 +62,10 @@ export default class Particle extends Renderable {
4462
this.alwaysUpdate = true;
4563

4664
if (typeof emitter.settings.tint === "string") {
47-
this.tint.parseCSS(emitter.settings.tint);
65+
this.tint.parseCSS(emitter.settings.tint as any);
4866
}
4967

50-
if (emitter.settings.textureAdditive === true) {
51-
this.blendMode = "additive";
52-
}
68+
this.blendMode = emitter.settings.textureAdditive ? "additive" : "normal";
5369

5470
if (emitter.settings.blendMode !== "normal") {
5571
this.blendMode = emitter.settings.blendMode;
@@ -106,28 +122,34 @@ export default class Particle extends Renderable {
106122
// Set the start particle rotation as defined in emitter
107123
// if the particle not follow trajectory
108124
if (!emitter.settings.followTrajectory) {
109-
this.angle = randomFloat(
125+
this._angle = randomFloat(
110126
emitter.settings.minRotation,
111127
emitter.settings.maxRotation,
112128
);
113129
}
130+
131+
this.alive = true;
114132
}
115133

116134
/**
117135
* Update the Particle <br>
118136
* This is automatically called by the game manager {@link game}
119137
* @ignore
120-
* @param {number} dt - time since the last update in milliseconds
138+
* @param dt - time since the last update in milliseconds
121139
*/
122-
update(dt) {
140+
override update(dt: number) {
123141
// move things forward independent of the current frame rate
124142
const skew = dt * this._deltaInv;
125143

126144
// Decrease particle life
127145
this.life = this.life > dt ? this.life - dt : 0;
128146

129-
if (this.life <= 0) {
130-
this.ancestor.removeChild(this);
147+
if (this.alive && this.life <= 0) {
148+
const parent = this.ancestor as Container;
149+
// use true for keepalive since we recycle the instance directly here after
150+
parent.removeChild(this, true);
151+
particlePool.release(this);
152+
this.alive = false;
131153
return false;
132154
}
133155

@@ -154,7 +176,7 @@ export default class Particle extends Renderable {
154176
// If necessary update the rotation of particle in accordance the particle trajectory
155177
const angle = this.followTrajectory
156178
? Math.atan2(this.vel.y, this.vel.x)
157-
: this.angle;
179+
: this._angle;
158180

159181
this.pos.x += this.vel.x * skew;
160182
this.pos.y += this.vel.y * skew;
@@ -173,9 +195,22 @@ export default class Particle extends Renderable {
173195
/**
174196
* @ignore
175197
*/
176-
draw(renderer) {
198+
override draw(renderer: CanvasRenderer | WebGLRenderer) {
177199
const w = this.width;
178200
const h = this.height;
179201
renderer.drawImage(this.image, 0, 0, w, h, -w / 2, -h / 2, w, h);
180202
}
181203
}
204+
205+
export const particlePool = createPool<Particle, [emitter: ParticleEmitter]>(
206+
(emitter) => {
207+
const instance = new Particle(emitter);
208+
209+
return {
210+
instance,
211+
reset(emitter) {
212+
instance.onResetEvent(emitter, false);
213+
},
214+
};
215+
},
216+
);

packages/melonjs/src/pool.ts

+10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { matrix2dPool } from "./math/matrix2d";
99
import { matrix3dPool } from "./math/matrix3d";
1010
import { vector2dPool } from "./math/vector2d";
1111
import { vector3dPool } from "./math/vector3d";
12+
import { particlePool } from "./particles/particle";
1213
import { boundsPool } from "./physics/bounds";
1314
import { tweenPool } from "./tweens/tween";
1415

@@ -26,6 +27,7 @@ const pools = {
2627
roundedRectangle: roundedRectanglePool,
2728
ellipse: ellipsePool,
2829
tween: tweenPool,
30+
particle: particlePool,
2931
} as const;
3032

3133
type PoolKey = keyof typeof pools;
@@ -34,4 +36,12 @@ export const getPool = <K extends PoolKey>(key: K): (typeof pools)[K] => {
3436
return pools[key];
3537
};
3638

39+
export const getTotalPoolSize = (): number => {
40+
let totalSize = 0;
41+
for (const key in pools) {
42+
totalSize += pools[key as PoolKey].size();
43+
}
44+
return totalSize;
45+
};
46+
3747
export { createPool } from "./system/pool";

packages/melonjs/src/system/legacy_pool.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { getTotalPoolSize } from "../pool";
2+
13
/**
24
* Object pooling - a technique that might speed up your game if used properly.<br>
35
* If some of your classes will be instantiated and removed a lot at a time, it is a
@@ -167,7 +169,7 @@ class ObjectPool {
167169
* @returns {number} amount of object instance
168170
*/
169171
getInstanceCount() {
170-
return this.instance_counter;
172+
return this.instance_counter + getTotalPoolSize();
171173
}
172174
}
173175

0 commit comments

Comments
 (0)