Objekte werfen, indem Sie eine PanAndThrow-Klasse erstellen

In diesem Lernprogramm werden wir eine Pan & Throw-Klasse simulieren und beenden, die es uns ermöglicht, diesen Effekt zu jedem Element hinzuzufügen, das wir wollen. Dazu erstellen wir einen Bildbetrachter - nicht jedoch Ihren durchschnittlichen Betrachter. Hier wird gezoomt, geworfen, geschwenkt… Es klingt fast wie eine Ninja-App, huh?


Schritt 1: Einführung

Mit der Pan- und Throw-Klasse können Sie jedem ActionScript-Objekt, das Sie möchten, die Pan- und Wurf-Funktion hinzufügen. Obwohl dieses Tutorial speziell für Flex gedacht ist, kann die Klasse selbst überall verwendet werden, wo sich ActionScript befindet. Ich hatte diesen Effekt auf mehreren Websites gesehen, dann in Photoshop CS4 und entschied, dass ich dies auch für meine Projekte wollte.

Es gibt viele Anwendungen für diesen Effekt. In diesem Lernprogramm verwenden wir einen Bildbetrachter, mit dem Sie ein Bild vergrößern und verkleinern und die Reibung des Wurfeffekts ändern können. In diesem Tutorial geht es jedoch nicht wirklich um den Bildbetrachter, sondern um das Erstellen einer Schwenk- und Wurfklasse. Also fangen wir damit an. Öffnen Sie Ihren bevorzugten Flex-Editor und bringen Sie ein Projekt in Gang; Informationen dazu in Flex Builder finden Sie in den Adobe LiveDocs. Öffnen Sie nach dem Erstellen Ihres Projekts die MXML-Datei. Wir müssen etwas Code hinzufügen, bevor wir unsere Klasse erstellen.


Schritt 2: Unser MXML

Da dies nicht der Hauptteil des Tutorials ist, werde ich nicht viel Zeit hier verbringen. Wenn Sie Fragen zu diesem Abschnitt haben, die nicht behandelt werden, können Sie in den Kommentaren nachfragen. Hier sind zunächst die MXML-Objekte, die in die Anwendung eingefügt werden sollen:

            

Sie werden die vier Funktionen bemerken, die in den Tags aufgerufen werden: init (), changeDecay (), smoothImage () und zoom (). Wir müssen diese Funktionen aufschreiben. Dies ist der Code zwischen dem Stichworte:

 import mx.states.SetStyle; import mx.effects.Move; mx.containers.HBox importieren; import mx.containers.Box; private var imageWidth: Number = 0; private var imageHeight: Number = 0; private var mover: Move = new Move (); // Dies wird aufgerufen, wenn die Anwendung die private Funktion init (): void // lädt. // Dieses Ereignis bietet die Möglichkeit, unsere Steuerelemente mit einem Klick auszublenden und anzuzeigen. control.addEventListener (MouseEvent.CLICK, controlClick); mover.target = Kontrolle;  // Diese Funktion vergrößert und verkleinert unser Bild entsprechend dem Wert unseres Zoom-Schiebereglers. private Funktion zoom (): void inside.width = (imageWidth * hSlider.value) / 100; inside.height = (imageHeight * hSlider.value) / 100;  // Dies wird aufgerufen, wenn sich unser Bild ändert. private function smoothImage (ev: Event): void // Bildglättung einstellen, damit das Bild bei der Transformation besser aussieht. var bmp: Bitmap = ev.target.content als Bitmap; bmp.smoothing = true; imageWidth = inside.width; imageHeight = inside.height;  // Wir werden diese noch nicht private Funktion changeDecay () verwenden: void // Dies wird den Zerfallswert (Reibungswert) unserer Klasse ändern, wenn wir dort ankommen.  private function controlClick (e: MouseEvent): void mover.play (); // Diese Funktion verbirgt / zeigt die Steuerelemente bei Klick if (control.y! = -5) mover.stop (); mover.yTo = -5; mover.play ();  else if (e.target == control) mover.stop (); mover.yTo = (Kontrollhöhe - 10) * -1; mover.play (); 

Sobald Sie MXML installiert haben, müssen Sie einen Ordner mit dem Namen "classes" in demselben Ordner wie Ihre MXML-Datei erstellen. (Bei Verwendung von Flash muss sich der Ordner im selben Verzeichnis wie Ihre FLA-Datei befinden.) Dies ist unser Klassenpaket. Dort wird die Datei PanAndThrow.as gespeichert. Erstellen Sie in Flex Builder eine neue Klasse, fügen Sie sie in das Klassenpaket ein und nennen Sie sie PanAndThrow. Dadurch wird Ihre Klasse erstellt - Standardstil.


Schritt 3: Die Herstellung einer Klasse

Hier ist unsere grundlegende PanAndThrow-Klasse. Speichern Sie es als PanAndThrow.as in Ihrem neuen "classes" -Ordner.

 // Namespace-Deklarationspaketklassen // Klassendeklaration der öffentlichen Klasse PanAndThrow / * Dies wird Konstruktor genannt. Diese Methode / Funktion wird aufgerufen, wenn Sie * eine Instanz Ihres Objekts erstellen oder Ihr Objekt instanziieren. * Für diese Klasse machen wir nichts, weil wir alles tun werden * in der Init-Funktion * / public-Funktion PanAndThrow () 

Welche Variablen und Funktionen benötigen wir in unserer PanAndThrow-Klasse? Um das zu verstehen, können Sie sich fragen: "Was muss meine Klasse tun, was muss sie wissen und was muss sie tun können?" Lassen Sie uns also einen Pseudo-Code erstellen.

Schnelle Notiz

Als ich diese Klasse zum ersten Mal entwickelte, habe ich alles in den Konstruktor eingefügt, was jedoch zu einem Problem führte, als ich die Start- und Stop-Methoden aufgrund des Gültigkeitsbereichs erstellt habe. Ich konnte diese Klasse nicht mit allen erforderlichen Informationen in einem globalen Bereich instanziieren. Ich habe daher eine init () - Funktion erstellt, sodass die Instanz von außerhalb der Klasse gestartet und gestoppt werden konnte.


Schritt 4: Unser Pseudo-Code

"Pseudo-Code" bedeutet nur gefälschten Code, mit dem wir uns überlegen können, welcher Code wirklich benötigt wird.

 Paketklassen public class PanAndThrow / * Dies sind die Variablen, die wir erstellen. Was müssen wir also wissen? * anObjectToThrow; * anObjectToThrowItIn; * ObjectLocation; * PreviousObjectLocation; * Verfall; // für die Physik * Dies sind die offensichtlichen, aber diese Liste wird um einiges größer *, da wir genau sehen, was wir in unseren Funktionen benötigen. * / public function PanAndThrow ()  / * Also, was wird unsere Klasse tun? ? * drin(); // muss gestartet werden * stop (); // wir wollen es irgendwie stoppen können. * Start(); // Wenn wir aufhören, müssen wir es erneut starten können. * pan (); * werfen(); * /

Da wir nun einen Pseudo-Code haben, können wir mit dem Aufbau der Klasse beginnen. Beginnen wir mit der Funktion init (). Dies führt uns auch zu einem der Prinzipien der objektorientierten Programmierung Verkapselung, die sich mit dem Zugriff auf Teile des Codes befasst.

Dieser Code sollte in die PanAndThrow-Klasse aufgenommen werden, die wir gerade gestartet haben. (Nicht sicher, wo? Überprüfen Sie den Quick-Tip der Dokumentklasse.)

 // Dank OOP können eine untergeordnete Klasse und eine übergeordnete Klasse (eine Klasse, die die untere Klasse erweitert) verwendet werden. Wie hier erweitert fast jedes Objekt, das Sie verwenden, die // Sprite-Klasse. Also muss ich nur nach einem Sprite-Objekt fragen und Sie können eine Box oder einen Button geben. private var targetObject: Sprite = new Sprite (); private var eventObject: Sprite = neuer Sprite (); private var originalDecay: Number = .9; private var buttonDown: Boolean = false; private var moveY: Boolean = true; private var moveX: Boolean = true; private var TargetClick: Boolean = true; // Wir werden dies verwenden, um zu überprüfen, wie lange sich Ihre Maus auf einem Objekt befand, ohne sich zu bewegen. private var t: Timer; private var timerInterval: int = 100; öffentliche Funktion 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 = neuer Timer (TimerInterval); Start(); 

Nur ein paar Dinge, auf die ich hinweisen möchte. In der Funktion für init habe ich einige der Argumente auf einen Wert gesetzt. Das heißt, ich gebe ihnen einen Standardwert und mache sie daher optional. Wenn Sie Standardwerte für Argumente einer Funktion festlegen, müssen diese die letzten Parameter sein. Sie dürfen keine erforderliche Variable nach einer optionalen Variable haben. Der Grund, warum ich Standardvariablen hinzugefügt habe, besteht darin, den Aufruf zu verkürzen, wenn wir die Standardeinstellungen verwenden. Ich kann PanAndThrow (Mover, Eventer) aufrufen. und mache statt PanAndThrow (Mover, Enventer, Decayer, yVal, ...) und so weiter.

Haben Sie sich jemals gefragt, was "privat" oder "öffentlich" vor Funktionen und Variablen bedeutet? Das ist die Belichtung des Objekts. Auf ein "öffentliches" Objekt kann von jeder anderen Klasse zugegriffen werden. Ein "privates" Objekt kann nur von den anderen Mitgliedern dieser Klasse gesehen werden. Ein "geschütztes" Objekt ist vor allem verborgen, außer Klassen, die sich in demselben Paket befinden.

Wir möchten in der Lage sein, den Verfall von MXML zu ändern, so dass wir einen öffentlichen Hook benötigen, um zu unserer privaten Variablen zu gelangen. Hier kommen Getter- und Setter-Funktionen ins Spiel:

 private var originalDecay: Number = .9; öffentliche Funktion get decay (): Number return originalDecay; 

Das ist eine "Getter" -Funktion. Das bedeutet, dass außerhalb von Klassen die PanAndThrow-Klasse über eine öffentliche Variable mit dem Namen "Decay" verfügt. Wenn sie versuchen, darauf zuzugreifen, geben wir ihnen den Wert unserer (privaten) originalDecay-Variablen zurück.

Setter-Funktionen sind fast gleich, aber die äußeren Klassen können den Wert unserer öffentlichen Variablen "fake" ändern:

 Public Function Set Decay (Wert: Number): void originalDecay = Wert; 

Diese sind nützlich, weil Sie die Logik in einen Setzer setzen können, um zu begrenzen, was in Ihrer privaten var enthalten ist. Wenn Sie beispielsweise im MXML-Tag für eine Box eine Zahl eingeben, erhalten Sie eine festgelegte Höhe. Wenn Sie ein% setzen (die Zahl zu einer Zeichenfolge machen), erhalten Sie eine prozentuale Höhe. Das ist im Code für den Höhensetzer der Box integriert. Nun, da wir unseren Getter und Setter haben, können Sie auf die Decay-Variable wie folgt von außerhalb der Klasse zugreifen:

 var pt: PanAndThrow = new PanAndThrow (); pt.init (Ziel, Elternteil); pt.decay = .7;

Schritt 5: Starten, Hören, Stoppen

Wir haben unsere Klasse, einige lokale Variablen und eine init () - Funktion. Lass uns jetzt etwas tun. Am Ende der init () - Funktion haben wir "start ();" Also machen wir die Startfunktion. Meistens sind es nur ein paar Zuhörer:

 public function start (): void // Mit gedrückter Maus wollen wir unsere Pan-Aktion starten, müssen jedoch // unseren OnlyMoveOnTargetClick überprüfen können, den wir unserem globalen Feld TargetClick targetObject.addEventListener (MouseEvent) zugewiesen haben. MOUSE_DOWN, handleOverTarget); eventObject.addEventListener (MouseEvent.MOUSE_DOWN, handleOverTarget); // Wenn wir unser pan aufrufen, verwendet es einen Mausbewegungslistener, dh es wird jedes Mal aufgerufen, wenn die // Maus bewegt wird. Wir müssen also einschränken, wann sich das Zielobjekt bewegt. eventObject.addEventListener (MouseEvent.MOUSE_MOVE, moveIt); // Dies ist das Objekt nach einem Schwenk zu werfen, dies ist ein wenig schwierig, da die throwIt () - Funktion einen anderen Listener aufruft. targetObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); eventObject.addEventListener (MouseEvent.MOUSE_UP, throwIt); // Die throwItOut-Methode bewirkt, dass unser Objekt so aussieht, als ob wir die Maustaste loslassen würden, aber es wird ausgelöst, wenn // die Maus das übergeordnete Objekt verlässt. targetObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); eventObject.addEventListener (MouseEvent.MOUSE_OUT, throwItOut); // Dies ist der Timer-Listener. Hier wird geprüft, ob Sie die Maus ein wenig gedrückt halten. Ich erkläre die Notwendigkeit dafür, wenn wir zur timerOut () - Funktion t.addEventListener (TimerEvent) gelangen. TIMER, timerOut); t.start (); 

Die stop () - Funktion ist fast gleich, aber wir entfernen die Zuhörer.

 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 (); 

Jetzt können wir hören, was los ist, lassen Sie uns jede dieser Listener-Funktionen durchgehen.


Schritt 6: MouseEvent.MOUSE_DOWN

Wir werden uns den Ereignishandler handleOverTarget ansehen.

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

Diese Funktion wird aufgerufen, wenn für das Ereignisobjekt oder das Zielobjekt ein Ereignis MOUSE_DOWN vorliegt. Es ist sehr wichtig zu beachten, dass der Handler auch dann aufgerufen wird, wenn ein Listener auf ein übergeordnetes Objekt gesetzt wird, wenn das Ereignis für ein untergeordnetes Objekt auftritt. In diesem Fall ist mein Zielobjekt ein Kind des Ereignisobjekts. Wenn ich auf das Zielobjekt klicke, wird diese Methode zweimal aufgerufen: zuerst für die untere Maustaste beim Kind und dann als zweite für die untere Maustaste beim Elternteil. Das ist wirklich wichtig, weil wir entscheiden werden, ob die Maus das Zielobjekt bewegen kann. Wir müssen also wirklich wissen können, ob diese Maus beim Kind war oder nicht.

Die erste Anweisung ist ziemlich einfach: Setzen Sie unsere Klassenvariable buttonDown auf true.

Die nächsten beiden sind auch ziemlich einfach, außer ich habe ein paar neue Variablen eingeführt, die in unsere Klassenvariablenliste aufgenommen werden müssen: MousePrevX, MousePrevY, arMousePrevX, arMousePrevY, MouseCurrX und MouseCurrY. Diese werden häufig in den Drag & Pan-Funktionen verwendet, also werde ich bis dahin warten, um darüber zu sprechen.

Die if-Anweisung prüft, ob das angeklickte Objekt das Zielobjekt ist. Denken Sie daran, dass TargetClick auf das Argument gesetzt wurde, das wir an init () übergeben haben, OnlyMoveOnTargetClick; Wenn dies falsch ist, möchten wir jedes untergeordnete Objekt beim Klicken als Zielobjekt behandeln. Deshalb haben wir den Check "||! TargetClick".

Das ist der leichte Teil. Der nächste Teil ist etwas kniffliger.

Das e.currentTarget gibt das Objekt zurück, das das Ereignis ausgelöst hat. Das e.target gibt das Objekt zurück, das das eigentliche Ziel war. Also könnte ich das sagen, richtig?

 if (e.target == targetObject ||! TargetClick) overTarget = true;  else overTarget = false; 

Das ist einfach genug, aber es ist falsch. Was ist, wenn mein Zielobjekt Kinder hat? Dann kann mein e.currentTarget das targetObject sein, aber das e.target ist das Kind von targetObject und wird nicht übereinstimmen. Wir möchten, dass sich dies auch dann bewegt, wenn wir uns auf ein untergeordnetes Objekt bewegen.

Hier kommt also String.search zur Rettung. Wenn unser currentTarget nicht unser targetObject ist, verwenden wir ein "else if", um zu sehen, ob wir unser Zielobjekt im Ziel finden können. e.target.toString () erzeugt so etwas: "application2.eventobject3.targetobject2.targetchild4" für unser Zielobjekt, wo targetObject.toString () so etwas wie "application2.eventobject3.targetobject2" erzeugen wird Finden Sie heraus, ob unser Ziel ein Kind unseres Zielobjekts ist:

 e.target.toString (). search (targetObject.toString ())

Wenn es eine Übereinstimmung gibt, wird der erste Index der Übereinstimmung zurückgegeben, oder wenn keine Übereinstimmung vorhanden ist, wird eine -1 zurückgegeben. Wir können also nur sehen, ob der Wert größer als -1 ist, und die Viola. Das Objekt wurde gefunden Das Anklicken ist ein Kind unseres targetObject.

(Wir könnten die Kinder oder die übergeordneten Objekte des Objekts über die Funktion getChildAt () und die übergeordnete Eigenschaft überprüfen. Dies ist jedoch eine ordentliche Alternative.)


Schritt 7: TimerOut und Pan

Die Timer-Funktion ist auch recht einfach, zumal wir das schon gemacht haben. Nun, das hätte ich schon fast gemacht. Wenn wir unser kleines targetObject ein wenig herumgezogen haben und uns entschieden haben, dass wir es nicht loslassen möchten, lieben wir es einfach zu sehr und stoppen abrupt die Maus. Was würde passieren, wenn Sie die Maustaste an diesem Punkt loslassen? Nun, was denkst du würde passieren? Ich werde das nicht für Sie beantworten, ich werde Ihnen nur mit dem Code helfen, damit es nicht passiert. Kommentieren Sie im letzten Code diese drei Zeilen aus. Dies sollte wirklich vertraut aussehen, wir haben dies nur im Button-Down-Handler verwendet, außer für eine Variable, MouseDragged. Wir werden das verwenden, wenn wir unsere andere Funktion aufrufen:

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

Wenn Sie also fragen, warum wir dieses Timer-Ereignis benötigen, haben Sie wahrscheinlich nicht versucht, herauszufinden, was passiert ist. Also mach das.

Diese nächste Funktion ist eine unserer Hauptfunktionen. Es ist die Pan-Funktion. Wir haben viel zu tun, also tauchen wir in unseren Pseudo-Code ein:

 private Funktion moveIt (e: MouseEvent): void / * ok, also, was brauchen wir diese Funktion? * es muss unser Zielobjekt schwenken. * also sehen wir, ob wir über unserem Zielobjekt sind * / // wenn (wir sind über unserem Zielobjekt) // // Welche Werkzeuge müssen wir schwenken? // Nun, vielleicht sollten wir prüfen, ob die Schaltfläche unten ist. // Wenn (Schaltfläche unten) // // müssen wir möglicherweise die Variable für die Schaltfläche unten setzen. buttonDown = true; // und wenn wir uns an dieser Stelle in dieser Funktion befinden, ist unsere Schaltfläche unten und // die Maus hat sich bewegt - das ist ein Ziehen: also MouseDragged = true; // Wenn wir das Objekt entsprechend der Mausbewegung verschieben, sollten wir // wahrscheinlich wissen, wo sich unsere Maus befindet: MouseCurrX, Y = current MouseX, Y; // Dies ist eine Einführung in unsere künstliche Maus prev, die // in der nächsten Funktion erklärt wird. Das ar steht für "künstlich" oder "nach der Veröffentlichung", je nachdem, was Sie bevorzugen. Das muss auf unsere aktuelle vorherige Mausposition gesetzt werden. // arMousePrevX = MousePrevX; // arMousePrevY = MousePrevY; // dann müssen wir das targetObject tatsächlich verschieben, // aber unsere Variablen merken, moveX und moveY, also: // wenn moveX move x; // wenn moveY verschieben y; // Wir müssen unseren Decay (Reibung) auf den ursprünglichen Zustand zurücksetzen: // Decay = originalDecay; // das sollte fertig sein wenn // // was noch? // // Wir haben unseren buttonDown vorher auf true gesetzt, also setzen wir ihn hier auf false. // buttonDown = false; // Wenn dies kein Zielklick ist, sollten wir unser overTarget auf false setzen, also: // if (! TargetClick) // overTarget = false; // das ist es. // // Es gibt ein paar Dinge, die wir unabhängig von den Bedingungen erreichen möchten. // Zuerst müssen wir unsere mousePrevX, Y-Variable setzen - BEVOR die Maus // erneut bewegt wird! // MousePrevX = eventObject.mouseX; // MousePrevY = eventObject.mouseY; // Hier sind zwei weitere Variablen, auf die Sie achten sollten: xOpposideEdge und yOppositeEdge // Wir testen, um zu sehen, wie groß das Zielobjekt in Bezug auf unser Ereignisobjekt ist. Wenn einer größer ist, müssen wir das Verhalten des Abpralls ändern. // if (targetObject.width> eventObject.width) xOppositeEdge = true; // else xOppositeEdge = false; // if (targetObject.height> eventObject.height) yOppositeEdge = true; // sonst yOppositeEdge = false; // und zum Schluss müssen wir unseren Timer stoppen und erneut starten. //t.stop (); //t.start (); //

Ich gebe zu, das ist ein bisschen mehr Pseudo als das letzte; Das ist aus zwei Gründen: Erstens wissen Sie nicht, was kommt, und zweitens bin ich einfach sehr gespannt auf den Code:

 private Funktion moveIt (e: MouseEvent): void // In unserem Pseudo-Code waren dies zwei Bedingungen, aber wir können sie zu einer kombinieren. // Wir testen, ob unser Event eine Schaltfläche gedrückt hat und ob wir über unserem stehen target // Wenn wir es sind, verschieben wir das Zielobjekt. if (e.buttonDown && overTarget) buttonDown = true; MouseDragged = true; MouseCurrX = eventObject.mouseX; MouseCurrY = eventObject.mouseY; // Hier ist die künstliche / nach der Veröffentlichung. wieder, gut zu dem kommen. arMousePrevX = MousePrevX; arMousePrevY = MousePrevY; / * Dies ist das Wichtige, in unserem Pseudo war es "Zielobjekt verschieben", * also müssen wir das übersetzen. Um uns zu helfen, erstellen wir eine lokale Variable * Topper für die Oberseite und Sider für die Seite. * Schauen wir uns also Topper an (das gleiche gilt für Sider). * eventObject.mouseY prüft, wo sich unsere Maus im eventObject befindet. * Wir nehmen unsere MousePrev davon weg, und das gibt uns die Höhe des Objekts *, so dass das Y je nach * Richtung um 2 Pixel oder -2 Pixel wandern kann, also nehmen wir diese Änderung und fügen sie dem Ziel hinzu Aktuelle * Position, aber das passiert noch nicht, das ist nur eine Variation. * / var Topper: int = (eventObject.mouseY - MousePrevY) + targetObject.y; var Sider: int = (eventObject.mouseX - MousePrevX) + targetObject.x; // Hier passiert es, wenn moveY (aus dem Pseudo-Code erinnern), dann // können wir die Position des Ziels festlegen. if (moveY) targetObject.y = Topper; if (moveX) targetObject.x = Sider; // Wir verwenden also nur Topper und Sider, um temporär zu speichern, wo das // Zielobjekt nach Decay = originalDecay verschoben werden soll ;  else buttonDown = false; if (! TargetClick) overTarget = false;  MousePrevX = eventObject.mouseX; MousePrevY = eventObject.mouseY; if (targetObject.width> eventObject.width) xOppositeEdge = true; else xOppositeEdge = false; if (targetObject.height> eventObject.height) yOppositeEdge = true; else yOppositeEdge = false; t.stop () ); t.start (); 

Und jetzt panning wir.


Schritt 8: Werfen Sie es aus, Repeater!

Dies ist die zweite große Funktion und damit werden wir unsere Klasse bauen lassen! Bereit zu schwenken und jedes Objekt zu werfen, das Sie für richtig halten! Es gibt zwei Funktionen, die wir zuerst ansprechen müssen: throwIt (), die wir als Handler für das MOUSE_UP-Ereignis festlegen, und throwItOut (), die wir als Handler für das MOUSE_OUT-Ereignis festlegen.

 private Funktion throwIt (e: MouseEvent): void buttonDown = false; if (MouseDragged) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater);  private Funktion throwItOut (e: MouseEvent): void buttonDown = false; if (e.relatedObject == null || e.relatedObject == eventObject.parent) eventObject.addEventListener (Event.ENTER_FRAME, theRepeater); 

Diese beiden Funktionen sind fast gleich (schließlich machen sie zu unterschiedlichen Zeiten das gleiche). In ihnen setzen wir buttonDown auf false, weil dies ein Mouse-Up-Ereignis ist, und prüfen, ob die Maus gezogen wurde, entweder mit MouseDragged (das wir in der letzten Funktion festgelegt haben) oder durch Überprüfen von "e.relatedObject"; das Objekt, aus dem die Maus gerade herausgefahren ist.

Wenn es gezogen wurde, fügen wir einen anderen Listener hinzu. Das Ereignis ENTER_FRAME ist ein wirklich cooles Ereignis. Dies ist die Basis unserer Animation. Jedes Mal, wenn wir einen neuen Frame eingeben, wird die throw () - Funktion ausgeführt. Dies ermöglicht es uns, nach dem Release ein Ziehen der Maus zu simulieren (erinnern Sie sich an die Variable arMousePrevX, Y?). Und das ist alles, was der Wurf wirklich tut, indem er eine Mausbewegung simuliert, natürlich ohne Maus. Wir haben also ziemlich genau die Funktion, die wir brauchen, außer dass wir die Aufrufe der aktuellen Mausposition an unsere künstliche Mausposition ersetzen müssen.

Ich bin dort fast ein bisschen voraus. Mit diesen beiden Ereignisfunktionen, throwIt und throwItOut, tun sie dasselbe, aber das tun sie ob in der zweiten Funktion ist es erwähnenswert. Ich bemühte mich eine Weile, diese Funktionalität zu erhalten, bis ich mir die Veranstaltung etwas näher ansah. Das Problem bestand darin zu versuchen, das Zielobjekt so zu veranlassen, als würde ich die Schaltfläche loslassen, wenn der Cursor das Ereignisobjekt verlassen hat. Versuchen Sie dies ohne das e.relatedObject. Ich hatte es schon ein paar Mal fast geschafft, konnte es aber nicht richtig machen. Das e.relatedObject sucht nach dem Ereignis, an dem sich das Objekt befindet. Deshalb ist es soooo cool. Wenn der Cursor den Film insgesamt verlässt, wird eine Null zurückgegeben. Andernfalls wird das Objekt zurückgegeben, in dem Sie sich befinden. Wir können also prüfen, ob e.relatedObject Null ist oder ein übergeordnetes Element für eventObject ist. Das führt zu der richtigen Aktion, nach der wir suchen.

In den oben genannten Funktionen richten wir Aufrufe an den Repeater () ein. Dies wird die Throw-Funktion sein. Denken Sie daran, dass sie jedes Mal aufgerufen wird, wenn wir einen neuen Frame eingeben. Lassen Sie uns diese Zeile für Zeile durchgehen:

 private Funktion theRepeater (e: Event): void // Der Timer muss gestoppt werden. Versuchen Sie es zu entfernen und sehen Sie, was passiert. t.stop (); // Hier ist eine lokale Variable, die die aktuelle (falsche) Cursorposition hält. // na ja, es ist nur "fake" nach dem ersten mal. var oldxer: Number = MouseCurrX; var oldyer: Number = MouseCurrY; // Wie jetzt müssen wir den Unterschied zwischen unserer aktuellen // und vorherigen Position ermitteln. Wie unterscheidet sich das von vorher? Warum? var xDiff: Number = MouseCurrX - arMousePrevX; var yDiff: Number = MouseCurrY - arMousePrevY; // Wenn der Button unten ist, bewegen wir uns nicht mehr, der Button stoppt die Aktion in diesem Fall. if (! buttonDown) // Nimm die Differenz und mal den Verfall. Dies gibt uns die neue // Differenz, die etwas kleiner sein wird als die letzte, und // wie wir damit den Reibungseffekt erhalten. // z.B. Wenn Decay gleich 0,5 ist, halbiert sich die zurückgelegte Entfernung bei jedem Bild. xDiff = xDiff * Decay; yDiff = yDiff * Decay; // Weiter ist einer der verwirrenden Teile für mich, das bewegt das Objekt nicht bei // allem, es testet nur, ob unser targetObject die Kante erreicht hat. Wenn ja, müssen wir es zurückholen. (Dies könnte in eine andere Aktion geändert werden, wenn Sie wollen, Sie könnten sie sogar entfernen. Was passiert, wenn Sie es tun? Versuchen Sie es! // In der Pan-Funktion setzen wir diese Variable, OppositeEdge, hier werden wir // Verwenden Sie das "wenn das targetObject größer ist als das Event-Objekt", das wir in // der init () - Funktion setzen. Ich gehe hier nur durch das x, weil das y fast gleich ist (was ist anders? Warum?) Denken Sie darüber nach!) Wenn (xOppositeEdge) / * so zuerst, "die Breite des eventObjects, - die Breite des targetObject-50", * ist hier die Breite des targetObject größer als die des eventObject * this Wenn Sie zum Beispielfilm gehen und das Bild auf * 10% verkleinern und umherwerfen, erhöhen Sie die Größe auf 200% und versuchen Sie und Beachten Sie * Welche Kante macht was, dann werden Sie den Unterschied zwischen den Abprallern sehen. * Dies ist der beste Weg, um diesen Teil zu verstehen. * / 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;  // Dies ist der Fall, wenn das Zielobjekt kleiner als das Ereignisobjekt ist. else / * also testen wir erneut die Kanten des targetObjects mit dem * event-Objekt. Dieses Mal haben wir es mit der gleichen Kante zu tun (gut, * 5px außerhalb der Kante). Also hüpft das, als würde es gegen eine Wand schlagen. * / 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);  if (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;  else 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);  // gut, wenn Sie Fragen zu diesem Teil haben, schreiben Sie einfach einen Kommentar dazu und ich werde sie beantworten. // Hier sind die Sider- und Topper-Vars (genau wie bei der Pan-Funktion). var sider: int = xDiff + targetObject.x; var Topper: int = yDiff + targetObject.y; // Wir müssen dies für den nächsten Durchlauf vorbereiten. MouseCurrX = MouseCurrX + xDiff; MouseCurrY = MouseCurrY + yDiff; // und dann das if moveX, Y (wieder wie die pan-Funktion) if (moveY) targetObject.y = Topper; if (moveX) targetObject.x = sider;  // und setzen Sie jetzt unsere künstliche Maus prev arMousePrevX = oldxer; arMousePrevY = oldyer; // und wenn wir uns nicht im reibungslosen Modus befinden (OriginalDecay = 1), // werden wir einen kleinen Betrag von unserem Zerfall abziehen, um // eine etwas natürlichere Lockerung zu erhalten. 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);  

Damit ist unsere Klasse beendet.


Schritt 9: Der abgeschlossene Klassencode

Sie können den vollständigen Code aus dem Quellcode herunterladen, der oben im Lernprogramm verlinkt ist. Es ist in der PanAndThrow.as-Klasse.


Schritt 10: Machen Sie etwas damit

Um etwas damit zu tun, müssen wir zur MXML zurückkehren und ein paar Zeilen Code hinzufügen. Fügen Sie unsere Deklaration im Abschnitt für globale Variablen hinzu, geben Sie die Decay-Methode ein und rufen Sie unsere pan and throw-Funktion (init ()) auf. Mit all dem, was hinzugefügt wurde, ist hier die vollständige MXML-Datei: