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

问题描述 投票:3回答:1

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

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

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

我想在这里实现的是:

在makeParticle函数中,检查粒子数组中是否存在任何“死”粒子,如果有的话可以重复使用它们,或者如果不是,则推送一个新粒子我已经为此创建了一个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?
}
javascript jquery arrays canvas particles
1个回答
0
投票

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

无论如何,足够的pontificating,这就是我将如何做你所要求的(我假设速度是你的主要关注点,所以我只使用原生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.来检查自己

© www.soinside.com 2019 - 2024. All rights reserved.