If you're seeing this message, it means we're having trouble loading external resources on our website.

Ако си зад уеб филтър, моля, увери се, че домейните *. kastatic.org и *. kasandbox.org са разрешени.

Основно съдържание

Системи частици със сили

Досега в тази секция се бяхме фокусирали върху това да структурираме кода си по обектно-ориентиран начин, за да управляваме колекция от частици. Може би забелязах, или пък не, но по време на този процес без да искаме направихме няколко стъпки назад към предишните раздели. Да разгледаме конструктора на нашия прост обект Particle:
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=MA) и да включим алгоритъма за натрупване на сила, върху който работихме толкова усилено в раздела Сили.
Първата стъпка е да добавим метода applyForce(). (Не забравяй, че ни трябва копие от 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()? Къде в кода ни е подходящо да приложим сила към една частица? Истината е, че няма правилен или грешен отговор; това всъщност зависи от точната функционалност и целта на конкретната програма. Все пак можем да създадем обща ситуация, която може да се приложи за повечето случаи, и да създадем модел за прилагане на сили към отделни частици от системата.

Добавяне на вятър

Да разгледаме следната цел: Да приложим сила глобално всеки път чрез метода draw() върху всички частици. Ще започнем, като приложим проста, подобна на вятър сила, която избутва частиците надясно:
var wind = new PVector(0,4, 0);
Казахме, че трябва да се прилага винаги, например в draw(), затова да разгледаме нашата функция draw() в сегашния ѝ вид.
draw = function() {
  background(168, 255, 156);
  particleSystem.addParticle();
  particleSystem.run();
};
Изглежда имаме малък проблем – applyForce() е метод, написан в обекта Particle, но ние нямаме връзка към отделните частици, а само към обекта ParticleSystem: променливата particleSystem.
Тъй като ние искаме всички частици да получат сила, обаче, можем да решим да приложим силата в системата от частици и да я оставим да управлява прилагането на сила за всички отделни частици.
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 отговаря за управлението на частиците, затова, ако искаме да говорим с частиците, трябва да говорим през техния мениджър.
Ето това го всичко заедно. Поиграй си със силата на вятъра и виж как тя се отразява на движението на частиците, забележи как частици с различна маса реагират по различен начин. Помисли защо това е така.

Добавяне на гравитация

Сега да добавим по-сложна сила, гравитацията, която се различава от вятъра, защото се променя според масата на обектите, върху които е приложена.
Да си припомним уравнението за изчисляване на силата на гравитацията между две маси:  Fg=Gm1m2||r||2r^
Спомни си, че, когато моделираме силата на гравитацията на земята, силата, прилагана от земята, надвива всички останали гравитационни сили, така че единственото уравнение, с което работим, е да изчислим силата на гравитацията между земята и обекта. G и m1 са едни и същи за всяка частица, а r (радиусът от земята) на практика е еднакъв (тъй като радиусът на земята е огромен в сравнение с това колко малко частиците могат да се отдалечат от нея), затова обикновено го опростяваме като g, константата за гравитацията на земята:
g=Gm1||r||2
Така, силата на гравитацията е просто някаква константа g, умножена по масата на частиците, умножена по единичен вектор в посока на силата (която винаги е надолу):
Fg=gm2r^
В кода това означава, че ще трябва да приложим различна сила на гравитацията към всяка частица според нейната маса. Как можем да направим това? Можем да преизползваме съществуващата функция 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);
    }
};
Сега, ако сме направили това правилно, всички наши частици трябва да падат с еднаква скорост в симулацията по-долу. Това е така, защото силата на гравитацията се основава на умножение по масата, но ускорението се основава на деление на масата, затова, в крайна сметка, масата няма никакъв ефект. Може би изглежда глупаво да вложим толкова усилия, за да нямаме ефект, но това е важно, когато започнем да комбинираме няколко различни сили.

Добавяне на отблъскващи обекти

Ами ако искаме да стигнем по-далеч с този пример и да добавим обект, който отблъсква частиците, когато се приближат към него? Той ще бъде подобен на обекта за привличане, който създадохме по-рано, но ще отблъсква частиците в обратна посока. Отново, подобно на гравитацията, трябва да изчислим различна сила за всяка частица, но в случая с нашия отблъскващ обект разликата е, че изчислението не се определя от масата, а от разстоянието. За гравитацията всички вектори на посоката имаха една и съща посока, но за отблъскващия предмет всички вектори на силата ще имат различна посока:
Сила на гравитацията: всички вектори имат еднаква посока
Сила на отблъскване: всички вектори на посоката са различни
Тъй като изчислението на силата на отблъскване е малко по-сложно от изчислението на гравитацията (а накрая може да искаме да имаме няколко отблъскващи обекта!), ще решим този проблем като включим нов обект Repeller в нашата система от частици, заедно с примера за гравитацията. Ще ни трябват две главни добавки към нашия код:
  1. Обект Repeller (деклариран, инициализиран и визуализиран).
  2. Функция, която подава обекта Repeller на ParticleSystem, за да може да приложи сила върху всеки обект – частица.
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);

  // Прилагаме силата на гравитацията към всички частици
  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()? Вместо да подаваме PVector на функция, както правим с applyForce(), ще подадем обекта Repeller на applyRepeller() и ще помолим тази функция да свърши цялото изчисление на силата между отблъскващия обект и частиците:
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, която е обратна на функцията calculateAttractionForce от нашия обект Attractor.
Repeller.prototype.calculateRepelForce = function(p) {
  // Изчисляваме вектора на силата между двата обекта
  var dir = PVector.sub(this.position, p.position); 
  // Изчисляваме разстоянието между обектите
  var dist = dir.mag();
  // Оставяме разстояние в разумни граници
  dist = constrain(dist, 1, 100);    
  // Изчисляваме силата на отблъскване,
  // обратно пропорционална на разстоянието на квадрат
  var force = -1 * this.power/ (dist * dist);     
  // Нормализираме вектора на посоката
  // (пренебрегваме информацията за разстоянието)
  dir.normalize();
  // Изчисляваме вектора на силата: посока * големина
  dir.mult(force);                                  
  return dir;
};
Забележи как през целия процес на добавяне на отблъскващ обект към средата не ни се наложи да редактираме самия обект Particle. Всъщност самата частица не е нужно да знае нищо за детайлите от своята среда; тя трябва да управлява само своята позиция, скорост и ускорение, както и да може да получава външна сила и да реагира на тази сила.
Сега можем да погледнем целия пример. Опитай да промениш големината на силите, които действат върху частиците – гравитацията и отблъскването – и виж как това ги променя:

Искаш ли да се присъединиш към разговора?

Все още няма публикации.
Разбираш ли английски? Натисни тук, за да видиш още дискусии в английския сайт на Кан Академия.