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

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

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

Движение на вектор

Всичката тази математика с вектори звучи като нещо, което е добре да знаем, но защо? Как на практика ще ни помогне да пишем код? Истината е, че трябва да имаме малко търпение. Ще мине известно време, преди да напълно да осъзнаем колко е яко, че можем да използваме класа PVector.
Това всъщност e често срещано явление, когато за първи път ти се наложи да изучаваш нова структура от данни. Например, когато за първи път учиш какво е масив, може да ти изглежда като много повече работа да използваш масиви, отколкото да имаш просто няколко променливи, заместващи множество от неща. Но тази стратегия бързо рухва, когато имаш нужда от сто, или хиляда, или десет хиляди неща.
Същото важи и за PVector. Това, което може би изглежда като повече работа сега, ще се изплати по-късно и то доста. И не е нужно да чакаш твърде дълго, тъй като наградата ти ще дойде в следващата глава.

Скорост

В момента, обаче, ние искаме да се фокусираме върху простотата. Какво означава да програмираме движение с помощта на вектори? Вече видяхме как можем да започнем в примера със скачащата топка. Един обект има местоположение на екрана (където се намира в даден момент), както и скорост (инструкции за това как трябва да се движи от един момент към следващия). Добавяме скорост към местоположението:
location.add(velocity);
И след това начертаваме обект на това местоположение:
ellipse(position.x, position.y, 16, 16);
Първи правила за движение:
  • Добавяме скоростта към местоположението
  • Чертаем обекта на това местоположение
В примера със скачащата топка, всичко от този код се случи вътре във функцията draw на ProcessingJS. Това, което искаме да направим сега, е да капсулираме цялата логика за движение вътре в обекта. По този начин можем да създадем основа за програмирането на движещи се обекти във всички наши ProcessingJS програми.
В този случай ще създадем един общ Mover (движещ се) обект, който ще опише всички неща, които се движат по екрана. И така ние трябва да обмислим следните два въпроса:
  • Какви данни има Mover?
  • Каква функционалност има Mover?
Алгоритъмът от Първите правила за движение ни дава отговори на тези въпроси. Обектът Mover се състои от две парчета данни: местоположение и скорост – и двете са обекти от тип PVector. Можем да започнем, като напишем функция конструктор, която инициализира тези свойства със съответни случайни стойности:
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
Неговата функционалност е също толкова елементарна. Mover трябва да може да се движи и да може да бъде видян. Ще имплементираме тези негови нужди като методи с имена update() (обновяване) и display()(показване). Ще поставим цялата логика на нашия код за движение в update(), а за чертане на обекта – в display().
Mover.prototype.update = function() {
  this.position.add(this.velocity);
};

Mover.prototype.display = function() {
  stroke(0);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 48, 48);
};
Ако обектно-ориентираното програмиране е нещо ново за теб, една негова характеристика тук може да ти изглежда малко объркваща. В крайна сметка започнахме тази глава с обсъждане на PVector. Обектът PVector е шаблон за обектите за местоположение и скорост. Така че какво правят те вътре в още един обект – Mover? Всъщност, това е нещо съвсем нормално. Един обект е просто нещо, което държи данни (и функционалност). Тези данни могат да бъдат числа, низове, масиви или други обекти! Ще срещаме това отново и отново в този курс. Например в ръководство за частици, ще пишем обект, за да опишем система от частици. Данните на обекта ParticleSystem (система от чатици) ще представляват масив от обекти от тип Particle и всеки обект от тип Particle ще има като свои данни няколко PVector обекти!
Нека да довършим Mover обекта, като добавим функция, която да определи какво трябва да направи обектът, когато достигне ръбовете на прозореца. Засега нека да направим нещо елементарно и да го увием около ръбовете:
Mover.prototype.checkEdges = function() {

  if (this.position.x > width) {
    this.position.x = 0;
  } 
  else if (this.position.x < 0) {
    this.position.x = width;
  }

  if (this.position.y > height) {
    this.position.y = 0;
  } 
  else if (this.position.y < 0) {
    this.position.y = height;
  }
};
Сега, когато обектът Mover е готов, можем да разгледаме това, което трябва да направим в нашата основна програма. Първо трябва да декларираме и инициализираме нова инстанция на Mover:
var mover = new Mover();
След това извикваме съответните функции в draw:
draw = function() {
  background(255, 255, 255);

  mover.update();
  mover.checkEdges();
  mover.display(); 
};
Ето го и напълно работещият пример. Опитай да си поиграеш с числата, като закоментираш кода и видиш какво се случва:

Ускорение

Добре. До този момент трябва да сме наясно с две неща: (1) какво е PVector и (2) как използваме PVector вътре в обект, за да проследим местоположението и движението му. Това е една отлична първа стъпка и заслужава леки аплодисменти. Преди да заслужим бурни овации и крещящи фенове обаче, ние трябва да направим още една малко по-голяма стъпка. В крайна сметка, примерът от Първото правило за движение е доста скучен: кръгът никога не ускорява ход, никога не се забавя и никога не завива. За по-интересно движение, движение което се появява в реалния свят около нас, ние трябва да добавим още един PVector към нашия Mover обект – ускорение.
Строгата дефиниция за ускорение, която използваме тук е: степента на изменение на скоростта. Нека помислим върху тази дефиниция за момент. Това понятие ново ли е? Не особено. Скоростта се определя като степента на изменение на местоположението. Реално се получава "многократен" ефект. Ускорението засяга скороста, която от своя страна влияе на местоположението (засега само загатваме, но това влияние ще стане още по-важно в следващата глава, където ще разгледаме как силите влияят на ускорението, което засяга скоростта, която засяга местоположението). В код това изглежда така:
velocity.add(acceleration);
position.add(velocity);
За целите на упражнението, нека от този момент нататък си измислим следното правило. Нека за останалата част от урока да пишем всеки пример, без да променяме стойността на скоростта и местоположението (освен за да ги инициализираме). С други думи целта ни засега е да програмираме движение по следния начин: да измислим алгоритъм за това как да изчислим ускорението и да оставим многократният ефект да си свърши работата. (В интерес на истината, ще намериш причини, поради които да нарушиш това правило, но е важно да онагледим принципите на нашия алгоритъм за движение.) И така, трябва да измислим няколко начина за изчисляване на ускорението:
  1. Постоянно ускорение
  2. Напълно случайно ускорение
  3. Ускорение към мишката
Алгоритъм #1, постоянно ускорение, не е особено интересен, но е най-елементарен и ще ни помогне да започнем да внедряваме ускорението в своя код.
Първото нещо, което трябва да направим е да добавим друго PVector свойство към Mover конструктора, което да представлява ускорението. Ще го инициализираме с (0,001,0,01) и никога няма да променяме тези стойности, тъй като текущият ни алгоритъм постоянно ускорява. Може би си мислиш, "Леле, тези стойности изглеждат ужасно малки!" Точно така, те са доста малки. Важно е да разберем, че нашите стойности за ускорение (измерени в пиксели) ще се натрупват с течение на времето в скоростта, около трийсет пъти в секунда, в зависимост от кадровата честота на скицата. Така че за да поддържаме величината на вектора на скоростта в рамките на разумен диапазон, нашите стойности за ускорение трябва да започнат като доста малки и да останат такива.
var Mover = function() {
  this.position = new PVector(width/2,height/2);
  this.velocity = new PVector(0, 0);
  this.acceleration = new PVector(-0{,}001, 0{,}01);
};
Забележи, че по-горе, започнахме скоростта с 0 – защото знаем, че ще я увеличаваме, докато се изпълнява програмата, благодарение на ускорението. Ще направим това в метода update() :
Mover.prototype.update = function() {
 this.velocity.add(this.acceleration);
 this.position.add(this.velocity);
};
Тъй като непрекъснато увеличаваме скоростта, рискуваме нашите стойности на скороста да станат изключително големи, ако оставим програмата работи достатъчно дълго. Искаме да ограничим скоростта до някакъв максимум. Можем да направим това с помощта на метода limit на PVector, който ограничава вектора до определена величина.
Mover.prototype.update = function() {
 this.velocity.add(this.acceleration);
 this.velocity.limit(10);
 this.position.add(this.velocity);
};
Това означава следното:
Каква величината на скоростта? Ако тя е по-малка от 10, не се безпокой; просто я остави колкото си е. Обаче ако е повече от 10, я намали до 10!
Да разгледаме промените в обекта Mover, завършен с функциите acceleration и limit():
Продължаваме с алгоритъм #2, напълно случайно ускорение. В този случай вместо да инициализираме ускорение в конструктора на обекта, искаме да взимаме ново ускорение с всеки цикъл, т.е. всеки път, когато се извиква методът update().
Mover.prototype.update = function() {
 this.acceleration = PVector.random2D();
 this.velocity.add(this.acceleration);
 this.velocity.limit(10);
 this.position.add(this.velocity);
};
Тъй като случайният вектор е нормализиран, можем да се опитаме да го скалираме според две различни техники:
  1. скалиране на ускорението до константна стойност:
    acceleration = PVector.random2D();
    acceleration.mult(0{,}5);
    
  1. скалиране на ускорението до случайна стойност:
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
Въпреки че това може би изглежда като нещо очевидно, изключително важно е да разбереш, че ускорението не се отнася просто до ускоряване или забавяне на движещ се обект, а по-скоро до всяка промяна във величината или посоката на скоростта. Ускорението се използва за да се насочи един обект и ще се натъкваме на това отново и отново в бъдещите глави, след като започнем да програмираме обекти, които сами вземат решения за това как да се движат по екрана.

Курсът "Компютърни симулации на физични явления" е производeн на "Природата на кода" от Даниел Шифман, използвана от Creative Commons Attribution-NonCommercial 3,0 Unported License.

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

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