如何在JavaScript / jQuery中为粒子系统重用数组中的对象?

时间:2014-04-22 13:00:54

标签: javascript jquery arrays canvas particles

我正在为画布游戏构建实体系统。这开始于一个简单的粒子发射器/更新器,我正在改变它以适应多粒子/实体发生器。虽然我通常可以使用JavaScript / jQuery,但由于它涉及到数组,我遇到了我的经验极限,并会感激地接受以下任何帮助:

当我需要一个新的粒子/实体时,我当前的系统调用一个函数将一个对象推入一个包含实体更新变量的数组。

然后更新函数在数组上运行for循环,检查类型变量以更新粒子(位置/颜色/等...)。以前我会根据某些条件[array.splice]粒子。当我需要更多粒子/实体时,我会推出新的粒子。

我想在这里实现的是:

在makeParticle函数中,检查粒子数组中的任何" dead"粒子,如果有的话可以重复使用它们,或者如果不是,我会推送一个新的粒子我已经为此创建了一个particleAlive var作为标志。

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

我之前找到了相关问题的答案,但我还是无法在makeParticle函数中使用它,比如如何将p的属性赋给粒子[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?
}

1 个答案:

答案 0 :(得分:0)

我个人对此事的看法是,如果你正在制作一个新的粒子,它应该是一个新的对象,而不是一个&#34;重新使用&#34;属性改变的旧的。每个新对象都应该有一个唯一的标识符,因此如果您需要跟踪它们(用于开发目的,调试或以后重新使用),这很容易做到。或者至少保留一个计数器,表明你重新使用粒子对象代表一个新的&#34;粒子!虽然我猜你是否发现&#34;重新使用&#34;提高性能(对吗?),这是最佳选择。

无论如何,足够的教诲,这就是我将如何做你所要求的(我认为速度是你的主要关注点,所以我只用原生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) );
    }
};

现在,我在此推荐这样做:放弃这个想法或者&#34;重新使用&#34;粒子,为每个粒子制作一个单独的构造函数(如果将来向粒子添加方法,将会有很大的帮助),并且每次添加一个粒子时都会丢弃死粒子:

//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);

管理更少的代码。我不确定哪种方式更快,但我敢打赌,速度差异可以忽略不计。当然,您可以通过快速jsPerf.

来检查自己