Inspirat de prof. Wildberger în seria de lecții despre algebra liniară, intenționez să pun în practică ideile sale matematice cu Flash. Nu trebuie să ne îndreptăm spre manipularea matematică a matricelor prin algebra liniară: doar prin vectori. Această înțelegere, deși diluează eleganța algebrei liniare, este suficientă pentru a ne lansa în câteva posibilități interesante de manipulare a matricei 2x2. În special, îl vom folosi pentru a aplica diferite efecte de forfecare, înclinare, răsturnare și scalare a imaginilor în timpul rulării.
Să aruncăm o privire asupra rezultatului final la care vom lucra. Apăsați cele patru taste direcționale - sus, jos, stânga, dreapta - pentru a vedea unele efecte pe care le putem obține cu transformările afine.
Dacă utilizați doar tastele săgeată stânga și dreapta, peștele pare să înoate în jurul unui spațiu izometric pseudo-3D.
Grafica este desenată pe spații de coordonate. Deci, pentru a le manipula, mai ales pentru a traduce, a roti, a scala, a reflecta și a scoate grafica, este vital să înțelegem spațiile de coordonate. În general, folosim nu doar unul, ci mai multe spații de coordonate într-un singur proiect - acest lucru este valabil nu numai pentru designerii care folosesc Flash IDE, dar și pentru programatorii care scriu ActionScript.
În Flash IDE acest lucru se întâmplă de fiecare dată când convertiți desenele în simboluri MovieClip: fiecare simbol are propria sa origine.
Imaginea de mai sus arată originea spațiului de coordonate al scenei (punct roșu) și cel al spațiului de coordonate al simbolului (punctul de înregistrare marcat de crosshair). Pentru a afla care spațiu sunteți în prezent, observați bara de sub cronologia Flash IDE, după cum arată imaginea de mai jos.
(Folosesc Flash CS3, așadar locația sa poate diferi pentru CS4 și CS5.) Ceea ce vreau să subliniez este existența unor spații de coordonate diferite și faptul că deja sunteți familiarizat cu utilizarea acestora.
Acum există un motiv bun pentru asta. Putem folosi un spațiu de coordonate ca referință pentru a schimba celălalt spațiu de coordonate. Acest lucru poate părea străin, așa că am inclus prezentarea Flash de mai jos pentru a facilita explicația mea. Dați clic și trageți pe săgețile roșii. Joacă-te cu el.
În fundal este o rețea albastră, iar în prim-plan este o rețea roșie. Săgețile albastre și roșii sunt aliniate inițial de-a lungul axelor x și y ale spațiului de coordonate Flash, al cărui centru am deplasat spre mijlocul scenei. Grilă albastră este o rețea de referință; linia de grilă nu se va schimba în timp ce interacționați cu săgețile roșii. Pe de altă parte, grila roșie poate fi reorientată și scalată prin glisarea săgeților roșii.
Rețineți că săgețile indică, de asemenea, o proprietate importantă a acestor grile. Acestea indică noțiunea de unitate de x și o unitate de y pe grila lor respectivă. Există două săgeți roșii pe grila roșie. Fiecare dintre ele indică lungimea unei unități pe axa x și axa y. De asemenea, dictează orientarea spațiului de coordonate. Să luăm săgeata roșie îndreptată de-a lungul axei x și să o extindem de două ori mai mult decât săgeata originală (afișată în albastru). Observați următoarele imagini.
Vedem că imaginea (cutia verde) desenată pe grila roșie este acum întinsă orizontal, datorită faptului că această grilă roșie pe care este trasată este acum de două ori mai lată. Punctul pe care încerc să îl fac este destul de simplu: puteți utiliza un spațiu de coordonate ca bază pentru a schimba un alt spațiu de coordonate.
Deci, ce este un "spațiu coordonat affine"? Sunt sigur că ești suficient de atent să observați că aceste spații de coordonate sunt desenate folosind grilaje paralele. Să luăm de exemplu spațiul roșu afins: nu există nici o garanție că atât axa x cât și axa y sunt întotdeauna perpendiculare între ele, dar trebuie să fiți siguri că, oricum încercați să modificați săgețile, nu veți ajunge vreodată la un astfel de caz ca mai jos.
De fapt, axele x și y se referă de obicei la spațiul de coordonate cartezian, după cum se arată mai jos.
Rețineți că grilele orizontale și verticale sunt perpendiculare unele pe altele. Cartesianul este a tip de spațiu coordonat afine, dar îl putem transforma în alte spații afinice după cum preferăm. Grilele orizontale și verticale nu trebuie neapărat să fie perpendiculare între ele.
După cum probabil ați ghicit, transformările afine sunt traducerea, scalarea, reflexia, înclinarea și rotația.
Inutil să spun, proprietăți fizice, cum ar fi x, y, scaleX, scaleY
și rotație
depinde de spațiu. Când facem apeluri la acele proprietăți, transformăm coordonatele afine.
Sper ca imaginile de mai sus să fie suficient de explicit pentru a conduce ideea. Acest lucru se datorează faptului că, pentru un programator care lucrează cu FlashDevelop, nu vom vedea acele grile pe care Flash IDE le afișează convenabil pentru designeri. Toate acestea trebuie să trăiască în capul tău.
În afară de imaginarea acestor rețele, trebuie, de asemenea, să ne căutăm ajutorul Matrice
clasă. Astfel, având o înțelegere matematică a matricelor este importantă, deci vom revizui operațiile matricei aici: adăugarea și multiplicarea.
Operațiunile Matrix convery semnifică geometric. Cu alte cuvinte, puteți vedea ce înseamnă ei pe un grafic. Să presupunem că avem patru puncte în spațiul nostru coordonat și dorim să le schimbăm într-un set de locații noi. Acest lucru se poate face folosind adăugarea de matrice. Verificați imaginea de mai jos.
După cum puteți vedea, schimbăm întregul spațiu local de coordonate (grilaje roșii) unde sunt extrase aceste patru puncte. Notatia pentru efectuarea acestor operatiuni este prezentata mai jos:
De asemenea, putem vedea că această schimbare poate fi reprezentată de fapt folosind un vector de (tx, ty). Să distingem vectorii și punctele statice în spațiile de coordonate prin folosirea parantezelor și a parantezelor pătrate. Le-am rescris în imaginea de mai jos.
Iată o implementare simplă a adăugării de matrice. Verificați comentariile:
publicarea clasei publice extinde Sprite funcția publică Addition () var m: Matrix = new Matrix (); // instantiate matrice m.tx = stage.stageWidth * 0.5; // schimbare în x m.ty = stage.stageHeight * 0.5; // schimbă în y var d: DottedBox = nou DottedBox (); // crea grafica particularizata (cutie punctata este Sprite) addChild (d); d.transform.matrix = m; // aplicați matricea graficului nostru
Matricea multiplicării este oarecum mai sofisticată decât adăugarea de matrice, dar Prof. Wildberger a distrus elegant această interpretare simplă. Voi încerca cu umilință să reiterez explicația lui. Pentru cei care ar dori să se scufunde mai adânc în înțelegerea algebrei liniare care duce la acest lucru, verificați seria de prelegeri a profesorului.
Să începem prin abordarea cazului matricei de identitate, eu.
Din imaginea de mai sus știm că înmulțind o matrice arbitrară, A, prin matricea identității, voi produce întotdeauna A. Iată o analogie: 6 x 1 = 6; matricea de identitate este asemănătoare cu numărul 1 în această multiplicare.
Alternativ, putem scrie rezultatul în următorul format vectorial care ne va simplifica foarte mult interpretarea:
Interpretarea geometrică a acestei formule este prezentată în imaginea de mai jos.
Din grila carteziană (grila din stânga), vedem punctul albastru situat la (2, 1). Acum, dacă am transforma această rețea originală de x și y într-o nouă rețea (grila dreaptă) conform unui set de vectori (sub grila dreaptă), punctul albastru va fi mutat la (2, 1) pe grila nouă - dar când o reintrăm la grila originală, este același lucru ca înainte.
Pentru că transformăm grila originală într-o altă rețea care împarte aceleași vectori pentru x și y, nu vedem nicio diferență. De fapt, modificările lui x și y în această transformare sunt zero. Asta însemna asta matrice de identitate, din punct de vedere geometric.
Totuși, dacă încercăm să realizăm o cartografiere folosind alte transformări, vom vedea o diferență. Știu că acest lucru nu a fost cel mai revelator exemplu pentru a începe, deci hai să trecem la un alt exemplu.
Imaginea de mai sus demonstrează o scalare a spațiului de coordonate. Verificați vectorul lui x în spațiul de coordonate transformat: o unitate a x transformat contabilizează două unități ale originalului x. Pe spațiul transformat al coordonatelor, coordonatele punctului albastru sunt încă (2, 1). Cu toate acestea, dacă încercați să cartografiați această coordonată din grila transformată pe grila originală, aceasta este (4, 1).
Această idee este captată de imaginea de mai sus. Ce zici de formula? Rezultatul ar trebui să fie consecvent; Hai să verificăm.
Sunt sigur că vă amintiți aceste formule. Acum, am adăugat semnificațiile lor respective.
Acum, pentru a verifica rezultatul numeric al exemplului nostru de scalare.
Ei sunt de acord între ei! Acum putem să aplicăm cu plăcere această idee altor transformări. Dar înainte de aceasta, o implementare ActionScript.
Consultați implementarea ActionScript (și SWF-ul rezultat) de mai jos. Rețineți că una dintre casetele suprapuse este întinsă de-a lungul x de o scală de 2. Am evidențiat valorile importante. Aceste valori vor fi modificate în etapele ulterioare pentru a reprezenta diferite transformări.
clasa publica Multiplicarea extinde Sprite functie publica Multiplicare () var ref: DottedBox = nou DottedBox (); // crea graficul de referință addChild (ref); ref.x = stage.stageWidth * 0.5; ref.y = stage.stageHeight * 0.5; var m: Matrice = Matrice nouă (); // instantiate matrice m.tx = stage.stageWidth * 0.5; // schimbare în x m.ty = stage.stageHeight * 0.5; // deplasare în y m.a = 2; m.c = 0; m.b = 0; m.d = 1; var d: DottedBox = nou DottedBox (); // creați grafica personalizată addChild (d); d.transform.matrix = m // aplicați matricea pe graficul nostru
Aici am scalat grilele cu un factor de doi de-a lungul ambelor axe x și y. Punctul albastru este la (2, 1) în grila originală înainte de transformare și (4, 2) în grila originală după transformare. (Desigur, este încă la (2, 1) în nou grilă după transformare.)
Și pentru a confirma rezultatul numeric ...
... se potrivesc din nou! Pentru a vedea acest lucru în implementarea ActionScript, trebuie doar să modificați valoarea m.d
de la 1 la 2.
(Rețineți că direcția de întindere de la y este în jos, nu în sus, deoarece y crește în jos în Flash, dar în sus în spațiul normal de coordonate carteziene pe care l-am folosit în diagramă.)
Aici am reflectat grila de-a lungul axei x folosind aceste două vectori, astfel încât poziția punctului albastru din grila originală se modifică de la (2, 1) la (-2, 1). Calculul numeric este după cum urmează:
Implementarea ActionScript este identică cu cea precedentă, dar utilizează în schimb aceste valori: m.a = -1, m.b = 0
pentru a reprezenta vectorul pentru transformarea x și: m.c = 0 și m. d = 1
pentru a reprezenta vectorul pentru transformarea y.
În continuare, ce zici de a reflecta simultan pe x și y? Verificați imaginea de mai jos.
De asemenea, calculat numeric în imaginea de mai jos.
Pentru implementarea ActionScript ... bine, sunt sigur că știți valorile pe care trebuie să le puneți în matrice. m.a = -1, m.b = 0
pentru a reprezenta vectorul pentru transformarea x; m.c = 0 și m. d = -1
pentru a reprezenta vectorul pentru transformarea y. Am inclus SWF-ul final de mai jos.
Tăblirea vine cu puțină distracție. În cazul imaginii de mai jos, grila transformată a avut reorientarea și scalarea axei sale x. Comparați săgețile roșii din ambele grile de mai jos: ele sunt diferite, dar axa y rămâne neschimbată.
Din punct de vedere vizual, se pare că distorsiunea se întâmplă de-a lungul direcției y. Acest lucru este adevărat deoarece axa noastră x transformată are acum o componentă y în vectorul ei.
Numeric, asta se întâmplă ...
În ceea ce privește punerea în aplicare, am enumerat trucurile de mai jos.
m.a = 2
m.b = 1
m.c = 0
m.d = 1
Sunt sigur că în acest moment doriți să încercați lucrurile pe cont propriu, deci mergeți și faceți-vă bine
Am inclus ieșirea Flash pentru ambele cazuri, după cum urmează. Pentru cititorii care ar dori ajutor cu aceste valori, verificați Multiplication_final.as
în descărcarea sursei.
Consider că rotația este o submulțime de înclinare. Singura diferență este că în rotație se menține magnitudinea unei unități de ambele axe x și y, ca și perpendicularitatea dintre cele două axe.
ActionScript oferă de fapt o metodă în Matrice
clasă, roti()
, pentru a face acest lucru. Dar hai să trecem prin asta oricum.
Acum nu vrem să modificăm amploarea unei lungimi de unitate în x și y din grila originală; doar pentru a schimba orientarea fiecăruia. Putem folosi trigonometria pentru a ajunge la rezultatul din imaginea de mai sus. Având un unghi de rotație, a, vom obține rezultatul dorit prin utilizarea vectorilor (cos a, sin a) pentru axa x și (-s a a, cos a) pentru axa y. Amploarea pentru fiecare axă nouă va fi totuși o unitate, dar fiecare axă va avea un unghi de a, comparativ cu originalele.
Pentru implementarea Actionscript, presupunând că unghiul a, este de 45 de grade (adică, 0,25 * Pi radiani), doar tweak valorile matricei la următoarele:
var a: Numărul = 0,25 * Math.PI m.a = Math.cos (a); m.c = -1 * Math.sin (a); m.b = Math.sin (a); m.d = Math.cos (a);
Sursa completă poate fi menționată în Multiplication_final.as
.
Având o interpretare vectorală a unei matrice 2x2 deschide spațiu pentru a explora. Aplicarea sa în manipularea bitmap-urilor (BitmapData, LineBitmapStyle, LineGradientStyle
, etc) este larg răspândită - dar cred că o voi salva pentru un alt tutorial. În cazul acestui articol, vom încerca să înșelăm sprite-ul nostru la timpul de execuție, astfel încât să pară că acesta este de fapt flipping în 3D.
Din imaginea de mai sus vedem că, într-o lume cu o vedere izometrică, orice grafic care este "în picioare" își menține vectorul axei y neschimbat în timp ce vectorul axei x se rotește. Rețineți că o unitate de lungime pentru axele x și y nu se modifică - cu alte cuvinte, nici o scalare nu ar trebui să se întâmple în nici una din axe, doar rotirea în jurul axei x.
Iată un exemplu de această idee în Flash. Faceți clic pe oriunde pe scenă și începeți să trageți în jur pentru a vedea oblicul de pește. Eliberați-vă pentru a opri interacțiunea.
Iată micul important al Actionscript. Am subliniat liniile cruciale care se ocupă de rotația axei x. De asemenea, vă puteți referi la FakeIso.as
.
privat var f1: Pește, m: Matrix; privat var disp: punct; privată var axX: Punct, axăY: Punct; funcția publică FakeIso () disp = nou punct (stage.stageWidth * 0.5, stage.stageHeight * 0.5); m = noua matrice (); m.tx = disp.x; m.ty = disp.y; // deplasați în centrul f1 = noul pește (); addChild (f1); f1.transform.matrix = m; // aplicați transformarea pe axa peștilorX = punctul nou (1, 0); // vector pentru axa axei xY = punct nou (0, 1); // vector pentru y-axis stage.addEventListener (MouseEvent.MOUSE_DOWN, start); // începe interacțiunea stage.addEventListener (MouseEvent.MOUSE_UP, end); // end interaction start funcția privată (e: MouseEvent): void f1.addEventListener (Event.ENTER_FRAME, actualizare); sfârșitul funcției private (e: MouseEvent): void f1.removeEventListener (Event.ENTER_FRAME, actualizare); actualizarea funcției private (e: Event): void axisX.setTo (mouseX - f1.x, mouseY - f1.y); // determinați orientarea (dar magnitudinea sa schimbat) axisX.normalize (1); // fix magnitudinea vectorului cu o orientare nouă la 1 unitate apply2Matrix (); // aplicați matrice pe pește funcția privată apply2Matrix (): void m.setTo (axaX.x, axaX.y, axaY.x, axaY.y, disp.x, disp.y); f1.transform.matrix = m;
Aici am folosit clasa Point pentru stocarea vectorilor.
În acest pas, vom încerca să adăugăm controale de la tastatură. Locația peștelui se va actualiza în funcție de viteza sa, velo
. Vom defini pași incrementali pentru rotirea pozitivă (în sensul acelor de ceasornic) și rotația negativă (în sens invers acelor de ceasornic).
velo = punct nou (1, 0); // velo va fi folosit pentru a defini axa axei xY = nou punct (0, 1); delta_positive = matrice nouă (); delta_positive.rotate (Math.PI * 0,01); // rotație pozitivă delta_negative = matrice nouă (); delta_negative.rotate (Math.PI * -0,01); // rotație negativă
La apăsarea unei taste, velo
va roti:
funcția privată keyUp (e: KeyboardEvent): void if (e.keyCode == Keyboard.LEFT) velo = delta_negative.transformPoint (velo) // roti velo în sens contrar acelor de ceasornic altceva (e.keyCode == Keyboard.RIGHT ) velo = delta_positive.transformPoint (velo) // roti velo în sensul acelor de ceasornic
Acum, pentru fiecare cadru, vom încerca să coloreze partea din față a peștilor și să înclinăm și peștele. În cazul în care viteza, velo
, are o magnitudine mai mare de 1 și o aplicăm la matricea peștilor, m
, vom obține și un efect de scalare - astfel încât, pentru a elimina această posibilitate, vom normaliza viteza și apoi vom aplica numai la matricea peștelui.
Actualizarea funcției private (e: Event): void var front_side: Boolean = velo.x> 0 // verificarea părții frontale a peștelui dacă (front_side) f1.colorBody (0x002233,0.5) / din pește altceva f1.colorBody (0xFFFFFF, 0.5) // alb aplicat pe partea din spate a peștilor disp = disp.add (velo); // actualizați deplasarea curentă cu viteza var velo_norm: Point = velo.clone (); // în cazul velo> 0, trebuie să recalculam 1 unitate de lungime pentru x. velo_norm.normalize (1); // rețineți că axa x mai mare de 1 va efectua scalarea. Nu vrem ca pentru moment m.setTo (velo_norm.x, velo_norm.y, axisY.x, axisY.y, disp.x, disp.y); f1.transform.matrix = m;
Faceți clic pe scenă, apoi apăsați tastele săgeată stânga și dreapta pentru a vedea direcția de schimbare a peștilor.
Pentru a controla lucrurile, permiteți și controlul vectorului axei y.
funcția privată keyUp (e: KeyboardEvent): void if (e.keyCode == Keyboard.LEFT) velo = delta_negative.transformPoint (velo) altceva (e.keyCode == Keyboard.RIGHT) velo = delta_positive.transformPoint (velo) dacă (e.keyCode == Keyboard.UP) axisY = delta_negative.transformPoint (axisY) altceva dacă (e.keyCode == Keyboard.DOWN) axisY = delta_positive.transformPoint (axisY)
De asemenea, pentru a determina partea din față a peștilor, trebuie acum să încorporăm axa y. Aici este codul pentru care:
var front_side: Boolean = velo.x * axaY.y> 0 dacă (front_side) f1.colorBody (0x002233,0.5) altceva f1.colorBody (0xFFFFFF, 0.5)
Ei bine, pentru unii, rezultatul controlului ambelor axe se poate dovedi a fi puțin confuz, dar ideea este că acum puteți să vă înclinați peștele, să îl traduceți, să îl reflectați și chiar să îl rotiți! Încercați combinații de sus + stânga, în sus + dreapta, în jos + stânga, în jos + dreapta.
De asemenea, vedeți dacă puteți menține partea "din față" a peștilor (peștii vor fi în gri). Sugestie: Apăsați continuu, apoi la stânga, apoi în jos, apoi la dreapta. Faceți o rotație!
Sper că veți găsi matematica matriceală un element valoros pentru proiectele dvs. după citirea acestui articol. Sper să scriu un pic mai mult despre aplicațiile de 2x2 matrice în câteva sfaturi scurte care se rostogolesc din acest articol și mai departe Matrix3d
care este esențială pentru manipularea 3D. Mulțumesc pentru citire, terima kasih.