How do I reuse objects in an array for a particle system in JavaScript/jQuery?

Bojangles

I'm in the process of building an entity system for a canvas game. This started from a simple particle emitter/updater which I am altering to accommodate a multi-particle/entity generator. Whilst I am usually ok with JavaScript/jQuery I am running into the limits of my experience as it concerns arrays and would gratefully accept any help on the following:

When I need a new particle/entity my current system calls a function to push an object into an array which contains variables for the entity updates.

Then the update function runs a for loop over the array, checking on the type variable to update the particle (position/colour/etc...). Previously I would then [array.splice] the particle, based on some condition. When I needed further particles/entities I would then push new particles.

What I would like to achieve here is:

In the makeParticle function, check over the particle array for any "dead" particles and if any are available reuse them, or push a new particle if not I have created a particleAlive var as a flag for this purpose.

var particles = [];
var playing = false;

function mousePressed(event) {
playing = !playing;
}

if(playing) {
makeParticle(1, 200, 200, 10, "blueFlame");
makeParticle(1, 300, 200, 10, "redFlame");
}

function makeParticle(numParticles, xPos, yPos, pRadius, pType) {
  var i;
  for (i = 0; i < numParticles; i++) {
    var p = {
        type : pType,
        x : xPos,
        y : yPos,
        xVel : random(-0.5, 0.5),
        yVel : random(-1, -3),
        particleAlive : true,
        particleRender : true,
        size : pRadius
      }; // close var P

      particles.push(p);

// instead of pushing fresh particles all the time I would like the function, here, to check for free objects in the array

  } // close for loop

} // close function makeParticle

function runtime() {

  for(var i=0; i<particles.length; i++) {

  var p = particles[i];
  var thisType = p.type; 

  switch (thisType) {

    case "blueFlame":
      c.fillStyle = rgb(100,100,255); 
  c.fillCircle(p.x,p.y,p.size);
  p.x += p.xVel;
  p.y += p.yVel;
  p.size*=0.9;

      if (particles.size < 0.5) {
        particleAlive = false;
        particleRender = false;
      } // close if
  break;

case "redFlame":
  c.fillStyle = rgb(255,100,100); 
  c.fillCircle(p.x,p.y,p.size);
  p.x -= p.xVel;
  p.y -= p.yVel;
  p.size*=0.95;
      if (particles.size < 0.5) {
    particleAlive = false;
        particleRender = false;
      } // close if
  break;
} // close switch
} // close function runtime

I've found previous answers to relate questions, but I've been unable to get it working within the makeParticle function, like how to assign the attributes of p to particle[j]:

var particleUseOldOrNew = function() {

for (var j = 0, len = particles.length; j < len; j++) {

    if (particles[j].particleAlive === false)
        // particles[j] = p;
     return particle[j];
}
return null; // No dead particles found, create new "particles.push(p);" perhaps?
}
AlexZ

My personal opinion on the matter is that if you are making a new particle, it should be a new object, not a "re-using" of an old one with properties changed. Each new object should have a unique identifier, so if you need to track them (for development purposes, debugging, or later re-use), it is easy to do. Or at least keep a counter of the number of times you've re-used a particle object to represent a "new" particle! Though I guess if you've found that "re-using" improves performance (have you?), that's the way to go.

Anyway, enough pontificating, here is how I would do what you're asking (I assume speed is your main concern, so I did this with only native JS):

var particles = [];

//Function to create brand spanking new particle
function makeNewParticle(xPos, yPos, pRadius, pType){
    return  {
        type : pType,
        x : xPos,
        y : yPos,
        xVel : random(-0.5, 0.5),
        yVel : random(-1, -3),
        particleAlive : true,
        particleRender : true,
        size : pRadius
    };
};



//Function to change the properties of an old particle to make a psuedo-new particle (seriously, why do you want to do this?)
function changeExistingParticle(existing, xPos, yPos, pRadius, pType){
    existing.x = xPos;
    existing.y = yPos;
    existing.size = pRadius;
    existing.type = pType;
    return existing;
};



//Figure out the keys of dead particles in the particles[] array
function getDeadParticleKeys() {
    var keys = [];
    for(var p = 0; P < particles.length; p++) {
        if (!particles[p].particleAlive) {
            keys.push(p);
        }
    }
};



function makeParticle(numParticles, xPos, yPos, pRadius, pType) {
    var d, i, deadParticles;

    //Grab the "dead" particle keys
    deadParticleKeys = getDeadParticleKeys();
    numParticles -= deadParticleKeys.length;

    //Replace each dead particle with a "live" one at a specified key
    for (d = 0; d < deadParticleKeys.length; d++) {
        particles[ deadParticleKeys[d] ] = changeExistingParticle(particles[ deadParticleKeys[d] ], xPos, yPos, pRadius, pType)
    }

    //If we had more particles than there were dead spaces available, add to the array
    for (i = 0; i < numParticles; i++) {
        particles.push( makeNewParticle(xPos, yPos, pRadius, pType) );
    }
};

Now, here's how I recommend doing it: abandon the idea or "re-using" particles, make a separate constructor for each particle (will help immensely if you add methods to your particles in the future), and just scrap dead particles every time one is added:

//Make a constructor for a particle
var Particle = function(props){
    if (typeof props === 'function') {
       props = props();
    }
    this.type = props.type;
    this.x = props.x;
    this.y = props.y;
    this.size = props.size;
};
Paticle.prototype.particleAlive = true;
Paticle.prototype.particleRender = true;

//Global particles list
var particles = [];

//Remove all dead element from a ParticleList
particles.clean = function(){
    var p, keys;
    for (p = this.length; p >= 0; p--) {
        if (!p.particleAlive) {
            this.splice(p, 1);
        }
    }
};

//Method for adding x amount of new particles - if num parameter isn't provided, just assume it to be 1
particles.add = function(props, num){
    //First, clean out all the garbage!
    this.clean();

    //Now, append new particles to the end
    var n, limit = (num && typeof num === 'number') ? num : 1;
    for (n = 0; n < limit; n++){
        particles.push( new Particle(props) );
    }
};

//A couple examples
particles.add({ //Add a single blueFlame
    type: "blueFlame",
    size: 10,
    x: 200,
    y: 200
});

particles.add({ //Add 4 redFlames
    type: "redFlame",
    size: 10,
    x: 300,
    y: 200
}, 4);

particles.add(function(){//Add 4 greenFlames, with randomized XY cooridinates
    this.x = Math.round(Math.random() * 1000);
    this.y = Math.round(Math.random() * 1000);
    this.size = 20;
    this.type = "greenFlame";
}, 4);

Way less code to manage. I'm not sure which way is faster, but I'd bet the speed difference is negligible. Of course, you could check for yourself by making a quick jsPerf.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How do I reuse Threads with different ExecutorService objects?

How do I account for a particle at rest on the ground in a gravity particle simulation?

How do I correctly use 3D Perlin Noise as turbulence for my particle system?

How do i reuse a state?

In System Verilog, how do I use a loop to create an array of objects of a parameterized class?

How do I format an array of objects with ruby?

How do I merge an array of objects in Javascript?

How do i push objects into the same array?

How do I filter on an array of objects in Swift?

How Do I Save an Array of Objects to NSUserDefaults?

How can I do array of objects

How do I map an array of objects

How do I create an Array of Objects in C?

How do I set listeners on an array of objects?

How do I sort an array of post objects?

How do I format timestamp in array of objects?

In Elastic search, how do I match by multiple objects in an array of objects?

How do i spread the objects inside an array of objects?

How do I group multiples of an array of json objects into new objects?

How do I declare the objects having array of objects in JavaScript?

In an array of Objects, how do I return all Objects by property in React?

How do I match by all objects in an array of objects in Elasticsearch?

How to get one of the particle system?

How to stop particle system with a timer?

How Do I Destroy Finished Walking Particle (Clones) in UNITY?

How do i run a particle design on my laptop?

How do I Make Particle Object follow Mouse Movement

How do I assign an array of objects to an empty array in a Vue component?

How do I extract an object(array) from an array of objects?