এখন পর্যন্ত এই অনুশীলনীতে আমরা অবজেক্ট অরিয়েন্টেড (object-oriented) নীতি ব্যবহার করে, কোড গঠন করছিলাম যেন আমরা কণাগুচ্ছকে (particle) নিয়ন্ত্রণ করতে পারি। হয়তো লক্ষ্য করা হয়নি, কিন্তু আগের অনুশীলনীটিতে আমরা এই প্রক্রিয়াটি নিয়ে কাজ করার সময় অনিচ্ছাকৃতভাবে কয়েক ধাপ পেছনে গিয়েছিলাম। সাধারণ কণা অবজেক্টের কন্সট্রাক্টরটি (constructor) পরীক্ষা করে দেখা যাকঃ
var Particle = function(position) {
  this.acceleration = new PVector(0, 0.05);
  this.velocity = new PVector(random(-1, 1), random(-1, 0));
  this.position = new PVector(position.x, position.y);
  this.timeToLive = 255.0;
};
এখন update() পদ্ধতিটির দিকে লক্ষ্য করিঃ
Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
  this.timeToLive -= 2;
};
এখানে লক্ষ্য করলে দেখা যায় যে, এখানে ত্বরণ ধ্রুবক, আর এটা কখনই কন্সট্রাক্টরের বাইরে থাকে না। একটি ভালো উপায় হল, নিউটনের দ্বিতীয় সূত্রটি অনুসরণ করা (F, with, vector, on top, equals, M, A, with, vector, on top) এবং বল সঞ্চয়ন অ্যালগোরিদম এটার সাথে একত্রীভূত করা যা নিয়ে আমরা বল সংক্রান্ত অনুশীলনীতে কাজ করেছি।
প্রথম ধাপটি হল, একটি applyForce() মেথড যোগ করা। (এখানে মনে রাখা দরকার যে, আমাদের PVector কে ভর দিয়ে ভাগ করার আগে PVector এর একটি কপি তৈরি করতে হবে।)
Particle.prototype.applyForce = function(force) {
  var f = force.get();
  f.div(this.mass);
  this.acceleration.add(f);
};
এটা পাওয়ার পর, আমরা update() এর শেষে আরও এক লাইন কোড যোগ করে ত্বরণকে বাদ দিতে পারি।
Particle.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
  this.acceleration.mult(0);
  this.timeToLive -= 2.0;
};
অর্থাৎ, আমাদের কাছে এমন একটি Particle (কণা) অবজেক্ট আছে, যার উপর আমরা বল প্রয়োগ করতে সক্ষম হবো। তাহলে এই applyForce() ফাংশনটিকে আমরা এখন কোথায় কল করব? এই কোডের ভেতরে কোথায় একটি কণার উপরে বল প্রয়োগ করা সঠিক হবে? সত্য ব্যাপারটি হল, এর উত্তর সঠিক কিংবা ভুলের কোন ব্যাপারই এখানে নেই; এটা আসলে একটি নির্দিষ্ট প্রোগ্রামের যথাযথ কার্যকারিতা এবং লক্ষ্যের উপরে নির্ভর করে। তারপরেও আমরা সাধারণ একটি অবস্থা তৈরি করতে পারি যা বেশিরভাগ ক্ষেত্রে প্রয়োগ করা যায় এবং একই সাথে একটি ব্যবস্থার মধ্যে থাকা প্রত্যেকটি কণার উপরে বল প্রয়োগ করার মডেল তৈরি করতে পারি।

বায়ু (wind) সংযুক্তকরণ

এখন নিচের লক্ষ্যটি বিবেচনা করে দেখা যাকঃ সকল কণার উপর প্রতিবার draw() ফাংশনটি ব্যবহার করার মাধ্যমে বল প্রয়োগ করা। আমরা একটি সাধারণ বায়ুর (wind) মত বল ব্যবহার করবো যেটা পার্টিকেলকে ডানদিকে ধাক্কা দিয়ে সরিয়ে দিবেঃ
var wind = new PVector(0.4, 0);
আমরা সবসময় বলেছি, এটাকে draw() ফাংশনের ভিতরে প্রয়োগ করা উচিৎ, তাহলে এখন draw() ফাংশনটি দেখা যাক।
draw = function() {
  background(168, 255, 156);
  particleSystem.addParticle();
  particleSystem.run();
};
আসলে, এখানে ছোট একটি সমস্যা আছে। applyForce() হল একটি মেথড Particle অবজেক্টের ভিতরে লেখা থাকে, কিন্তু আমাদের কাছে ঐ কণার আলাদাভাবে কোন উল্লেখ নেই, শুধুমাত্র ParticleSystem এর অবজেক্টে: particleSystem চলকের উল্লেখ রয়েছে।
আমরা চাই যেন সকল কণা এই বল অনুভব করে, যাই হোক, আমরা এই বলটি কণা ব্যবস্থায় (particle system) প্রয়োগ করতে পারি এবং এই ব্যবস্থাই সামগ্রিকভাবে সকল কণার উপর বল প্রয়োগ করতে পারে।
draw = function() {
  background(168, 255, 156);
  particleSystem.applyForce(wind);
  particleSystem.addParticle();
  particleSystem.run();
};
অবশ্যই, ParticleSystem অবজেক্টের draw() এ নতুন একটি ফাংশন কল করলে, আমাদের ঐ ফাংশনটিকে ParticleSystem অবজেক্টের ভেতরে লিখতে হবে। এই ফাংশনের যে কাজটি সম্পাদন করতে হবে সেটা বর্ণনা করা যাক: PVector হিসেবে একটি বল গ্রহণ করবে এবং সকল কণার উপরে এটি প্রয়োগ করবে।
এটার কোড নিম্নরূপঃ
ParticleSystem.prototype.applyForce = function(f){
  for(var i = 0; i < this.particles.length; i++){
    this.particles[i].applyForce(f);
  }
};
এই ফাংশনটির কোড দেখতে খুবই অদ্ভুত। আমরা চাই “একটি সম্পূর্ণ কণা ব্যবস্থা উপরে বল প্রয়োগ করলে সেটা যেন কণা ব্যবস্থার অধীনে সকল কণার উপর এককভাবে বল প্রয়োগ করতে পারে।” আসলেই কাজটি যুক্তিযুক্ত। কারণ, ParticleSystem অবজেক্টটি কণাগুলো পরিচালনা করার কাজে নিয়োজিত, তাই আমরা যদি কণাগুলো নিয়ে কাজ করতে চাই, তাহলে আমাদেরকে এই পরিচালকের মাধ্যমেই কাজ করতে হবে।
এখন সংক্ষেপে আমরা এভাবে বলতে পারি। বায়ুর বল পরিবর্তন করে দেখা যাক এটা কিভাবে কণার গতির উপর প্রভাব ফেলে এবং একই সাথে বিভিন্ন ভরের কণার উপরে এই বলের প্রভাবের বিভিন্নতা লক্ষ্য করি। বিষয়টি নিয়ে চিন্তা করা যাক।

মহাকর্ষীয় বল (gravity) সংযুক্তকরণ

এখন আরও জটিল একটি বল নিয়ে কাজ করা যাক আর সেটা হল মহাকর্ষ (gravity), যেটা বায়ুর বল থেকে আলাদা কারণ মহাকর্ষ বস্তুর ভরের উপর নির্ভরশীল।
দুইটি বস্তুর মহাকর্ষীয় বল পরিমাপ করার সমীকরণটি দেখা যাকঃ  Fg=Gm1m2r2r^ \vec{F_g} = \frac{Gm_1m_2}{||r||^2} \hat{r}
আমরা যখন পৃথিবীর মহাকর্ষ বলের মডেল তৈরি করেছিলাম তখন বলেছিলাম যে, পৃথিবীর মহাকর্ষ বল অন্য যে কোন মহাকর্ষীয় বল থেকে অনেক বেশি, এজন্য আমরা শুধুমাত্র পৃথিবী এবং বস্তুটির মহাকর্ষ বল হিসাব করছি। G এবং m, start subscript, 1, end subscript প্রতিটি কণার জন্য সমান এবং r (পৃথিবী থেকে ব্যাসার্ধ) মূলত সমান হয়ে থাকে (যেহেতু পৃথিবীর ব্যাসার্ধ, অন্য যে কোন কণার চেয়ে অনেক বড়), তাই আমরা এই জিনিসগুলোকে একদম সরল করি লিখতে পারি, g, যা হল পৃথিবীর মহাকর্ষের ধ্রুবক:
g, equals, start fraction, G, m, start subscript, 1, end subscript, divided by, vertical bar, vertical bar, r, vertical bar, vertical bar, start superscript, 2, end superscript, end fraction
এখন মহাকর্ষীয় বল হল একটি ধ্রুবক g, গুণ কণাগুলোর ভর, গুণ একক ভেক্টর যা বলের দিকে ক্রিয়া (যেটা সবসময়ই নিচের দিকে যেতে থাকবে) করেঃ
Fg=gm2r^ \vec{F_g} = g m_2 \hat{r}
কোডে এর অর্থ হল, প্রতিটি কণার ভরের উপর ভিত্তি করে, আলাদা আলাদা মহাকর্ষীয় বল কণাগুলোর উপর প্রয়োগ করতে হবে। আমরা এটা কিভাবে করতে পারি? আমরা বিদ্যমান applyForce ফাংশনটি পুনরায় ব্যবহার করতে পারি না, কারণ এটা সবগুলো কণার উপরে সমান বল প্রয়োগ করে থাকে। ভর দিয়ে গুণ করার জন্য আমরা applyForce ফাংশনে একটি প্যারামিটার প্রবেশের কথা ভেবে দেখতে পারি, কিন্তু এখন এই ফাংশনটি বাদ দিয়ে নতুন একটি ফাংশন তৈরি করা যাক, applyGravity ফাংশন, যা সার্বজনীন ধ্রুবক ভেক্টরের উপর ভিত্তি করে বল হিসাব করেঃ
// একটি ধ্রুব ভেক্টর, যা শুরুতেই তৈরি করা হয়
var gravity = new PVector(0, 0.2);
ParticleSystem.prototype.applyGravity = function() {
    for(var i = 0; i < this.particles.length; i++) {
        var particleG = gravity.get();
        particleG.mult(this.particles[i].mass);
        this.particles[i].applyForce(particleG);
    }
};
এখন এটা আমরা যদি সঠিকভাবে করতে পারি, তাহলে আমাদের সকল কণাগুলো নিচে দেখানো সিমুলেশনের মত সমান হারে নিচে পড়বে। কারণ মহাকর্ষীয় বল, ভরের (mass) গুণের উপর ভিত্তি করে নির্ণয় করা হয়। কিন্তু ত্বরণ নির্ণয় করা হয় ভরকে ভাগ করার মাধ্যমে, তাই অবশেষে দেখা যায় যে, বস্তুর ভরের কোন প্রভাব এগুলোর উপরে থাকে না। এটা অর্থহীন বলে মনে হয় যে, এত প্রচেষ্টা করে একটি কাজ শেষ করার পরে দেখা গেল যে কাজটির উপরে এর কোন প্রভাবই থাকছে না, কিন্তু আমরা যখন বিভিন্ন ধরনের ফোর্স বা বলকে একসাথে করব তখন এই অর্থহীন কাজটিই বিশাল গুরুত্বপূর্ণ হয়ে উঠবে।

বিকর্ষক (repeller) সংযুক্তকরণ

এখন আমরা যদি এই উদাহরণটিকে আরও এক ধাপ সামনে এগিয়ে নিয়ে একটি বিকর্ষক (repller) অবজেক্ট যোগ করতে চাই যেটা কণাগুলোর কাছে আসলে কণাগুলো এর থেকে দূরে সরে যায়, তাহলে কি করবো? এটা অনেকটা আমাদের আগে অনুশীলন করা আকর্ষকের মত হবে, যেটা বিপরীত দিকে বস্তুগুলোকে সরিয়ে দিত। আবারও, এটা মহাকর্ষের মতই, প্রতিটি কণার জন্য আমাদেরকে আলাদাভাবে বল হিসাব করতে হবে, কিন্তু বিকর্ষণের ক্ষেত্রে ব্যতিক্রমটি হল, হিসাবটি ভরের উপরে ভিত্তি করে হয় না, হিসাবটি করা হয় দূরত্বের উপরে ভিত্তি করে। মহাকর্ষের ক্ষেত্রে সকল বলের ভেক্টর একই দিকে যায়, কিন্তু বিকর্ষকের ক্ষেত্রে আমাদের কাছে যে বল থাকবে সেগুলো বিভিন্ন দিক নির্দেশ করবেঃ
মহাকর্ষীয় বল: সবগুলো ভেক্টর একই দিকে নির্দেশ করবে
বিকর্ষক বল: সবগুলো ভেক্টর বিভিন্ন দিকে নির্দেশ করবে
যেহেতু বিকর্ষক বলের হিসাব, মহাকর্ষ বলের হিসাব থেকে একটু বেশি জটিল (এবং শেষে আমরা বেশ কয়েকটি বিকর্ষক চাই!), তাই আমরা কণা ব্যবস্থায় এই সমস্যাটি সমাধান করবো একটি নতুন বিকর্ষক অবজেক্ট যোগ করার মাধ্যমে এবং একই সাথে মহাকর্ষের উদাহরণটিও থাকবে। আমাদের কোডে দুইটি বড় ধরণের পরিবর্তন করতে হবে:
  1. একটি Repeller (বিকর্ষক) অবজেক্ট (সংজ্ঞায়িত, সক্রিয় এবং প্রদর্শিত হবে)।
  2. একটি ফাংশন যা Repeller অবজেক্টকে ParticleSystem পাঠায়, যাতে এটি প্রতিটি Particle অবজেক্টের উপর বল প্রয়োগ করতে পারে।
var particleSystem = new ParticleSystem(new PVector(width/2, 50));
var repeller = new Repeller(width/2-20, height/2);
var gravity = new PVector(0, 0.1);

draw = function() {
  background(214, 255, 171);

  // Apply gravity force to all Particles
  particleSystem.applyForce(gravity);
  particleSystem.applyRepeller(repeller);
  repeller.display();
  particleSystem.addParticle();
  particleSystem.run();
};
প্রদর্শন করা যায় এমন একটি Repeller অবজেক্ট তৈরি করা সহজ; এটি হল আমাদের আগে তৈরি করা Attractor অবজেক্টের অনুলিপি:
var Repeller = function(x, y) {
  this.position = new PVector(x, y);
};

Repeller.prototype.display = function() {
  stroke(255);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 32, 32);
};
সবচেয়ে কঠিন প্রশ্নটি হল, এখানে আমরা কিভাবে applyRepeller() মেথডটি লিখতে পারি? একটি ফাংশনে applyForce() মত PVector প্রবেশ করানোর পরিবর্তে, আমরা applyRepeller() এ একটি Repeller অবজেক্ট প্রবেশ করাবো এবং ফাংশনটিকে বিকর্ষক এবং সকল কণার মধ্যেকার বল হিসাব করার নির্দেশ দেবোঃ
ParticleSystem.prototype.applyRepeller = function(r) {
  for(var i = 0; i < this.particles.length; i++){
    var p = this.particles[i];
    var force = r.calculateRepelForce(p);
    p.applyForce(force);
  }
};
সবচেয়ে বড় যে পরিবর্তনটি এখানে দেখা যাচ্ছে সেটা হল প্রতিটি কণার জন্য একটি নতুন বল হিসাব করা হচ্ছে, আর আমরা আগে যেটা দেখেছি যে, বিকর্ষকের সাথে প্রতিটি কণার সম্পর্কের উপর ভিত্তি করে বল ভিন্ন হয়ে থাকে। আমরা বল হিসাব করি calculateRepelForce ফাংশনটি ব্যবহার করে, যেটা Attractor এর calculateAttractionForce ফাংশনের বিপরীত।
Repeller.prototype.calculateRepelForce = function(p) {
  // বলের দিক নির্ণয়
  var dir = PVector.sub(this.position, p.position); 
  // অবজেক্টগুলোর মধ্যে দূরত্ব
  var d = dir.mag();
  // নরমালাইজ দিক নির্দেশক ভেক্টর (দূরত্ব দরকার নেই, শুধু দিকের জন্য এই ভেক্টর প্রয়োজন)
  dir.normalize();
  // উপযুক্ত দূরত্ব বজায় রাখা
  d = constrain(d, 1, 100);    
  // বিকর্ষক বল দূরত্বের ব্যাস্তানুপাতিক
  var force = -1 * this.power/ (d * d);     
  // বলের ভেক্টর --> মান * দিক
  dir.mult(force);                                  
  return dir;
};
লক্ষ্য করি যে একটি বিকর্ষক সংযুক্তকরণের সম্পূর্ণ প্রক্রিয়াতে আমরা একবারের জন্যও Particle অবজেক্টটি সম্পাদনার কথা বিবেচনা করি নাই। একটি কণা তার আশপাশের পরিবেশ সম্পর্কে বিস্তারিতভাবে জানার কোন প্রয়োজন নেই; শুধুমাত্র এর অবস্থান (location), বেগ (velocity) এবং ত্বরণ (acceleration) ব্যবহার করতে পারলেই হল এবং একই সাথে বাইরের একটি বল গ্রহণ করার ক্ষমতা থাকতে হবে, আর এটার সাপেক্ষে কাজ করার ক্ষমতাও থাকতে হবে।
আমরা এখন তাহলে এই উদাহরণটি সম্পূর্ণভাবে দেখতে পারি। এই কণাগুলোর কাজ করা বল পরিবর্তন করে দেখা যাক- মহাকর্ষ এবং বিকর্ষক - দেখা যাক এটা বলগুলোর উপর কিরূপ প্রভাব ফেলতে পারেঃ