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

标签 javascript jquery arrays canvas particles

我正在为 Canvas 游戏构建实体系统。这从一个简单的粒子发射器/更新器开始,我正在对其进行更改以适应多粒子/实体生成器。虽然我通常可以使用 JavaScript/jQuery,但由于涉及数组,我遇到了经验的限制,并且非常乐意接受以下方面的任何帮助:

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

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

我想在这里实现的是:

在 makeParticle 函数中,检查粒子数组中是否有任何“死”粒子,如果有可用的,则重用它们,如果没有,则推送一个新粒子。为此,我创建了一个 molecularAlive 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?
}

最佳答案

我个人对此事的看法是,如果你要制作一个新粒子,它应该是一个新对象,而不是“重新使用”属性已更改的旧粒子。每个新对象都应该有一个唯一的标识符,因此如果您需要跟踪它们(出于开发目的、调试或以后重用),这很容易做到。或者至少保留一个计数器,记录您重复使用粒子对象来表示"new"粒子的次数!尽管我猜想如果您发现“重用”可以提高性能(是吗?),那就是正确的方法。

无论如何,已经足够武断了,这就是我将如何做你所要求的事情(我认为速度是你主要关心的问题,所以我只用原生 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) );
    }
};

现在,我建议这样做:放弃这个想法或“重复使用”粒子,为每个粒子创建一个单独的构造函数(如果您将来向粒子添加方法,这将有很大帮助),然后报废每添加一个粒子:

//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.来自行检查。

关于javascript - 如何在 JavaScript/jQuery 中为粒子系统重用数组中的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23220403/

相关文章:

javascript - 在 2048 游戏中只向右移动一步

javascript - 使用表中的 jquery 填充选择选项按钮

javascript - Angular 表达式执行顺序(带 ngif 的分层 div)似乎未按预期工作

javascript - Google map 上的自定义标记。 (适用于Iphone)

javascript - 创建键匹配的数组

javascript - 具有最大数字索引的元素

javascript - 递增字符串中的字母 - 在不使用 .charCodeAt(0) 的情况下将 char 视为 int

java - 数组作为 Volley POST 请求参数

javascript - Mongoose 从对象数组中的对象值返回数组,无需 JS 工作

javascript - 模式中的按钮不起作用