03. Vektory
Úloha 1
Urobte skeč, ktorý na začiatku vygeneruje náhodnú pozíciu balónu a náhodný smer. V animácii sa balón pohybuje v tomto smere.

Poloha a smer
Doteraz sme na pamätanie si polohy alebo smeru potrebovali vždy dvojicu premenných:
// Poloha
float x, y;
// Smer
float sx, sy;
A operácie s nimi sme museli robiť samostatne pre x a samostatne pre y:
// Pohyb
x = x + sx;
y = y + sy;
Keď budeme v budúcnosti potrebovať aj 3D súradnice x
,y
,z
, alebo keď budeme mať viacero objektov, ktorých súradnice si potrebujeme pamätať, tak je dosť prácne mať pre každú súradnicu samostatnú premennú a samostatné výpočty. Bolo by fajn vedieť si hodnoty x,y uložiť do jednej premennej. Beztak reprezentujú súradnice jedného predmetu a sú neoddeliteľné.
Čo je vektor?
Presne na toto slúži v matematike tzv. vektor. Je to dvojica čísel (alebo trojica, alebo n-tica), ktoré reprezentujú súradnice. A táto dvojica je spojená do jednej premennej.
Pomocou vektora vieme reprezentovať polohu aj smer.
Tu je napríklad nejaký bod P, ktorý má súradnice x=3
, y=2
:

Štandardne by sme v Processingu zapísali jeho súradnice takto:
float px = 3;
float py = 2;
Pomocou vektora však môžeme polohu bodu P zapísať takto:
PVector p = new PVector(3,2);
PVector
je špeciálny typ premennej. My zatiaľ poznáme int
, float
, String
a teraz už poznáme aj PVector
. Slovo new
sme už videli, keď sme vyrábali nové pole. Tu tiež pomocou neho vyrábame niečo nové, ale je to nový vektor so súradnicami x=3 a y=2.
Podobne vieme zapísať do vektora aj smer. Tu je napríklad nejaký smer posunu o 5 pixelov doprava a 1 pixel nahor:

Po starom by sme to zapísali takto:
float sx = 5;
float sy = -1;
Po novom to zapíšeme kratšie:
PVector s = new PVector(5,-1);
Posunutie o vektor
Keby sme chceli po starom posunúť bod p
v smere s
, zapísali by sme to takto:
px = px + sx;
py = py + sy;
Ale po novom, s použitím vektorom, je to jednoduchšie:
p = PVector.add(p,s);
Príkaz Pvector.add()
funguje ako znamienko +, akurát sčítava celé vektory: x-ové súradnice spolu, y-súradnice spolu, z-súradnice spolu. Takýchto príkazov má PVector
veľa a postupne si ich viaceré ukážeme.
Úloha 1 znova, ale s vektormi
Prepíšeme Úlohu 1 do reči vektorov. Namiesto súradníc x
,y
použijeme vektor poloha
a namiesto smeru sx
,sy
použijeme vektor smer
.
PVector poloha;
PVector smer;
void setup()
{
size(400,400);
poloha = new PVector(random(width), random(height));
smer = new PVector(random(-2,2), random(-2,2));
}
Pohyb polohou zapíšeme pomocou príkazy add()
:
// Pohyb
poloha = PVector.add(poloha,smer);
A keď chceme vykresliť elipsu a potrebujeme sa dostať k jednotlivým súradniciam x a y, aby sme ich dali ako parametre do príkazu ellipse()
, urobíme to takto:
// Vykreslenie
fill(#FF00FF);
ellipse(poloha.x, poloha.y, 40, 60);
Ak chceme pracovať s obidvoma súradnicami naraz, použijeme zápis poloha
.
Ak chceme pracovať len s jednou konkrétnou súradnicou, použijeme zápis poloha.x
.
Úloha 2
Doplňte do predošlej úlohy "zacyklenie" pohybu. Keď balón vyjde von z obrazovky, aby sa vrátil naspäť na opačnej strane:

Operácie s vektormi
Úspora riadkov kódu nie je to jediné, ani to najpodstatnejšie, na vektoroch. Podstatné sú všetky funkcie a operácie s vektormi, ktoré nám Processing ponúka. Predstavíme si niektoré z nich. Všetky funkcie vektorov nájdete v dokumentácii.
Už sme si ukázali posunutie polohy o smer, pomocou funkcie add()
. V nasledujúcej úlohe to využijeme na vyrobenie naháňačky, kde objekt na obrazovke bude naháňať kurzor myši. Základnú prípravu zvládnete aj sami:
Úloha 3
Vytvorte skeč, ktorý obsahuje vektor poloha
a vektor smer
. Poloha je na začiatku nastavená na stred obrazovky. Smer je na začiatku nastavený na 1,0
. V draw() posúvajte polohu o smer a vykresľujte na polohu krúžok. Mal by vám vzniknúť skeč, kde sa krúžok pohybuje doprava:

Toto je len základ. My chceme, aby sa objekt pohyboval smerom ku kurzoru myši a nie stále doprava.

Na to budeme potrebovať vypočítať smer. Pomôžeme si vektormi. Na operácie s vektormi platia dve jednoduché pravidlá.
Sčítanie a odčítanie vektorov
Vektory sa dajú sčítať funkciou Vector.add()
a odčítať zase funkciou Vector.sub()
.
Pre naše využitie, na pohyb polohy v želanom smere nám vystačia dve pravidlá:
Nová poloha = Súčasná poloha + smer

Sčítavanie už poznáme, používame to pri posúvaní polohy v smere.
Smer = cieľ - poloha

Odčítavanie je nové a použijeme to na vypočítanie smeru od polohy ku kurzoru myši. Našim cieľom bude pozícia myši.
Vytvoríme si nový vektor mys
, ktorý bude nastavený na pozíciu myši a následne vypočítame smer ako mys
mínus poloha
.
PVector poloha;
PVector smer;
void setup()
{
size(400,400);
poloha = new PVector(width/2, height/2);
smer = new PVector(1,0);
}
void draw()
{
background(0);
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha);
// Pohyb
poloha.add(smer);
// Vykreslenie
circle(poloha.x, poloha.y, 20);
}
Bodka sa už pohybuje za myšou, ale pohybuje sa tak rýchlo, že okamžite skočí do polohy myši:

Je to preto, že takto vypočítaný smer predstavuje celú dlžku cesty od súčasnej polohy po kurzor myši. Keď teda pohneme polohu o celú túto dĺžku, dostane sa okamžite až do cieľa.
Delenie vektora
Aby sme zachovali smer, ale skrátili dĺžku, môžeme vektor vydeliť. Napríklad desiatimi, takto:
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha); // Toto znamena smer = mys - poloha
smer = PVector.div(smer, 10); // Toto znamena smer = smer / 10;


Alebo môžeme využiť skrátený zápis:
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha).div(10); // Toto znamena smer = (mys-poloha)/10
Pohyb krúžku je už animovaný. Ak by sme chceli ešte jemnejší pohyb, môžeme vydeliť smer
väčším číslom, napríklad 100
:

Takto počítaný smer pohybu, resp. jeho dĺžka, ale spôsobuje, že na začiatku sa krúžok hýbe rýchlo a postupne spomaľuje. Je to logické. Keď je vzdialenosť od myši veľká, je veľká aj stotina tejto vzdialenosti a krúžok sa pohne o veľký kus. Keď je vzdialenosť od myši už malá, tak je malá aj stotina tejto vzdialenosti a krúžok sa pohne o malý kúsok.
Ak by sme chceli rovnomerný pohyb krúžku, musíme si pomôcť ďalšou funkciou.
Normalizácia vektora
Normalizácia je operácia, ktorá z vektora urobí taký vektor, ktorý má rovnaký uhol smerovania, ale má vždy dĺžku 1. Takže bez ohľadu na to, či je myš ďaleko od krúžku, alebo blízko ku krúžku, normalizovaný smer bude vždy rovnako dlhý:
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha).normalize();
Takto znormalizovaný pohyb je už rovnomerný a nemení rýchlosť:

Ak sa nám zdá pohyb pomalý, môžeme znormalizovaný vektor vynásobiť a bude mať väčšiu dĺžku.
Násobenie vektora
Na vynásobenie vektora použijeme funkciu mult()
, napríklad vynásobíme smer tromi:
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha).normalize().mult(3);

Alebo, ak chceme byť dôslední a nemať v kóde žiadne nepotrebné čísla (ako teraz trojku), vytvoríme premennú rychlost
a budeme násobiť smer ňou:
PVector poloha;
PVector smer;
float rychlost = 3;
void setup()
{
size(400,400);
poloha = new PVector(width/2, height/2);
smer = new PVector(1,0);
}
void draw()
{
background(0);
// Vypocitanie smeru
PVector mys = new PVector(mouseX, mouseY);
smer = PVector.sub(mys, poloha).normalize().mult(rychlost);
// Pohyb
poloha.add(smer);
// Vykreslenie
circle(poloha.x, poloha.y, 20);
}
Úloha 4
Presuňte výpočet smeru a pohyb do podprogramu mouseMoved()
, aby sa krúžok pohyboval iba iba vtedy, keď hýbeme myšou.

Úloha 5
Smer aktuálne počítame ako myš mínus poloha. Vymeňte poradie a počítajte smer ako poloha mínus myš. Čo sa zmenilo a prečo?
Zhrnutie
Pomocou vektora vieme do jednej premennej uložiť dve súradnice naraz.
Takto vieme reprezentovať polohu objektu alebo aj smer objektu.
S vektormi vieme vykonávať operácie podobne ako s číslami:
Sčítať dva vektory
a
ab
funkciouPVector.add(a,b)
Odčítať dva vektory
a
ab
funkciouPVector.sub(a,b)
Ak vektor vyjadruje smer, tak je dôležitý nie len uhol smerovania ale aj jeho dĺžka
Vynásobiť dĺžku číslom
c
vieme funkciou.mult(c)
Vydeliť dĺžku číslom
c
vieme funkciou.div(c)
Keď vektor znormalizujeme funkciou
.normalize()
, tak sa jeho dĺžka nastaví na 1.
Všetky operácie s dĺžkou vektora nemenia uhol smerovania. Menia iba dĺžku.
Smer z bodu
p
do bodum
vypočítame ako m-p, tedaPVector.sub(m, p)
.Posun z bodu
p
smeroms
vypočítame ako p+s,tedaPVector.add(p,s)
.
Last updated