Kasta objekt genom att skapa en PanAndThrow-klass

I denna handledning kommer vi att mocka upp och avsluta en panna och kasta klass som gör att vi kan lägga till denna effekt på något element vi vill ha. För att uppnå detta ska vi skapa en bildvisare - men inte din genomsnittliga tittare. Här kommer vi att zooma, kasta, panorera ... Nästan låter som en ninja app, va?


Steg 1: Introduktion

Pan- och kasta-klassen låter dig lägga till panelen och kasta funktionaliteten till alla ActionScript-objekt du vill ha. Även om denna handledning är specifikt för Flex kan klassen själv användas överallt ActionScript är. Jag hade sett denna effekt på flera webbplatser, sedan i Photoshop CS4 och bestämde mig för att jag ville ha det på mina projekt också.

Det finns många applikationer för denna effekt; Den som vi ska använda för denna handledning är en bildvisare som låter dig zooma in och ut ur bilden och ändra friktionen som kastaffekten använder. Men denna handledning handlar inte egentligen om bildvisaren, det handlar om att göra en panna och kasta klassen. Så låt oss börja med det. Öppna din favorit Flex-redaktör och få ett projekt att gå; För information om hur du gör det i Flex Builder, se Adobe LiveDocs. När ditt projekt är skapat, öppna MXML-filen. Vi måste lägga till en kod till detta innan vi skapar vår klass.


Steg 2: Vår MXML

Eftersom detta inte är den stora delen av handledningen kommer jag inte att spendera mycket tid här. Om du har några frågor om det här avsnittet som inte är täckta, kan du fråga i kommentarerna nedan. För det första är här MXML-objekten som ska läggas in i ansökan:

            

Du märker de fyra funktionerna som heter i init: (), changeDecay (), smoothImage () och zoom (). Vi måste skriva upp de funktionerna. Detta är koden mellan tags:

 importera mx.states.SetStyle; importera mx.effects.Move; importera mx.containers.HBox; importera mx.containers.Box; privat var imageWidth: Number = 0; privat var imageHeight: Number = 0; privat var mover: Move = new Move (); // detta kommer att ringas när applikationen laddar privat funktion init (): void // Den här händelsen kommer att lägga till möjligheten att dölja och visa våra kontroller med ett klick. control.addEventListener (MouseEvent.CLICK, controlClick); mover.target = control;  // Denna funktion kommer att zooma in och ut ur vår bild enligt värdet av vår zoomreglage. privatfunktionszoom (): void inside.width = (imageWidth * hSlider.value) / 100; inside.height = (imageHeight * hSlider.value) / 100;  // det här heter när vår bild ändras. privat funktion smoothImage (ev: Event): void // set bildutjämning så bilden ser bättre ut när den omvandlas. var bmp: Bitmap = ev.target.content som Bitmap; bmp.smoothing = true; imagewidth = inside.width; imageHeight = inside.height;  // vi kommer inte att använda den här men ändå privata funktionen changeDecay (): void // detta kommer att ändra sönderfallets (friktions) värde i vår klass när vi kommer dit.  Private Function ControlClick (e: MouseEvent): void mover.play (); // den här funktionen döljer / visar kontrollerna på klicka om (control.y! = -5) mover.stop (); mover.yTo = -5; mover.play ();  annars om (e.target == kontroll) mover.stop (); mover.yTo = (control.height -10) * -1; mover.play (); 

När du har din MXML behöver du skapa en mapp som heter "klasser" i samma mapp som din MXML-fil. (Om du använder Flash måste mappen vara i samma bild som din FLA-fil.) Detta är vårt klasspaket och där PanAndThrow.as-filen kommer att gå. I Flex Builder skapar du en ny klass, lägger den i klasspaketet och kallar det PanAndThrow; Detta kommer att skapa din klass - standardstil.


Steg 3: Förverkligandet av en klass

Här är vår grundläggande PanAndThrow-klass. Spara det som PanAndThrow.as i din nya "klasser" -mapp.

 // namnrymddeklaration paketklasser // klassdeklaration offentlig klass PanAndThrow / * det här kallas konstruktören, den här metoden / funktionen kommer att ringas när du skapar * en förekomst av ditt objekt, eller instanserar ditt objekt. * För den här klassen gör vi ingenting för att vi ska göra allt * i Init-funktionen * / offentlig funktion PanAndThrow () 

Vilka variabler och funktioner behöver vi i vår PanAndThrow-klass? För att få det kan du fråga dig själv "Vad behöver min klass att göra, vad behöver den veta och vad behöver den för att kunna göra det?" Så låt oss skapa lite pseudokod.

Snabbanmälan

När jag först utvecklade den här klassen satt jag allt i konstruktören, men det ledde till ett problem när jag skapade start och stoppar metoder på grund av omfattning. Jag kunde inte instansiera den här klassen på ett globalt område med all information som krävs. Jag gjorde därför en init () -funktion, så förekomsten kunde startas och stoppas från utsidan av klassen.


Steg 4: Vår Pseudokod

"Pseudokod" betyder bara falsk kod, som vi kan använda för att hjälpa oss att tänka på vilken riktig kod vi behöver.

 Paketklasser offentlig klass PanAndThrow / * Dessa kommer att vara de variabler vi gör. Så vad behöver vi veta? * anObjectToThrow; * anObjectToThrowItIn; * ObjectLocation; * PreviousObjectLocation; * Förfall // för fysiken * det här är de självklara, men den här listan blir mycket större * som vi ser exakt vad vi behöver i våra funktioner * / offentlig funktion PanAndThrow ()  / * Så vad ska vår klass göra ? * i det(); // det måste börja * stoppa (); // vi vill kunna stoppa det på något sätt * Start(); // Om vi ​​slutar måste vi kunna starta det igen. * pan (); * kasta (); * /

Nu när vi har lite pseudokod kan vi börja bygga klassen. Låt oss börja med init () -funktionen. Detta kommer också att leda till en av principerna för objektorienterad programmering som heter inkapsling, som handlar om åtkomst av bitar av koden.

Den här koden ska gå i den PanAndThrow-klass vi just har börjat. (Var inte säker var? Kolla in Quick Class Tips för dokumentklassen.)

 // tack vare OOP, en lägre nivå klass och en övre nivå klass (en som sträcker sig // klassen lägre klass) kan användas. Precis som här, kommer nästan alla objekt som du använder att utöka // Sprite-klassen. Så jag behöver bara fråga om ett Sprite-objekt och du kan ge en ruta eller en knapp. privat var targetObject: Sprite = new Sprite (); privat var eventObject: Sprite = new Sprite (); privat var originalDecay: Number = .9; privat var buttonDown: Boolean = false; privat var moveY: Boolean = true; privat var moveX: Boolean = true; private var TargetClick: Boolean = true; // Vi använder detta för att kontrollera hur länge musen har gått ner på ett objekt utan att flytta. privat var t: Timer; privat var timerinterval: int = 100; public function 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 = ny timer (timerintervall); Start(); 

Bara ett par saker jag vill påpeka. I funktionen för init har jag satt några av argumenten som är lika med ett värde. Det betyder att jag ger dem ett standardvärde, vilket gör dem valfria. När du anger standardvärden för argument för en funktion måste de vara de sista parametrarna - du kan inte ha en önskad variabel efter en valfri. Anledningen till att jag har lagt till standardvariabler är att ringa samtalet kortare om vi använder standardinställningarna. Jag kan ringa PanAndThrow (mover, eventer); och görs istället för PanAndThrow (mover, enventer, decayer, yVal, ...) och så vidare.

Har du någonsin undrat vad den "privata" eller "offentliga" framför funktioner och variabler betyder? Det är objektets exponering. Ett "offentligt" objekt kan nås av någon annan klass; ett "privat" objekt kan endast ses av de andra medlemmarna i denna klass; ett "skyddat" objekt är dolt för allt utom klasser som finns i samma paket.

Vi vill kunna ändra förfallet från vår MXML så vi behöver en offentlig krok för att komma till vår privata variabel. detta är där getter och setterfunktioner kommer in:

 privat var originalDecay: Number = .9; allmän funktion få förfall (): Nummer return originalDecay; 

Det är en "getter" -funktion. Det betyder att det ser ut som att i klasserna PanAndThrow finns en offentlig variabel som kallas "förfall". När de försöker komma åt det kommer vi att återvända till värdet av vår (privata) originalDecay-variabel.

Setterfunktionerna är nästan lika, men låter de yttre klasserna ändra värdet av vår "falska" offentliga variabel:

 public function set decay (värde: Number): void originalDecay = value; 

Dessa är användbara eftersom du kan lägga in logik i en setter för att begränsa vad som kommer in i ditt privata var. Om du till exempel anger ett nummer i MXML-taggen för en låda får du en bestämd höjd; Om du lägger ett% (gör numret en sträng) får du en procentuell höjd. Det är inbyggt i koden för lådans höjd setter. Nu när vi har vår getter och setter kan du få tillgång till sönderfallsvariabeln så här från utsidan av klassen:

 var pt: PanAndThrow = ny PanAndThrow (); pt.init (mål, förälder); pt.decay = .7;

Steg 5: Börja, Lyssna, Stopp

Vi har vår klass, några lokala variabler och en init () -funktion. Låt oss göra något nu. I slutet av init () -funktionen kallade vi "start ();" så låt oss göra startfunktionen. För det mesta är det bara en massa lyssnare:

 public function start (): void // Med musen nere, vi letar efter att starta vår pan action, men vi måste kunna // för att kontrollera vår OnlyMoveOnTargetClick som vi tilldelade vårt globala fält TargetClick targetObject.addEventListener (MouseEvent. MOUSE_DOWN, handleOverTarget); eventObject.addEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); // När vi kallar vår pan, använder den en musförflyttningslyssnare, vilket betyder att det kallas varje gång // musen rör sig, så vi måste se hur man begränsar när målobjektet rör sig. eventObject.addEventListener (MouseEvent.MOUSE_MOVE, moveIt); // det här är att kasta objektet efter en pan, det här är lite knepigt eftersom funktionen throwIt () kallar en annan lyssnare. targetObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); // methoden throwItOut gör att vårt objekt fungerar som om vi släpper musknappen men det blir avfyrat när / / musen lämnar förälderobjektet targetObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); // det här är timerhöraren, det här kommer att kolla om du har hållit musen nere för en liten stund, jag ska / förklara behovet av detta när vi kommer till funktionen timerOut () t.addEventListener (TimerEvent. TIMER, timerOut); t.start (); 

Stoppfunktionen () är nästan densamma, men vi tar bort lyssnare.

 public function stop (): 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 (); 

Nu kan vi lyssna på vad som händer, låt oss gå igenom alla dessa lyssnarfunktioner.


Steg 6: MouseEvent.MOUSE_DOWN

Vi ska titta på handtaget HandOverTarget.

 privat funktion handleOverTarget (e: MouseEvent): void buttonDown = true; arMousePrevX = MousePrevX = MouseCurrX = eventObject.mouseX; arMousePrevY = MousePrevY = MouseCurrY = eventObject.mouseY; om (e.currentTarget == targetObject ||! TargetClick) overTarget = true;  annars om (e.target.toString (). search (targetObject.toString ()) < 0)  overTarget = false;  

Den här funktionen kommer att ringas när det finns en MOUSE_DOWN-händelse på antingen händelseobjektet eller målobjektet. Det är mycket viktigt att notera att om jag lägger en lyssnare på ett förälderobjekt, kommer handlaren även att ringas när händelsen inträffar på ett barn. I detta fall är mitt målobjekt ett barn för händelseobjektet. När jag klickar på målobjektet kommer denna metod att kallas två gånger: först för musen ner på barnet och sedan för musen nere på föräldern. Det är verkligen viktigt för det här eftersom vi ska bestämma om musen ner kommer att kunna flytta vårt målobjekt så att vi verkligen måste kunna veta om musen var nere på barnet eller inte.

Det första uttalandet är ganska enkelt: sätt vår klassvariabelknappDown to true.

De två följande är också ganska enkla, förutom att jag har infört ett par nya variabler som måste läggas i vår klassvariabel lista: MousePrevX, MousePrevY, arMousePrevX, arMousePrevY, MouseCurrX och MouseCurrY. Dessa kommer att användas mycket i drag och pan funktioner, så jag väntar på att prata om dem tills dess.

Om-testet kontrollerar om objektet som klickas är målobjektet. Kom ihåg att TargetClick var inställt på argumentet vi passerade till init (), OnlyMoveOnTargetClick; Om detta är falskt vill vi behandla varje barnobjekt som målobjektet när det klickas. Det är därför vi har kontrollen "||! TargetClick".

Det är den lätta delen. Nästa del är lite knepigare.

E.currentTarget returnerar objektet som utlöste händelsen. E.target returnerar objektet som var det aktuella målet. Så jag kunde säga det här, rätt?

 om (e.target == targetObject ||! TargetClick) overTarget = true;  annat overTarget = false; 

Det är enkelt nog, men det är fel. Vad händer om mitt målobjekt har barn? Då kan min e.currentTarget vara targetObject men e.target är targetObjects barn och matchar inte. Vi vill att detta ska röra sig även om vi smälter på ett barnobjekt.

Så här kommer String.search till undsättning. Om vår nuvarandeTarget inte är vårt målObject använder vi en "annan om" för att se om vi kan hitta vårt målobjekt i målet. e.target.toString () kommer att skapa något som detta: "application2.eventobject3.targetobject2.targetchild4" för vårt målobjekt där targetObject.toString () kommer att producera något som denna "application2.eventobject3.targetobject2" allt jag behöver göra för att ta reda på om vårt mål är ett barn i vårt målObject är av följande:

 Sök e.target.toString (). (targetObject.toString ())

Om det finns en match kommer det att returnera matchens första index eller om det inte finns en match kommer det att returnera en -1, så vi kan bara se om den är större än -1 och viola, vi har funnit om objektet Att klicka på är ett barn i vårt målObject.

(Vi kunde kontrollera barnets eller föräldrarnas föremål via funktionen getChildAt () och föräldraegenskap, men det här är ett snyggt alternativ.)


Steg 7: TimerOut och Pan

Timerns funktion är också ganska lätt, särskilt eftersom vi tidigare har gjort det. Tja, nästan gjort detta förut. När vi har dragit runt vårt lilla målObject lite och bestämt oss för att vi inte vill släppa det, älskar vi det bara för mycket och slutar plötsligt musen, vad skulle hända om du släpper musknappen då? Tja, vad tror du skulle hända? Jag kommer inte att svara på det för dig, jag ska bara hjälpa dig med koden för att få det att hända. I den sista koden, kommentera dessa tre raderna. Det här borde se väldigt bekant ut, vi använde just det här i knapphanteraren, förutom en variabel, MouseDragged. Vi kommer att använda det när vi kallar vår andra funktion:

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

Så om du frågar varför vi behöver den här timerhändelsen försökte du förmodligen inte ta ut det för att se vad som hände. Så gör det.

Denna nästa funktion är en av våra huvudfunktioner; det är pan-funktionen. Det är mycket involverat så låt oss dyka in i vår pseudokod:

 privat funktion moveIt (e: MouseEvent): void / * ok, så vad behöver vi den här funktionen att göra? * Det måste panorera vårt målobjekt. * så kan vi se om vi är över vårt målobjekt * / // om (vi är över vårt målobjekt) // // vilka verktyg ska vi behöva panorera? // well, kanske vi bör kontrollera om knappen är nere // om (knappen är nere) // // vi kan behöva ställa in knappen ner variabeln. buttonDown = true; // och om vi befinner oss i den här funktionen är vår knapp nere och // musen har flyttats - det är ett drag: så MouseDragged = true; // om vi flyttar objektet enligt musen flyttar bör vi // säkert veta var musen är: MouseCurrX, Y = nuvarande MouseX, Y; // Detta är en introduktion till vår konstgjorda mus prev, som förklaras // i nästa funktion. Ar står för "artificiell" eller "efter frigöring", // beroende på vad du föredrar. Det måste ställas in på vår tidigare föregående muspos. // arMousePrevX = MousePrevX; // arMousePrevY = MousePrevY; // då måste vi faktiskt flytta targetObject, // men kom ihåg våra variabler, moveX och moveY, så: // om moveX flytta x; // om moveY flytta y; // vi måste återställa vår förfall (friktion) tillbaka till det ursprungliga tillståndet: // Decay = originalDecay; // som borde slutföra om // // vad mer? // // vi ställer in vår buttondown till sant förut, så kan vi ställa in det som falskt här. // buttonDown = false; // Om detta inte är ett målklick, borde vi ställa in vår överTarget så felaktigt: // om (! TargetClick) // overTarget = false; // det är allt. // // det finns några saker som vi vill hända oavsett förhållandena. // först måste vi ställa in mousePrevX, Y variabel - FÖRE musen är // flyttad igen! // MousePrevX = eventObject.mouseX; // MousePrevY = eventObject.mouseY; // Här är två ytterligare variabler för att hålla reda på: xOpposideEdge och yOppositeEdge // vi testar för att se hur storleksordningen av vårt målobjekt är i relation // till vårt händelseobjekt; om en är större måste vi ändra beteendet hos studsen. // if (targetObject.width> eventObject.width) xOppositeEdge = true; // else xOppositeEdge = false; // om (targetObject.height> eventObject.height) yOppositeEdge = true; // else yOppositeEdge = false; // och slutligen måste vi stoppa och starta om vår timer. //t.stop (); //t.start (); //

Jag erkänner att detta är lite mer psuedo-y än det sista; det är av två anledningar: en, du vet inte vad som kommer och två, jag är bara väldigt glad över att komma till koden:

 privat funktion moveIt (e: MouseEvent): void // i vår pseudo-kod var det två villkor men vi kan kombinera då med en, // vi testar om vår händelse var en knapp ner och om vi är över vår mål, // om vi sedan flyttar målobjektet. om (e.buttonDown && overTarget) buttonDown = true; MouseDragged = true; MouseCurrX = eventObject.mouseX; MouseCurrY = eventObject.mouseY; // här är den artificiella / efter frisläppande en. igen, snälla få till det. arMousePrevX = MousePrevX; arMousePrevY = MousePrevY; / * Detta är viktigt, i vår pseudo var det "flytta målobjektet", * så vi måste översätta det. För att hjälpa oss skapar vi en lokal variabel * Topper för toppen och Sidan för sidan. * så låt oss titta på Topper (samma gäller Sider). * eventObject.mouseY tittar på var musen är inne i händelsenObject. * Vi tar bort vår MousePrev från det, och det kommer att ge oss hur mycket objektet * ska resa, så att Y kan resa 2 pixlar eller -2 pixlar beroende på * riktning, så vi tar den ändringen och lägger den till målets nuvarande * -position, men det händer inte än, det här är bara ett var. * / var Topper: int = (eventObject.mouseY - MousePrevY) + targetObject.y; var Sider: int = (eventObject.mouseX - MousePrevX) + targetObject.x; // här är var det händer, om moveY (kom ihåg från pseudokoden) då kan vi // ställa in målet för målet. if (moveY) targetObject.y = Topper; om (moveX) targetObject.x = Sidor; // så verkligen använder vi bara Topper och Sider för att tillfälligt lagra där // målobjektet ska flyttas till Decay = originalDecay ;  else buttonDown = false; om (! TargetClick) overTarget = false;  MousePrevX = eventObject.mouseX; MousePrevY = eventObject.mouseY; om (targetObject.width> eventObject.width) xOppositeEdge = true; annat xOppositeEdge = false; om (targetObject.height> eventObject.height) yOppositeEdge = true; annat yOppositeEdge = false; t.stop ); t.start (); 

Och nu panorerar vi.


Steg 8: Kasta, ut, repeterare!

Det här är den andra stora funktionen och med detta kommer vi att ha vår klass byggd! Klar för att panorera och kasta objekt som du tycker är lämplig! Det finns två funktioner som vi måste ta itu med först: throwIt (), som vi ställer in som en hanterare till MOUSE_UP-händelsen, och throwItOut (), som vi ställer som en hanterare till MOUSE_OUT-händelsen.

 privata funktionskastaIt (e: MouseEvent): void buttonDown = false; om (MouseDragged) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater);  privatfunktionskastaItOut (e: MouseEvent): void buttonDown = false; om (e.relatedObject == null || e.relatedObject == eventObject.parent) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater); 

Dessa två funktioner är nästan samma (trots allt gör de samma sak bara vid olika tidpunkter). I dem ställer vi knappen nedåt till falskt, eftersom det här är en mus-upp-händelse, och kontrollera om musen släpades med antingen MouseDragged (som vi satt i den sista funktionen) eller genom att markera "e.relatedObject"; det föremål som musen bara flyttat ut ur.

Om det släpades lägger vi till en annan lyssnare. ENTER_FRAME-händelsen är en riktigt cool en. Detta är grunden för vår animation; varje gång vi skriver in en ny ram körs () -funktionen. Det är det som gör det möjligt för oss att simulera en musdragning efter frisläppande (kom ihåg arMousePrevX, Y-variabeln? Det är vad det är för). Och det är allt kasta verkligen, simulerar en musdragning utan mus naturligtvis. Så vi har ganska mycket redan den funktion vi behöver, förutom att vi behöver byta samtalen till den aktuella muspositionen till vår konstgjorda musposition.

Nästan fick lite framför mig där. Så med dessa två händelsefunktioner, kastar och slänger, gör de samma sak men det om i den andra funktionen är värt att nämna. Jag kämpade ett tag för att försöka få denna funktionalitet, tills jag tittade på evenemanget lite närmare. Problemet försökte få målobjektet att fungera som om jag släppte knappen när markören lämnade händelseobjektet. Fortsätt, försök och gör det utan e.relatedObject. Jag hade nästan det ett par gånger, men kunde inte få det rätt. Vad e.relatedObject gör är att hitta vilket objekt du är på, efter händelsen heter. Det är därför det är så coolt. När vår markör lämnar filmen helt och hållet returnerar den en null, annars kommer det att returnera objektet du är på, så vi kan kontrollera om e.relatedObject är null eller är en förälder till händelsenObject. Det ger den rätta åtgärden vi letar efter.

I ovanstående funktioner ställer vi upp samtal till theRepeater (). Detta blir kasta-funktionen, och kom ihåg att det kommer att ringas varje gång vi skriver in en ny ram. Låt oss gå igenom denna rad efter rad:

 privat funktion theRepeater (e: Event): void // timern måste stoppas, försök ta bort det här och se vad som händer. t.stop (); // här är en lokal variabel som håller aktuell (falsk) markörposition. // ja det är bara "falskt" efter första gången. var oldxer: Number = MouseCurrX; var oldyer: Number = MouseCurrY; // nu, precis som vi gjorde tidigare, måste vi hitta skillnaden mellan vår nuvarande // och tidigare position. så hur skiljer det sig från tidigare? Varför? var xDiff: Number = MouseCurrX - arMousePrevX; var yDiff: Number = MouseCurrY - arMousePrevY; // Om knappen är nere, kommer vi inte att flytta längre, knappen kommer att stoppa åtgärden i det här fallet. om (! buttonDown) // ta skillnaden och tider den genom förfallet. Detta kommer att ge oss den nya // skillnaden, som kommer att vara något mindre än den sista, vilket är hur / / vi får friktionseffekten med detta. // t.ex. Om sönderfallet är 0,5 kommer det avstånd som flyttas halvera varje ram. xDiff = xDiff * Decay; yDiff = yDiff * Decay; // nästa är en av de förvirrande delarna för mig, detta rör inte objektet på // alla, det testar bara för att se om vårt målObject har nått kanten. om det har, // vi måste studsa tillbaka det. (det här kan ändras till en annan åtgärd om du vill ha det, kan du även ta bort det, vad händer om du gör det? Försök det! // i pan-funktionen ställer vi in ​​denna variabel, Motsatt, det är här vi ska använd det som "om måletObject är större än händelseobjektet" som vi ställer in // init () -funktionen. Jag går bara igenom x här eftersom y är // nästan densamma (vad är annorlunda? varför ? Tänk på det!) om (xOppositeEdge) / * så först, "bredden på eventObject, - bredden på targetObject - 50", * här är bredden på targetObject större än den för händelsenObject * detta kommer att tillåta motsatta kanten av målobjektet att ligga 50 px från * motsatt kant. Om du går till exempelfilmen och krympa bilden till * 10% och kasta den runt, öka storleken till 200% och försök märker * vilken kant gör vad, då kommer du att se skillnaden mellan studsen. * Det är det bästa sättet att förstå den här delen. * / 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;  // det här är om målobjektet är mindre än händelsenObject. annars / * så igen testar vi kanterna på måletObject mot * händelseobjektet. Den här gången handlar vi om samma kant (väl, * 5px utanför kanten). Så det kommer att studsa som om det träffar en vägg. * / 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);  om (yOppositeEdge) om (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;  annat om (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);  // ja, om du har frågor om den delen, skriv bara en kommentar om det och jag kommer att svara på dem. // Här är sidorna och Topper vars (precis som de från pan-funktionen). var sider: int = xDiff + targetObject.x; var Topper: int = yDiff + targetObject.y; // Vi måste ställa in det här redo för nästa gång. MouseCurrX = MouseCurrX + xDiff; MouseCurrY = MouseCurrY + yDiff; // och sedan om moveX, Y (igen som pan-funktionen) om (moveY) targetObject.y = Topper; om (moveX) targetObject.x = sider;  // och nu ställa in vår konstgjorda mus prev arMousePrevX = oldxer; arMousePrevY = oldyer; // och om vi inte är i friktionslösa läge (OriginalDecay = 1) // kommer vi att subtrahera en liten mängd från vårt förfall, till // ger det lite mer naturlig lättnad. if (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);  

Och med det är vår klass färdig.


Steg 9: Den färdiga klasskoden

Du kan ta tag i den färdiga koden från källkoden, kopplad längst upp i handledningen. Det är i PanAndThrow.as-klassen.


Steg 10: Gör något med det

För att göra något med detta måste vi gå tillbaka till MXML och lägga till några rader kod. Lägg till vår deklaration i den globala variabla sektionen, fyll i nedbrytningsmetoden och ring vår pan och kasta init () -funktionen. Med allt som läggs till, här är den fullständiga MXML-filen:

               

Slutsats

Nu har du en arbetspanna och kasta klassen! Jag hoppas att du är så upphetsad som jag är. Det finns mycket här och jag hoppas att jag kunde täcka allt och inte göra denna handledning för länge.

Jag hoppas att du gillade den här handledningen, tack för att du läste! Vänligen skicka in kommentarerna om du har några frågor.