Aruncați obiecte creând o clasă PanAndThrow

În acest tutorial vom fi batjocorind și terminând o tava și aruncăm o clasă care ne va permite să adăugăm acest efect la orice element dorim. Pentru a realiza acest lucru, vom crea un vizualizator de imagini - dar nu și vizualizatorul dvs. mediu. Aici vom avea zoom, aruncare, panning ... Aproape sună ca o aplicație ninja, huh?


Pasul 1: Introducere

Pan și Throw Class vă vor permite să adăugați funcția pan și aruncare la orice obiect ActionScript pe care îl doriți. Deși acest tutorial este special pentru Flex, clasa însăși poate fi utilizată oriunde în ActionScript. Am văzut acest efect pe mai multe site-uri web, apoi în Photoshop CS4 și am decis că am vrut acest lucru și pe proiectele mele.

Există multe aplicații pentru acest efect; cea pe care o vom folosi pentru acest tutorial este un vizualizator de imagini care vă permite să măriți și micșorați imaginea și să modificați frecarea utilizată de efectul de aruncare. Cu toate acestea, acest tutorial nu este cu adevărat despre vizualizatorul de imagini, este vorba de a face o tigaie și arunca clasa. Deci, să începem cu asta. Deschideți editorul preferat Flex și obțineți un proiect; pentru informații despre acest lucru în Flex Builder, consultați Adobe LiveDocs. Odată ce proiectul dvs. este creat, deschideți fișierul MXML. Trebuie să adăugăm un cod la acest lucru înainte de a ne crea clasa.


Pasul 2: MXML-ul nostru

Deoarece aceasta nu este partea cea mai importantă a tutorialului, nu voi petrece mult timp aici. Dacă aveți întrebări despre această secțiune care nu sunt acoperite, vă puteți adresa în comentariile de mai jos. În primul rând, aici sunt obiectele MXML pe care le puneți în aplicație:

            

Veți observa cele patru funcții numite în etichetele: init (), changeDecay (), smoothImage () și zoom (). Trebuie să scriem aceste funcții. Acesta este codul dintre Etichete:

 import mx.states.SetStyle; import mx.effects.Move; import mx.containers.HBox; import mx.containers.Box; privat var imageWidth: Număr = 0; privat var imageHeight: Number = 0; sonda privată: Mutare = nouă Mutare (); // aceasta va fi apelată atunci când aplicația încarcă funcția privată init (): void // Acest eveniment va adăuga capacitatea de a ascunde și de a afișa comenzile noastre cu un clic. control.addEventListener (MouseEvent.CLICK, controlClick); mover.target = control;  // această funcție va mări și micșora imaginea noastră în funcție de valoarea glisorului nostru de zoom. funcția privată zoom (): void inside.width = (imageWidth * hSlider.value) / 100; inside.height = (imagineHeight * hSlider.value) / 100;  / / aceasta se numește atunci când imaginea noastră modifică dimensiunea. funcția privată smoothImage (ev: Eveniment): void // setarea netezirii imaginii, astfel încât imaginea să fie mai bună atunci când este transformată. var bmp: bitmap = ev.target.content ca bitmap; bmp.smoothing = true; imagewidth = inside.width; imageHeight = inside.height;  // nu vom folosi această funcție, dar încă privată changeDecay (): void // aceasta va schimba valoarea de decădere (frecare) a clasei noastre, atunci când ajungem acolo.  funcția privată controlClick (e: MouseEvent): void mover.play (); // această funcție ascunde / afișează comenzile pe clic dacă (control.y! = -5) mover.stop (); mover.yTo = -5; mover.play ();  altfel dacă (e.target == control) mover.stop (); mover.yTo = (control.height - 10) * -1; mover.play (); 

Odată ce ai MXML, trebuie să creezi un folder numit "clase" în același director ca fișierul MXML. (Dacă utilizați Flash, folderul trebuie să fie în același director ca și fișierul dvs. FLA.) Acesta este pachetul nostru de clase și este locul în care va merge fișierul PanAndThrow.as. În Flex Builder, creați o nouă clasă, puneți-o în pachetul de clase și numiți-o PanAndThrow; aceasta va crea stilul tău implicit de clasă.


Pasul 3: Formele unei clase

Iată clasa noastră de bază PanAndThrow. Salvați-l ca PanAndThrow.as în noul folder "clase".

 // declarația clasei de clase de clase // clasa de clasă declarată clasa publică PanAndThrow / * acest lucru se numește constructor, această metodă / funcție va fi apelată atunci când creați * o instanță a obiectului sau instanțiați obiectul. * pentru această clasă nu facem nimic pentru că vom face totul * în funcția Init * / funcția publică PanAndThrow () 

Ce variabile și funcții avem nevoie în clasa noastră PanAndThrow? Pentru a obține acest lucru, vă puteți întreba "ce trebuie să facă clasa mea, ce trebuie să știe și ce trebuie să fie capabil să o facă?" Deci, să creăm niște pseudo-coduri.

Notă rapidă

Când am dezvoltat pentru prima oară această clasă, am pus totul în constructor, dar asta a condus la o problemă atunci când am creat metode de pornire și oprire din cauza scopului. Nu am putut instantiza această clasă într-un domeniu global cu toate informațiile necesare. Prin urmare, am făcut o funcție init (), astfel încât instanța ar putea fi pornită și oprită din afara clasei.


Pasul 4: Pseudo-codul nostru

"Pseudo-codul" înseamnă doar un cod fals, pe care îl putem folosi pentru a ne ajuta să ne gândim la ce cod real avem nevoie.

 pachete clase clasa publica PanAndThrow / * Acestea vor fi variabilele pe care le facem. Deci, ce trebuie să știm? * anObjectToThrow; * anObjectToThrowItIn; * ObjectLocation; * PreviousObjectLocation; * Descompunere; // pentru fizică * acestea sunt cele evidente, dar această listă va fi mult mai mare * după cum vedem exact ceea ce avem nevoie în funcțiile noastre * / funcția publică PanAndThrow ()  / * Deci ce va face clasa noastră ? * init (); // trebuie să înceapă * stop (); // vrem să reușim să o oprim cumva. * start(); // Dacă ne oprim, trebuie să putem începe din nou. * tigaie(); * arunca (); * /

Acum că avem niște pseudo-coduri, putem începe construirea clasei. Să începem cu funcția init (). Acest lucru ne va aduce și unul dintre principiile programării orientate pe obiecte încapsulare, care se referă la accesul la piese ale codului.

Acest cod ar trebui să intre în clasa PanAndThrow pe care tocmai am început-o. (Nu știți unde? Verificați sfatul rapid al clasei de documente.)

 // datorită OOP, pot fi utilizate o clasă de nivel inferior și o clasă de nivel superior (una care se extinde // clasa inferioară). Ca și în cazul în care aproape orice obiect pe care îl veți folosi, se extinde clasa // Sprite. Așa că trebuie să ceară un obiect Sprite și poți da o casetă sau un buton. private var targetObject: Sprite = Sprite nou (); privat var eventObject: Sprite = Sprite nou (); private var originalDecay: număr = .9; buton privat varDescriere: Boolean = false; privat var moveY: Boolean = adevărat; private var movX: Boolean = adevărat; private var TargetClick: Boolean = adevărat; // Vom folosi acest lucru pentru a verifica cât timp mouse-ul a coborât pe un obiect fără să se miște. privat var t: Timer; privat var timerInterval: int = 100; funcția publică funcția init (ObjectToMove: Sprite, ObjectToEventise: Sprite, DecayAmout: Number = .9, isMoveY: Boolean = true, isMoveX: Boolean = true, OnlyMoveOnTargetClick: Boolean = true): void targetObject = ObjectToMove; eventObject = ObjectToEventise; originalDecay = DecayAmount; moveX = isMoveX; moveY = isMoveY; TargetClick = OnlyMoveOnTargetClick; t = Timer nou (timerInterval); start(); 

Doar câteva lucruri pe care vreau să le subliniez. În funcția pentru init am stabilit câteva argumente pentru a fi egale cu o valoare. Asta înseamnă că le dau o valoare implicită, făcându-le astfel opționale. Când setați valorile implicite pentru argumentele unei funcții, ele trebuie să fie ultimii parametri - nu puteți avea o variabilă necesară după una opțională. Motivul pentru care am adăugat variabilele implicite este de a face apelul să fie mai scurt dacă folosim setările implicite. Pot apela PanAndThrow (mover, eventer); și să fie făcut, în loc de PanAndThrow (mover, enventer, decayer, yVal, ...) și așa mai departe.

Te-ai întrebat vreodată ce înseamnă "privat" sau "public" în fața funcțiilor și variabilelor? Aceasta este expunerea obiectului. Un obiect "public" poate fi accesat de orice altă clasă; un obiect "privat" poate fi văzut doar de ceilalți membri ai acestei clase; un obiect "protejat" este ascuns de tot, cu excepția claselor care se află în același pachet.

Vrem să reușim să schimbăm decăderea de la MXML, așa că avem nevoie de un cârlig public pentru a ajunge la variabila noastră privată; acesta este locul unde se găsesc funcțiile getter și setter:

 private var originalDecay: număr = .9; funcția publică se distruge (): Număr return originalDecay; 

Aceasta este o funcție "getter". Aceasta înseamnă că, pentru clasele din afara, se pare că clasa PanAndThrow are o variabilă publică numită "decay". Când încearcă să le acceseze, le vom reveni la valoarea variabilei noastre (private) originalDecay.

Funcțiile Setter sunt aproape la fel, dar permite clasei externe să schimbe valoarea variabilei publice "false":

 funcția publică decăderea funcției (valoare: Număr): void originalDecay = value; 

Acestea sunt utile pentru că puteți pune logica într-un setter pentru a constrânge ceea ce vine în privat dvs. var. De exemplu, dacă ați pus un număr în eticheta MXML pentru o cutie, veți obține o înălțime setată; dacă ați pus un% (a face numărul un șir), veți obține o înălțime procentuală. Aceasta este inclusă în codul setterului de înălțime al cutiei. Acum, când avem getterul și setterul nostru, puteți accesa variabila de dezintegrare ca aceasta din afara clasei:

 var pt: PanAndThrow = nou PanAndThrow (); pt.init (țintă, părinte); pt.decay = .7;

Pasul 5: Începeți, Ascultă, Opriți

Avem clasa noastră, câteva variabile locale și o funcție init (). Să facem ceva acum. La sfârșitul funcției init () am numit "start ();" așa că să facem funcția de pornire. În mare parte, este vorba doar de o mulțime de ascultători:

 funcția public start (): void // Cu mouse-ul în jos, căutăm să începem acțiunea noastră pan, dar trebuie să putem // verifica doar OurMoveOnTargetClick pe care l-am atribuit campului nostru global TargetClick targetObject.addEventListener (MouseEvent. MOUSE_DOWN, handleOverTarget); eventObject.addEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); // Când sunăm panoul nostru, acesta folosește un ascultător de mișcare a mouse-ului, ceea ce înseamnă că acesta devine apelat de fiecare dată când // mouse-ul se mișcă, așa că trebuie să vedem cum să limităm când obiectele țintă se mișcă. eventObject.addEventListener (MouseEvent.MOUSE_MOVE, moveIt); // aceasta este de a arunca obiectul după o tigaie, aceasta este puțin complicată deoarece funcția throwIt () numește un alt ascultător. targetObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); // metoda throwItOut face ca obiectul nostru să acționeze ca și cum l-am lăsa pe butonul mouse-ului, dar este concediat atunci când // mouse-ul părăsește obiectul părinte targetObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); // acesta este ascultatorul de timp, acesta va verifica dacă ați ținut puțin mouse-ul jos, voi explica necesitatea acestui lucru când ajungem la funcția timerOut () t.addEventListener (TimerEvent. TIMER, timerOut); t.start (); 

Funcția stop () este aproape aceeași, dar eliminăm ascultătorii.

 funcția publică (): void targetObject.removeEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); eventObject.removeEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); eventObject.removeEventListener (MouseEvent.MOUSE_MOVE, moveIt); targetObject.removeEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.removeEventListener (MouseEvent.MOUSE_UP, throwIt); targetObject.removeEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.removeEventListener (MouseEvent.MOUSE_OUT, throwItOut); t.removeEventListener (TimerEvent.TIMER, timerOut); t.stop (); 

Acum putem asculta ce se întâmplă, să trecem prin fiecare dintre aceste funcții ascultător.


Pasul 6: MouseEvent.MOUSE_DOWN

Vom analiza mânerul evenimentului handleOverTarget.

 funcția privată handleOverTarget (e: MouseEvent): void buttonDown = true; arMousePrevX = MousePrevX = MouseCurrX = eventObject.mouseX; arMousePrevY = MousePrevY = MouseCurrY = eventObject.mouseY; dacă (e.currentTarget == targetObject ||! TargetClick) overTarget = true;  altfel dacă (e.target.toString (). search (targetObject.toString ()) < 0)  overTarget = false;  

Această funcție va fi apelată atunci când există un eveniment MOUSE_DOWN fie pe obiectul evenimentului, fie pe obiectul țintă. Este foarte important să rețineți că dacă aș pune un ascultător pe un obiect parent, manipulatorul va fi chiar apelat când evenimentul are loc pe un copil. În acest caz, obiectul țintă este un copil al obiectului evenimentului. Când fac clic pe obiectul țintă, această metodă va fi apelată de două ori: mai întâi pentru mouse-ul jos pe copil, apoi pentru al doilea mouse-ul în jos pe părinte. Acest lucru este cu adevărat important pentru acest lucru, deoarece vom decide dacă șoarecele în jos va fi capabil să ne miște obiectul țintă, așa că într-adevăr trebuie să știm dacă acest mouse-ul a fost pus pe copil sau nu.

Prima afirmație este destul de simplă: setați butonul variabil al claseiDown to true.

Următoarele două sunt destul de ușor, de asemenea, cu excepția faptului că am introdus câteva variabile noi care vor trebui să fie introduse în lista claselor variabile: MousePrevX, MousePrevY, arMousePrevX, arMousePrevY, MouseCurrX și MouseCurrY. Acestea vor fi folosite mult în funcțiile de tragere și tigaie, așa că am să aștept să vorbesc despre ele până atunci.

Instrucțiunea if verifică dacă obiectul pe care faceți clic este obiectul țintă. Amintiți-vă că TargetClick a fost setat la argumentul pe care am trecut-o la init (), OnlyMoveOnTargetClick; dacă acest lucru este fals, vrem să tratăm fiecare obiect copil ca obiect țintă atunci când faceți clic pe el. De aceea avem verificarea "||! TargetClick".

Aceasta este partea ușoară. Următoarea parte este puțin mai complicată.

E.currentTarget returnează obiectul care a declanșat evenimentul. Obiectul e.target va returna obiectul care a fost ținta reală. Aș putea spune asta, corect?

 dacă (e.target == targetObject ||! TargetClick) overTarget = true;  altfel overTarget = false; 

Este destul de simplu, dar e greșit. Ce se întâmplă dacă obiectul țintă are copii? Apoi e.currentTarget poate fi targetObject dar e.target este copilul targetObject și nu se va potrivi. Vrem ca acest lucru să se miște, chiar dacă măturăm un obiect copil.

Așa că vine String.search la salvare. Dacă targetul nostru curent nu este targetObjectul nostru, folosim un "else if" pentru a vedea dacă putem găsi obiectul țintă în țintă. e.target.toString () va produce ceva de genul: "application2.eventobject3.targetobject2.targetchild4" pentru obiectul țintă unde targetObject.toString () va produce ceva de genul "application2.eventobject3.targetobject2" tot ce trebuie să fac aflați dacă ținta noastră este un copil al țintăObiectivul nostru este prin aceasta:

 e.target.toString (). căutare (targetObject.toString ())

Dacă există un meci, acesta va întoarce primul index al meciului sau, dacă nu există o potrivire, va returna un -1, așa că putem vedea doar dacă acesta este mai mare decât -1 și viola, am descoperit dacă obiectul a face clic pe este un copil al targetObject noastre.

(Am putea verifica copiii sau părinții obiectului prin funcția getChildAt () și proprietatea părintească, dar aceasta este o alternativă potrivită.)


Pasul 7: TimerOut și Pan

Funcția temporizatorului este destul de simplă, mai ales că am făcut acest lucru înainte. Aproape că ați făcut asta înainte. Când ne-am târât puțin în jurul țintei mici și ne-am hotărât să nu lăsăm să meargă, ne place foarte mult și oprim brusc mouse-ul, ce s-ar întâmpla dacă ați lăsa butonul mouse-ului în acel moment? bine, ce crezi că se va întâmpla? Nu voi răspunde la asta pentru tine, te voi ajuta cu codul ca să nu te mai întâmple. În codul final, comentați aceste trei linii. Acest lucru ar trebui să arate foarte familiar, tocmai am folosit acest lucru în butonul de jos handler, cu excepția unei variabile, MouseDragged. Vom folosi acest lucru atunci când numim o altă funcție:

 funcția privată timerOut (e: TimerEvent): void MouseDragged = false; arMousePrevX = MousePrevX = MouseCurrX = eventObject.mouseX; arMousePrevY = MousePrevY = MouseCurrY = eventObject.mouseY; 

Deci, dacă întrebați de ce avem nevoie de acest eveniment timer, probabil că nu ați încercat să o luați pentru a vedea ce se întâmplă. Asa faceti asta.

Următoarea funcție este una dintre funcțiile noastre principale; este funcția pan. Există multe implicări, așa că să ne aruncăm în pseudo-codul nostru:

 funcția privată moveIt (e: MouseEvent): void / * ok, deci de ce avem nevoie de această funcție? * trebuie să ne pătrundem obiectul țintă. * astfel încât să vedem dacă suntem peste obiectivul nostru țintă * / // dacă (suntem peste obiectivul nostru țintă) // // ce unelte vom avea nevoie pentru a panorama? // bine, poate că ar trebui să verificăm dacă butonul este în jos // dacă (butonul este în jos) // // ar putea fi necesar să setăm variabila butonului. buttonDown = true; // și dacă suntem în această funcție în acest moment butonul nostru este în jos și / / mouse-ul sa mutat - asta este o drag-ul: MouseDragged = true; // dacă mutăm obiectul în funcție de mutarea mouse-ului, atunci ar trebui să știm unde știe unde este mouse-ul: MouseCurrX, Y = actualul MouseX, Y; // aceasta este o introducere la mouse-ul nostru artificial prev, care va fi explicat // în următoarea funcție. Ar înseamnă "artificial" sau "după eliberare", // oricare preferați. Acest lucru trebuie să fie setat la poziția actuală a mouse-ului precedent. // arMousePrevX = MousePrevX; // arMousePrevY = MousePrevY; // atunci trebuie sa mutam targetObject, // dar amintim variabilele noastre, moveX si moveY, deci: // daca moveX muta x; // if moveY move y; // trebuie să resetați Declanșarea (fricțiunea) înapoi la starea inițială: // Decay = originalDecay; // care ar trebui să termine if // // ce altceva? // // ne-am setat butonul cu adevărat înainte, deci l-am lăsat aici false. // buttonDown = false; // dacă nu este un clic țintă, ar trebui să setăm overTarget la false astfel: // if (! TargetClick) // overTarget = false; // asta e. // // există câteva lucruri pe care vrem să le facem indiferent de condiții. // în primul rând, trebuie să setăm mouse-ul nostruPrevX, variabila Y - înainte ca mouse-ul să fie mutat din nou! // MousePrevX = eventObject.mouseX; // MousePrevY = eventObject.mouseY; // Aici sunt încă două variabile care urmăresc: xOpposideEdge și yOppositeEdge // testează pentru a vedea care este dimensiunea obiectului țintă în relația // cu obiectul nostru de eveniment; dacă cineva este mai mare, trebuie să schimbăm comportamentul sariturii. // if (targetObject.width> eventObject.width) xOppositeEdge = true; // altfel xOppositeEdge = false; // if (targetObject.height> eventObject.height) yOppositeEdge = true; // else yOppositeEdge = false; / / și, în final, trebuie să ne oprim și să ne repornim cronometrul. //t.stop (); //t.start (); //

Recunosc că este un pic mai mult decât ultimul; care este din două motive: una, nu știți ce se întâmplă și două, sunt foarte încântat să ajung la cod:

 funcția privată moveIt (e: MouseEvent): void // în pseudo-codul nostru au fost două condiții, dar putem combina apoi la unul, // testează pentru a vedea dacă evenimentul nostru a fost un buton în jos și dacă suntem peste țintă, // dacă suntem apoi să mutăm obiectul țintă. dacă (e.buttonDown && overTarget) buttonDown = true; MouseDragged = true; MouseCurrX = eventObject.mouseX; MouseCurrY = eventObject.mouseY; // aici este cea artificială / ulterioară. din nou, ajungeți la asta. arMousePrevX = MousePrevX; arMousePrevY = MousePrevY; / * acesta este cel important, în pseudo-ul nostru a fost "mișcarea obiectului țintă", * așa că trebuie să traducem asta. Pentru a ne ajuta, vom crea o variabilă locală * Topper pentru partea de sus și Sider pentru partea laterală. * Hai să ne uităm la Topper (același lucru se va aplica și lui Sider). * eventObject.mouseY se uită unde mouse-ul se află în interiorul evenimentului Object. * Noi luam MousePrev departe de asta, si asta ne va da cat de mult obiectul * ar trebui sa calatoreasca, astfel incat Y ar putea sa calatoreasca 2 pixeli, sau -2 pixeli in functie de directia, asa ca luam acea schimbare si adaugam-o la targetul poziția curentă *, dar acest lucru nu se întâmplă încă, acesta este doar un var. * / var Topper: int = (eventObject.mouseY - MousePrevY) + targetObject.y; var Sider: int = (eventObject.mouseX - MousePrevX) + targetObject.x; // aici este locul unde se întâmplă, dacă mutați (amintiți-vă din pseudo-cod), atunci // putem seta poziția țintă. daca (moveY) targetObject.y = Topper; daca (moveX) targetObject.x = Sider; // asa ca suntem doar folosind Topper si Sider pentru a stoca temporar unde obiectul target ar trebui sa se deplaseze Decay = originalDecay ;  altceva buttonDown = false; dacă (! TargetClick) overTarget = false;  MousePrevX = eventObject.mouseX; MousePrevY = eventObject.mouseY; dacă (targetObject.width> eventObject.width) xOppositeEdge = true; altfel xOppositeEdge = false; if (targetObject.height> eventObject.height) yOppositeEdge = true; else yOppositeEdge = false; t.stop ); t.start (); 

Și acum suntem în panning.


Pasul 8: Aruncați, ieșiți, repetați!

Aceasta este a doua funcție importantă și cu aceasta vom construi clasa noastră! Sunteți gata să aruncați și aruncați orice obiect pe care îl considerați potrivit! Există două funcții pe care trebuie să le adresăm mai întâi: throwIt (), pe care le-am setat ca un handler la evenimentul MOUSE_UP și throwItOut (), pe care le-am setat ca un handler la evenimentul MOUSE_OUT.

 funcția privată throwIt (e: MouseEvent): void buttonDown = false; dacă (MouseDragged) eventObject.addEventListener (Event.ENTER_FRAME, TheRepeater);  funcția privată throwItOut (e: MouseEvent): void buttonDown = false; dacă (e.relatedObject == null || e.relatedObject == eventObject.parent) eventObject.addEventListener (Event.ENTER_FRAME, TheRepeater); 

Aceste două funcții sunt aproape la fel (la urma urmei, ele fac același lucru doar la momente diferite). În ele am setat butonulDown to false, deoarece acesta este un eveniment mouse up și verificați dacă mouse-ul a fost tras, folosind MouseDragged (pe care l-am setat în ultima funcție) sau bifând "e.relatedObject"; obiectul pe care mouse-ul tocmai l-a mutat.

Dacă a fost târât, adăugăm un alt ascultător. Evenimentul ENTER_FRAME este unul foarte cool. Aceasta este baza animației noastre; de fiecare dată când introducem un nou cadru, funcția throw () va fi rulată. Aceasta este ceea ce ne permite să simulam un mouse trageți după eliberare (amintiți-vă arMousePrevX, variabila Y? Asta este ceea ce este pentru). Și asta este tot ceea ce aruncă este într-adevăr face, simularea unui trageți mouse-ul, fără mouse-ul, desigur. Așa că am obținut deja funcția de care avem nevoie, cu excepția faptului că trebuie să înlocuim apelurile cu poziția actuală a mouse-ului cu poziția noastră de șoarece artificială.

Aproape am ajuns puțin acolo. Prin urmare, cu aceste două funcții de evenimente, throwIt și throwItOut, aceștia fac același lucru, dar asta dacă în a doua funcție merită menționat. M-am străduit o vreme să încerc să obțin această funcționalitate, până când m-am uitat la eveniment mai aproape. Problema a fost încercarea de a obține obiectul țintă să acționeze ca și cum l-aș da drumul butonului când cursorul a părăsit obiectul evenimentului. Continuați, încercați să faceți acest lucru fără e.relatedObject. Aproape că am avut-o de câteva ori, dar nu am reușit. Ceea ce face obiectul e.relatedObject constă în ce obiect se află, după ce evenimentul este chemat. De aceea este foarte cool. Când cursorul nostru părăsește întregul film, acesta returnează o nulă, altfel va returna obiectul pe care vă aflați, astfel încât să putem verifica dacă e.relatedObject este nulă sau este părinte pentru eventObject. Asta produce acțiunea corectă pe care o căutăm.

În funcțiile de mai sus, setăm apelurile către referent (). Aceasta va fi funcția de aruncare și amintiți-vă că va fi apelată de fiecare dată când introduceți un nou cadru. Să trecem prin această linie:

 funcția privată theRepeater (e: Event): void // temporizatorul trebuie oprit, încercați să îl eliminați și să vedeți ce se întâmplă. t.stop (); // aici este o variabilă locală care va menține poziția cursorului curent (fals). // bine, este doar "fals" după prima dată în jur. Var oldxer: Number = MouseCurrX; var oldyer: Număr = MouseCurrY; // acum, așa cum am făcut înainte, trebuie să găsim diferența dintre poziția curentă // și poziția anterioară. asa cum este aceasta diferita de cea anterioara? De ce? var xDiff: Număr = MouseCurrX - arMousePrevX; var yDiff: Număr = MouseCurrY - arMousePrevY; // în cazul în care butonul este în jos, nu vom mai muta, butonul va opri acțiunea în acest caz. dacă (! buttonDown) // luați diferența și o faceți prin decădere. acest lucru ne va da noua // diferenta, care va fi putin mai mica decat cea din ultima, care este modul in care // vom obtine efectul de frecare cu aceasta. // de exemplu. dacă Decay este 0.5, atunci distanța mutată va înjumătăți fiecare cadru. xDiff = xDiff * Decay; yDiff = yDiff * Decay; // next este una dintre părțile confuze pentru mine, acest lucru nu mișcă obiectul la // toate, doar testează pentru a vedea dacă targetObject a ajuns la margine. dacă are, // trebuie să-l sărim înapoi. (acest lucru ar putea fi schimbat la alte acțiuni dacă // doriți, ați putea chiar să îl eliminați, ceea ce se întâmplă dacă o faci? încercați! // în funcția pan setați această variabilă, OppositeEdge, aici vom // foloseste ca daca 'targetObject este mai mare decat Objectul de Eveniment' pe care l-am setat in functia // init (), voi merge doar prin x aici, deoarece y este // aproape la fel (ce este diferit? (xOppositeEdge) / * astfel primul, "lățimea evenimentului Object, - lățimea targetObject - 50", * aici, lățimea targetObject este mai mare decât cea a eventObject * this va permite ca marginea opusă a obiectului țintă să fie de 50 px de la marginea opusă. Dacă mergeți la exemplul filmului și micșorați imaginea la * 10% și aruncați-l în jur, apoi măriți dimensiunea la 200% și încercați și notă * ce margine face ceea ce, atunci veți vedea diferența dintre bounces. * Aceasta este cea mai bună modalitate de a înțelege această parte. * / if (targetObject.x < (eventObject.width - targetObject.width - 50))  xDiff = -1 * xDiff; targetObject.x = eventObject.width - targetObject.width - 50;  // this does the same thing for the other edge. if(targetObject.x > 50) xDiff = -1 * xDiff; targetObject.x = 50;  / aceasta este dacă obiectul țintă este mai mic decât evenimentul Object. altfel / * din nou, testează marginile obiectelor objectOject împotriva obiectului * event. De data aceasta avem de-a face cu aceeași margine (bine, * 5px în afara marginii). Deci, aceasta va sări ca și cum ar fi lovit un zid. * / if (targetObject.x < -5)  xDiff = -1 * xDiff; targetObject.x = -5;  if(targetObject.x > (eventObject.width - (targetObject.width - 5))) xDiff = -1 * xDiff; targetObject.x = eventObject.width - (targetObject.width - 5);  dacă (yOppositeEdge) if (targetObject.y < (eventObject.height - targetObject.height - 50))  yDiff = -1 * yDiff; targetObject.y = eventObject.height - targetObject.height - 50;  if(targetObject.y > 50) yDiff = -1 * yDiff; targetObject.y = 50;  altceva if (targetObject.y < -5)  yDiff = -1 * yDiff; targetObject.y = -5;  if(targetObject.y > (eventObject.height - (targetObject.height - 5))) yDiff = -1 * yDiff; targetObject.y = eventObject.height - (targetObject.height - 5);  // bine, dacă aveți întrebări despre acea parte, postați un comentariu despre el și îi voi răspunde. // aici sunt siderul și Topper vars (la fel ca cele din funcția pan). var sider: int = xDiff + targetObject.x; var Topper: int = yDiff + targetObject.y; // trebuie să setăm acest lucru pregătit pentru următorul pas. MouseCurrX = MouseCurrX + xDiff; MouseCurrY = MouseCurrY + yDiff; // și apoi if moveX, Y (din nou ca funcția pan) dacă (moveY) targetObject.y = Topper; dacă (moveX) targetObject.x = sider;  // și acum setăm mouse-ul nostru artificial prev arMousePrevX = oldxer; arMousePrevY = vechi; // și dacă nu suntem în modul frictionless (OriginalDecay = 1) // vom scădea o mică cantitate de la decăderea noastră, // vom da o relaxare mai naturală. în cazul în care (originalDecay < 1)  Decay = Decay - .004;  // so the moving is done.  // if the button is down we need to remove the listener. else  eventObject.removeEventListener(Event.ENTER_FRAME, theRepeater);  // now we need to check if the effect is over, which is if our x and y diffs are less than 1px. if((Math.abs(xDiff) < 1 && Math.abs(yDiff) < 1))  eventObject.removeEventListener(Event.ENTER_FRAME, theRepeater);  

Și cu asta, clasa noastră este terminată.


Pasul 9: Codul de clasă finalizat

Puteți lua codul completat din sursa Source, legat în partea de sus a tutorialului. Este în clasa PanAndThrow.as.


Pasul 10: Faceți ceva cu el

Pentru a face ceva cu asta, trebuie să ne întoarcem la MXML și să adăugăm câteva linii de cod. Adăugați declarația noastră în secțiunea variabilă globală, completați metoda de dezintegrare și apelați funcția noastră pan și throw init (). Cu toate acestea adăugat, aici este fișierul complet MXML:

      
	
Cod