Skip to content

Commit

Permalink
convert Particle to TS and the new pooling system
Browse files Browse the repository at this point in the history
also fix the legacy pool system not reporting instances from the new pool implementation (temporary while the 2 co-exists)
  • Loading branch information
obiot committed Aug 18, 2024
1 parent 5634eee commit c2c3f84
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 27 deletions.
2 changes: 1 addition & 1 deletion packages/melonjs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import Container from "./renderable/container.js";
import World from "./physics/world.js";
import ParticleEmitterSettings from "./particles/settings.js";
import ParticleEmitter from "./particles/emitter.js";
import Particle from "./particles/particle.js";
import Particle from "./particles/particle.ts";
import Entity from "./renderable/entity/entity.js";
import Application from "./application/application.js";

Expand Down
6 changes: 3 additions & 3 deletions packages/melonjs/src/particles/emitter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import pool from "../system/legacy_pool.js";
import { particlePool } from "./particle.ts";
import ParticleEmitterSettings from "./settings.js";
import { randomFloat } from "./../math/math.ts";
import Container from "./../renderable/container.js";
Expand Down Expand Up @@ -142,7 +142,7 @@ export default class ParticleEmitter extends Container {
addParticles(count) {
for (let i = 0; i < count; i++) {
// Add particle to the container
this.addChild(pool.pull("Particle", this), this.pos.z);
this.addChild(particlePool.get(this), this.pos.z);
}
this.isDirty = true;
}
Expand Down Expand Up @@ -252,7 +252,7 @@ export default class ParticleEmitter extends Container {
super.destroy(arguments);
// clean emitter specific Properties
if (typeof this._defaultParticle !== "undefined") {
pool.push(this._defaultParticle);
this._defaultParticle.destroy();
this._defaultParticle = undefined;
}
this.settings.image = undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import timer from "./../system/timer.ts";
import { randomFloat, clamp } from "./../math/math.ts";
import Renderable from "./../renderable/renderable.js";
import { vector2dPool } from "../math/vector2d.ts";
import timer from "../system/timer.ts";
import { randomFloat, clamp } from "../math/math.ts";
import Renderable from "../renderable/renderable.js";
import { Vector2d, vector2dPool } from "../math/vector2d.ts";
import { createPool } from "../pool.ts";
import ParticleEmitter from "./emitter.js";
import CanvasRenderer from "../video/canvas/canvas_renderer.js";
import WebGLRenderer from "../video/webgl/webgl_renderer.js";
import Container from "../renderable/container.js";

/**
* @import ParticleEmitter from "./emitter.js";
Expand All @@ -11,31 +16,44 @@ import { vector2dPool } from "../math/vector2d.ts";
* Single Particle Object.
*/
export default class Particle extends Renderable {
vel: Vector2d;
image: any;
life: number;
startLife: number;
startScale: number;
endScale: number;
gravity: number;
wind: number;
followTrajectory: boolean;
onlyInViewport: boolean;
_deltaInv: number;
_angle: number;
alive: boolean;

/**
* @param {ParticleEmitter} emitter - the particle emitter
* @param emitter - the particle emitter
*/
constructor(emitter) {
constructor(emitter: ParticleEmitter) {
// Call the super constructor
super(
emitter.getRandomPointX(),
emitter.getRandomPointY(),
emitter.settings.image.width,
emitter.settings.image.height,
);
// particle velocity
this.vel = vector2dPool.get();
this.onResetEvent(emitter, true);
}

/**
* @ignore
*/
onResetEvent(emitter, newInstance = false) {
if (newInstance === false) {
onResetEvent(emitter: ParticleEmitter, newInstance: boolean = false) {
if (!newInstance) {
this.pos.set(emitter.getRandomPointX(), emitter.getRandomPointY());
this.resize(emitter.settings.image.width, emitter.settings.image.height);
this.currentTransform.identity();
} else {
// particle velocity
this.vel = vector2dPool.get();
}

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

if (typeof emitter.settings.tint === "string") {
this.tint.parseCSS(emitter.settings.tint);
this.tint.parseCSS(emitter.settings.tint as any);
}

if (emitter.settings.textureAdditive === true) {
this.blendMode = "additive";
}
this.blendMode = emitter.settings.textureAdditive ? "additive" : "normal";

if (emitter.settings.blendMode !== "normal") {
this.blendMode = emitter.settings.blendMode;
Expand Down Expand Up @@ -106,28 +122,34 @@ export default class Particle extends Renderable {
// Set the start particle rotation as defined in emitter
// if the particle not follow trajectory
if (!emitter.settings.followTrajectory) {
this.angle = randomFloat(
this._angle = randomFloat(
emitter.settings.minRotation,
emitter.settings.maxRotation,
);
}

this.alive = true;
}

/**
* Update the Particle <br>
* This is automatically called by the game manager {@link game}
* @ignore
* @param {number} dt - time since the last update in milliseconds
* @param dt - time since the last update in milliseconds
*/
update(dt) {
override update(dt: number) {
// move things forward independent of the current frame rate
const skew = dt * this._deltaInv;

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

if (this.life <= 0) {
this.ancestor.removeChild(this);
if (this.alive && this.life <= 0) {
const parent = this.ancestor as Container;
// use true for keepalive since we recycle the instance directly here after
parent.removeChild(this, true);
particlePool.release(this);
this.alive = false;
return false;
}

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

this.pos.x += this.vel.x * skew;
this.pos.y += this.vel.y * skew;
Expand All @@ -173,9 +195,22 @@ export default class Particle extends Renderable {
/**
* @ignore
*/
draw(renderer) {
override draw(renderer: CanvasRenderer | WebGLRenderer) {
const w = this.width;
const h = this.height;
renderer.drawImage(this.image, 0, 0, w, h, -w / 2, -h / 2, w, h);
}
}

export const particlePool = createPool<Particle, [emitter: ParticleEmitter]>(
(emitter) => {
const instance = new Particle(emitter);

return {
instance,
reset(emitter) {
instance.onResetEvent(emitter, false);
},
};
},
);
10 changes: 10 additions & 0 deletions packages/melonjs/src/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { matrix2dPool } from "./math/matrix2d";
import { matrix3dPool } from "./math/matrix3d";
import { vector2dPool } from "./math/vector2d";
import { vector3dPool } from "./math/vector3d";
import { particlePool } from "./particles/particle";
import { boundsPool } from "./physics/bounds";
import { tweenPool } from "./tweens/tween";

Expand All @@ -26,6 +27,7 @@ const pools = {
roundedRectangle: roundedRectanglePool,
ellipse: ellipsePool,
tween: tweenPool,
particle: particlePool,
} as const;

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

export const getTotalPoolSize = (): number => {
let totalSize = 0;
for (const key in pools) {
totalSize += pools[key as PoolKey].size();
}
return totalSize;
};

export { createPool } from "./system/pool";
4 changes: 3 additions & 1 deletion packages/melonjs/src/system/legacy_pool.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { getTotalPoolSize } from "../pool";

/**
* Object pooling - a technique that might speed up your game if used properly.<br>
* If some of your classes will be instantiated and removed a lot at a time, it is a
Expand Down Expand Up @@ -167,7 +169,7 @@ class ObjectPool {
* @returns {number} amount of object instance
*/
getInstanceCount() {
return this.instance_counter;
return this.instance_counter + getTotalPoolSize();
}
}

Expand Down

0 comments on commit c2c3f84

Please sign in to comment.