এখন পর্যন্ত আমরা একটি একক কণা তৈরি কর‍তে পেরেছি যে কণাগুলো শেষ হয়ে গেলে পুনরায় তৈরি হতে পারে। এখন আমরা অব্যাহত কণার প্রবাহ তৈরি করতে চাই যেটি প্রতিবার একটি নতুন চক্রে draw() এর মাধ্যমে যোগ হবে। প্রতিবার আমরা একটি নতুন অ্যারে তৈরি করে এর মধ্যে নতুন একটি কণা (particle) পাঠিয়ে দিতে পারিঃ
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();
  }
};
যদি এই কোডটি নিয়ে কিছুক্ষনের জন্য চালান হয়, তাহলে সম্ভবত দেখা যাবে যে, প্রোগ্রামটি শেষ না হওয়া পর্যন্ত ফ্রেমের হারটি ধীরে ধীরে কমে যাচ্ছে। কারণ হল আমরা বাদ না দিয়ে আরও নতুন নতুন কণা যোগ করছি যেগুলো প্রদর্শনের জন্য একটি প্রক্রিয়ার সম্পাদন করতে হয়। যখন কণাগুলো নষ্ট হয়ে যায়, সেগুলো ব্যবহারের অযোগ্য হয়ে পড়ে, আমাদের প্রোগ্রামটির যেন অপ্রয়োজনীয় কোন কাজ করা না লাগে তাই ঐ নষ্ট কণাগুলো সরিয়ে ফেলার ব্যবস্থা করতে হবে।
জাভাস্ক্রিপ্টের অ্যারে থেকে কোন কিছু সরিয়ে ফেলার জন্য আমরা splice() মেথড ব্যবহার করতে পারি, এটি ব্যবহার করলে প্রোগ্রামের নির্ধারিত কোন ইনডেক্স এবং সংখ্যা মুছে ফেলা যায় (শুধুমাত্র একটি)। কণাগুলো সত্যিই নষ্ট হয়ে গেছে কিনা তা যাচাই করার পরে আমরা এই কাজটি করব:
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)));
}
এটি মারাত্মক একটি উদাহরণ (ত্রুটিযুক্ত যুক্তিসহ), যা সমস্যাটিকে প্রমান করছে। উপরে উল্লেখিত ক্ষেত্রে, অ্যারেতে থাকা প্রতিটি কণার সাথে আমরা একটি করে নতুন কণা যোগ করবো (এতে অ্যারের দৈর্ঘ্যটি পরিবর্তন হবে)। এর ফলাফল হিসেবে আমরা অসীম একটি লুপ পাব, যেহেতু i কোডের particles.length থেকে বড় হতে পারবে না।
লুপ চলার সময় কণার অ্যারে থেকে কোন জিনিস সরিয়ে নিলে, প্রোগ্রামটি ক্রাশ করবে না (যেমন যোগ করার ক্ষেত্রে হয়), এই সমস্যাটির একটি গুপ্ত সমস্যা, যেটি কোন সূত্র রাখে না। সমস্যাটি বের করার জন্য আমাদের প্রথমেই গুরুত্বপূর্ণ একটি তত্ত্ব বাস্তবায়ন করতে হবে। যখন অ্যারে থেকে কোন জিনিস সরিয়ে নেওয়া হয়, সব জিনিসগুলো তার বামদিকে এক ঘর সরে আসে। নিচের চিত্রটি লক্ষ্য করা যাক, যেখানে particle C (ইনডেক্স 2) কে সরিয়ে নেওয়া হয়েছে। Particles A এবং B একই জায়গায় থাকলেও, Particles C এবং D যথাক্রমে তাদের 3 এবং 4 নম্বর ঘর থেকে বামদিকে সরে 2 এবং 3 নম্বর ঘরে চলে এসেছে।
ধরি i দিয়ে অ্যারেতে লুপ চালান হচ্ছে।
  • যখন i = 0 → particle A যাচাই করা হয় → মুছে ফেলা যাবে না
  • যখন i = 1 → particle B যাচাই করা হয় → মুছে ফেলা যাবে না
  • যখন i = 2 → particle C যাচাই করা হয় → মুছে ফেলা যাক!
  • (particles D এবং E, 3 এবং 4 নম্বর ঘর থেকে 2 এবং 3 নম্বর ঘরে চলে আসবে)
  • যখন i = 3 → particle E যাচাই করা হয় → মুছে ফেলা যাবে না
সমস্যাটি খুঁজে পাওয়া গেল? আমরা কখনই particle D পরীক্ষা করে দেখি নাই! যখন ঘর #2 থেকে C মুছে ফেলা হল, D তখন ঘর #2 এ চলে এলো, কিন্তু ততক্ষনে i ঘর #3 এ চলে গেছে। এটি বড় কোন বিপর্যয় নয়, কারণ পরবর্তীতে প্রোগ্রামটি চালানোর সময় particle D পুনরায় পরীক্ষা করা হবে। আমরা এখন অ্যারেতে থাকা প্রতিটি জিনিস পুনরায় ব্যবহার করার জন্য কোড লিখছি। অ্যারের কোন উপাদান বাদ দেওয়া অগ্রহণযোগ্য।
এই সমস্যাটির সহজ একটি সমাধান আছে: বিপরীত দিক থেকে অ্যারেটি পুনরায় চালানো। অ্যারে থেকে কোন উপাদান ডানদিক থেকে বামদিকে সরিয়ে ফেলার সময় ভুলবশত কোন উপাদান বাদ পড়া অসম্ভব। আমাদের যেটা করতে হবে সেটা হল, লুপে থাকা তিনটি বিট (bits) কিছুটা পরিবর্তন করাঃ
  for (var i = particles.length-1; i >= 0; i--) {
    var p = particles[i];
    p.run();
    if (p.isDead()) {
      particles.splice(i, 1);
    }
  }
এখন সব কোড একসাথে করে পাই:
এখন ঠিক আছে। আমরা এখন পর্যন্ত দুইটি জিনিস সম্পন্ন করেছি। আমরা এমন একটি অবজেক্ট তৈরি করেছি যা একটি Particle (কণা) কে বর্ণনা করে। এখন আমরা, অ্যারে ব্যবহার করে অনেকগুলো Particle অবজেক্টকে পরিচালনা করতে পারি (কণাগুলো নিজের ইচ্ছামত যোগ করতে এবং মুছে ফেলতে পারি)।
আমরা এখানেই থেমে যেতে পারি। কিন্তু, অতিরিক্ত আরও একটি ধাপ আমরা নিতে পারি এবং এটা অবশ্যই করা উচিৎ, যা হল, এমন একটি অবজেক্ট তৈরি করা যা একগুচ্ছ কণা অবজেক্টকে বর্ণনা করে— 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);
    }
  }
};
আমরা এটা কিভাবে একটি অবজেক্টের ভিতরে পুনরায় লিখতে পারি সেটা দেখা যাক - আমরা particles অ্যারেকে অবজেক্টের একটি বৈশিষ্ট্য হিসেবে লিখবো, নতুন কণা যোগ করার জন্য আমরা 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));
};
সব কোড একত্র করে পাইঃ
লোড করা হচ্ছে