03. Vektory
Last updated
Last updated
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.
Doteraz sme na pamätanie si polohy alebo smeru potrebovali vždy dvojicu premenných:
A operácie s nimi sme museli robiť samostatne pre x a samostatne pre y:
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é.
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:
Pomocou vektora však môžeme polohu bodu P zapísať takto:
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:
Po novom to zapíšeme kratšie:
Keby sme chceli po starom posunúť bod p
v smere s
, zapísali by sme to takto:
Ale po novom, s použitím vektorom, je to jednoduchšie:
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.
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
.
Pohyb polohou zapíšeme pomocou príkazy add()
:
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:
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
.
Doplňte do predošlej úlohy "zacyklenie" pohybu. Keď balón vyjde von z obrazovky, aby sa vrátil naspäť na opačnej strane:
Ú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:
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á.
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
.
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.
Aby sme zachovali smer, ale skrátili dĺžku, môžeme vektor vydeliť. Napríklad desiatimi, takto:
Alebo môžeme využiť skrátený zápis:
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 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ý:
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.
Na vynásobenie vektora použijeme funkciu mult()
, napríklad vynásobíme smer tromi:
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:
Presuňte výpočet smeru a pohyb do podprogramu mouseMoved()
, aby sa krúžok pohyboval iba iba vtedy, keď hýbeme myšou.
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?
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
a b
funkciou PVector.add(a,b)
Odčítať dva vektory a
a b
funkciou PVector.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 bodu m
vypočítame ako m-p, teda PVector.sub(m, p)
.
Posun z bodu p
smerom s
vypočítame ako p+s,teda PVector.add(p,s)
.