지금까지 죽으면 다시 만드는 단일 입자를 생성해 보았습니다. 이젠 draw()를 사용해 매 사이클마다 새로운 입자들을 추가하면서 연속적인 입자의 흐름을 생성하고자 합니다. 배열을 생성하여 새로운 입자를 계속 넣을 수 있습니다:
var particles = [];
draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = 0; i < particles.length; i++) {
    var p = particles[i];
    p.run();
  }
};
코드를 몇 분간 실행시켜보면 프레임 속도가 점점 느려지고 결국엔 멈추게 될 겁니다.' 왜냐하면 처리하고 보여줘야 할 입자를 점점 더 많이 생성하는데 제거하지는 않기 때문입니다. 일단 입자가 죽으면 쓸모가 없기 때문에 그런 입자를 프로그램에서 제거해 불필요한 작업을 하지 않도록 할 수 있습니다.
To remove items from an array in JavaScript, we can use the splice() method, specifying the desired index to delete and number to delete (just one). We'd do that after querying whether the particle is in fact dead:
var particles = [];
draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = 0; i < particles.length; i++) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
};
위의 코드가 잘 수행되더라도 (그리고 중간에 멈추지 않더라도) 중간 규모의 문제가 발생합니다. 배열에서 반복문을 실행하면서 그 배열의 내용을 조작하면 문제가 생길 수도 있습니다. 예로 다음의 코드를 보겠습니다:
for (var i = 0; i < particles.length; i++) {
  var p = particles[i];
  p.run();
  particles.push(new Particle(new PVector(width/2, 50)));
}
이것은 다소 극단적인 (결함있는 논리를 가진) 예제이긴 하나 문제점을 보여줍니다. 위 경우는 배열의 각 입자에 대해 배열에 새로운 입자를 추가합니다 (그 결과 배열의 length를 변경합니다). i가 절대로 particles.length보다 커질 수 없으므로 무한 반복이 발생하게 됩니다.
While removing items from the particles array during a loop doesn’t cause the program to crash (as it does with adding), the problem is almost more insidious in that it leaves no evidence. To discover the problem we must first establish an important fact. When an item is removed from an array, all items are shifted one spot to the left. Note the diagram below where particle C (index 2) is removed. Particles A and B keep the same index, while particles D and E shift from 3 and 4 to 2 and 3, respectively.
반복문 속의 i 가 되었다고 생각해 봅시다.
  • i = 0이면 → 입자 A를 확인합니다. → 삭제하지 않습니다.
  • i = 1이면 → 입자 B를 확인합니다. → 삭제하지 않습니다.
  • i = 2이면 → 입자 C를 확인합니다. → 삭제합니다!
  • (입자 D와 E를 슬롯 3과 4에서 슬롯 2와 3으로 넣습니다.)
  • i = 3이면 → 입자 E를 확인합니다. → 삭제하지 않습니다.
문제를 알아채셨나요? 입자 D를 확인하지 않았습니다! C가 슬롯 #2에서 제거되면 D가 슬롯 #2로 옮겨지지만 i는 슬롯 #3으로 이동합니다. 입자 D는 다음 번에 확인될 것이기 때문에 재앙이 일어나지는 않습니다. 그래도 원래 목표는 모든 항목을 확인하는 코드를 작성하는 것이었습니다. 항목을 건너 뛰는 것은 허용될 수 없습니다.
이 문제는 간단히 해결할 수 있습니다. 배열을 반대로 반복하면 됩니다. 항목이 제거될 때 오른쪽에서 왼쪽으로 항목을 밀어 넣으면 실수로 항목을 건너뛰는 것이 불가능합니다. 해야할 일은 for 반목문에서 세 부분을 수정하는 것입니다:
  for (var i = particles.length-1; i >= 0; i--) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
Putting it all together, we have this:
좋습니다. 이제 두 가지를 했습니다. 개별 입자에 대한 객체를 작성했고 배열을 이용하여 많은 입자 객체들을 관리(마음대로 추가하고 삭제하는 기능)하는 방법을 알았습니다.
여기에서 끝낼 수도 있지만, 입자 객체들의 집합 자체를 다루는 객체 ParticleSystem 객체를 만들어 봅시다. 이 객체를 이용하면 메인 탭에서 입자들을 다루는 복잡한 반복문을 없앨 뿐만 아니라 하나 이상의 입자 시스템을 만들 수 있습니다.
이 단원 처음에 세웠던 목표들을 생각해보면 프로그램이 다음과 같아야 합니다:
var ps = new ParticleSystem(new PVector(width/2, 50));

draw = function() {
  background(0, 0, 0);
  ps.run();
};
위에 작성한 프로그램을 어떻게 ParticleSystem 객체로 표현할 수 있을지 알아봅시다.
다음은 전에 작성한 코드입니다. 굵게 표시된 부분을 주의 깊게 보기 바랍니다:
var particles = [];

draw = function() {
  background(133, 173, 242);
  particles.push(new Particle(new PVector(width/2, 50)));

  for (var i = particles.length-1; i >= 0; i--) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
};
다음은 이 코드를 어떻게 객체로 다시 쓸 수 있는지 보여줍니다. 입자 배열을 객체의 프로퍼티로 만들고, 새로운 입자를 추가하기 위해 래퍼 메소드인 addParticle을 만들난 후 입자의 움직임에 관한 모든 코드를 run에 넣습니다:
var ParticleSystem = function() {
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  this.particles.push(new Particle());
};

ParticleSystem.prototype.run = function() {
  for (var i = this.particles.length-1; i >= 0; i--) {
      var p = this.particles[i];
      p.run();
      if (p.isDead()) {
        this.particles.splice(i, 1);
      }
    }
};
또한 입자시스템 자체에 새로운 특성을 추가할 수 있습니다. 예를 들어 ParticleSystem 객체가 입자가 만들어진 원점을 기록하게 할 수도 있습니다. 이것은 입자가 생성되고 내보내지는 “에미터”라는 개념에 알맞습니다. 원점은 생성자에서 초기화되어야 합니다.
var ParticleSystem = function(position) {
  this.origin = position.get();
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  this.particles.push(new Particle(this.origin));
};
지금까지 만든 코드는 다음과 같습니다: