AS3-Tutorium: Flash: Butterfly 06 external code: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Kowa (Diskussion | Beiträge)
Kowa (Diskussion | Beiträge)
Keine Bearbeitungszusammenfassung
 
(52 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{AS3-Tutorium:Flash:Butterfly:Menü}}
{{AS3-Tutorium:Flash:Butterfly:Menü}}


=Verbesserung der vierten Version des Schmetterling-Movies=
=Verbesserung der fünften Version des Schmetterling-Movies=


In [[AS3-Tutorium: Flash: Butterfly 05 external code]] wurde der Code aus der Hauptzeitleiste in eine Klasse ausgelagert.
In [[AS3-Tutorium: Flash: Butterfly 05 external code]] wurde der Code aus der Hauptzeitleiste in eine Klasse ausgelagert.
Nun soll auch noch der Code vom Schmetterlings-Movie so weit wie möglich ausgelagert werden (ohne das Verhalten des Filmes zu ändern.)
Nun soll auch noch der Code vom Schmetterlings-Movie so weit wie möglich ausgelagert werden (ohne das Verhalten des Filmes zu ändern.)
<noinclude>


<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_2/butterfly_06_external_code_2.swf</swf>
<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code/Butterfly06Flash11.swf</swf>
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_2/ Musterlösung]: butterfly_06_external_code_2.swf'''
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS5)]'''
([http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs5/butterfly/butterfly_06_external_code/ SVN-Repository])
 
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs4/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS4)]'''
([http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs4/butterfly/butterfly_06_external_code/ SVN-Repository])
</noinclude>


==Der Code des Schmetterlingsmovies wird ausgelagert==  
==Der Code des Schmetterlingsmovies wird ausgelagert==  


* In der Bühne: Doppelklick auf das Icon vor dem Symbol <code>ButterflyMovie</code> → Die Definition des Symbols wird in der Bühne geöffnet.
# Die Datei <code>Butterfly05Flash.fla</code> unter dem Namen <code>Butterfly06Flash.fla</code> speichern und mit dieser Datei weiterarbeiten.
* In der Bühne: Rechtsklick Icon vor dem Symbol <code>ButterflyMovie</code> → <code>Eigenschaften</code> → <code>Erweitert</code> aufklappen → Haken vor <code>Export für ActionScript</code>, kein Haken vor <code>Export in Bild 1</code>, Klasse: <code>ButterflyMovie</code> → <code>OK</code> → <code>OK</code>
# In der Bibliothek: Doppelklick auf das Icon vor dem Symbol <code>ButterflyMovie</code> → Die Definition des Symbols wird in der Bühne geöffnet.
* <code>Datei</code> → <code>Neu</code> → <code>ActionScript 3.0-Klasse</code> → <code>OK</code> -> Klassenname: <code>ButterflyMovie</code>
# In der Bibliothek: Rechtsklick auf das Icon vor dem Symbol <code>ButterflyMovie</code> → <code>Eigenschaften</code> → <code>Erweitert</code> aufklappen → Haken vor <code>Export für ActionScript</code>, Haken vor <code>Export in Bild 1</code>, Klasse: <code>ButterflyMovie</code> → <code>OK</code> → <code>OK</code>
* <code>Datei</code> → <code>Datei speichern unter</code> → <code>ButterflyMovie.as</code> (im selben Ordner wie die zugehörige <code>fla</code>-Datei.)
# <code>Datei</code> → <code>Neu</code> → <code>ActionScript 3.0-Klasse</code> (CS5) bzw.  <code>ActionScript-Datei</code> (CS4 und früher) → <code>OK</code><br/> Nur in CS5: -> Klassenname: <code>ButterflyMovie</code> → <code>OK</code>
# <code>Datei</code> → <code>Datei speichern unter</code> → <code>ButterflyMovie.as</code> (im selben Ordner wie die zugehörige <code>fla</code>-Datei.)
 
'''Achtung''': Die <code>scripts</code>-Ebene des Butterfly-Movies wird — im Gegensatz zur <code>scripts</code>-Ebene des Main-Movies — nicht gelöscht.
Der ActionScript-Code wird allerdings deutlich vereinfacht: In einem Frame steht zum Schluss höchstens ein Methodenaufruf (siehe weiter unten).


In die Datei <code>ButterflyMovie.as</code> wird folgender Code eingefügt:
In die Datei <code>ButterflyMovie.as</code> wird folgender Code eingefügt:


<source lang="actionscript">package
<source lang="actionscript3">package
{
{
   import flash.display.MovieClip;
   import flash.display.MovieClip;
  import flash.events.Event;
 
  import flash.events.MouseEvent;
   public class ButterflyMovie extends MovieClip
 
   public class Main extends MovieClip
   {
   {
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
     // MovieClips on the stage
     // Attributes
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
      
      
     public var mc_user_input: MovieClip;
     public var roundsToFly: int = 0;
    public var mc_butterfly:  MovieClip;
 
   
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
     // Constructor
     // Constructor
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
      
      
     public function Main()
     public function ButterflyMovie()
     {
     {
       mc_user_input.mc_button_start.addEventListener(MouseEvent.CLICK, o_start);  
       stop();
     }
     }
      
      
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
     // Observer methods
     // Methods called from within the timeline
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////


     private function o_start(p_event: MouseEvent): void
     public function testNumberOfRounds(): void
     {
     {
       mc_user_input.visible = false;
       if (roundsToFly == 0)
     
        gotoAndPlay("lb_end");
      var l_rounds_to_fly: Number = parseInt(mc_user_input.mc_input_rounds.text);
    }


      if (isNaN(l_rounds_to_fly) || l_rounds_to_fly < 0)
    public function decrementNumberOfRounds(): void
        l_rounds_to_fly = 0;
    {
 
       roundsToFly--;
       mc_butterfly.roundsToFly = l_rounds_to_fly;
//    if (roundsToFly > 0)
       mc_butterfly.gotoAndPlay("lbStart");
       gotoAndPlay("lb_start");
     }
     }
 
     /////////////////////////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////////////////////////
     // End of class
     // End of class
Zeile 65: Zeile 72:
}</source>
}</source>


Eine Flash-Klasse ist immer in einem <code>package</code> enhalten. Wenn die
Die öffentlich zugängliche [[Zustandasvariable]] <code>roundsToFly</code>
Klasse im selben Ordner wie der Flash-Film gespeichert wird, gibt es keinen
wurde in die Klasse verlagert. Außerdem wurden zwei Methoden definiert, die den
Package-Namen. Wird dagegen die Datei beispielsweise in einem  Unterordner
Test-Code aus der Zeitleiste des Butterfly-Movies enthalten (wobei die zweite
<code>main</code> eines Unterordners <code>example</code> gespeichert, so
If-Bedingung überflüssig ist und daher auskommentiert wurde).
lautet der Package-Name <code>example.main</code>:
 
Der <code>stop</code>-Befehle aus dem ersten Frame wurde in den Konstruktor ausgelagert.
 
Damit kann der Code in der Zeitleiste auf drei simple Methodenaufrufe reduziert werden:
 
; Frame 1:
: kein Code mehr
; Frame 2:
: <code>testNumberOfRounds();</code>
; Frame 150:
: <code>decrementNumberOfRounds();</code>
; Frame 220:
: <code>stop();</code>
 
Vergessen Sie nicht, bei den obigen Frames Schlüsselbilder in der Ebene <code>scripts</code> zu erzeugen (sofern diese noch nicht vorhanden sind).
Sonst können Sie den entsprechenden Frames keinen Code zuweisen.
 
Die Label <code>lbStart</code> und <code>lbEnd</code> werden in der Zeitleiste in <code>lb_start</code> und <code>lb_end</code> umbenannt. Damit wird ausgedrückt,
dass auf diese Labels nur noch inter, d.h. von der dem MovieClip zugeordneten Klasse aus, auf diese Labels zugegriffen wird.


<source lang="actionscript">package example.main
==Export in Bild 1==
{
 
  ...
[[Datei:Flash CS5 Butterfly Klasse Basisklasse 01.png|miniatur|529px|Verknüpfen einer Klasse mit einem Symbol]]
}</source>
Wie oben gezeigt wurde, kann eine Klasse mit einem Symbol ganz einfach werknüpft werden:
* In der Bibliothek: Rechtsklick auf das Icon vor dem gewünscheten Symbol → <code>Eigenschaften</code> → <code>Erweitert</code> aufklappen.
 
Daraufhin erscheint das rechts abgebildete Menü.


Jede Klassen-Datei muss genau eine öffentliche Klasse (<code>public</code>)
Der Menü-Punkt <code>Export in Bild 1</code> sollte immer dann gewählt werden, wenn die Chance besteht,
mit dem Namen der Datei (ohne Endung <code>.as</code>) enthalten. Weitere
dass keine zugehörigen Objekte direkt auf der Bühne abgelegt werden, sondern nur zur Laufzeit mit Hilfe
interne Klassen können in der Datei enthalten sein, aber keine weitere
von <code>new ButterflyMovie</code> erzeugt werden sollen.
öffentlich zugängliche Klasse.


Wie in Java steht vor der Klasse eine Liste <code>import</code>-Anweisungen,
Der Grund ist, dass der ActionScript-Compiler bestrebt ist, möglichst kleine [[SWF]]-Dateien zu erzeugen.
die den direkten Zugriff auf andere Klassen im Code ermöglicht. In der
Er analisiert dazu, welche Objekte (direkt oder innerhalb anderer Movie Clips) auf der Bühne liegen und fügt nur
Flash-Zeitleiste müssen im Prinzip dieselben <code>import</code>-Anweisungen
den Code für diejenigen Symbole ein, die auf der Bühne auch tatsächlich verwendet werden.
vorhanden sein. Allerdings werde in der Flash-Zeitleiste einige Standard-Klassen-Pakete
defaultmäßig importiert, so dass eine Angabe von <code>import</code>-Anweisungen
in diesem Fall unterbleiben kann. In eine Flash-Klasse dagegen müssen stets alle notwendigen
<code>import</code>-Anweisungen angegeben werden.


Die Objekte, die auf der Bühne liegen und einen Objektnamen erhalten haben, sollten
Wenn nun für ein Symbol keine Objekte auf der Bühne liegen, wird der zugehörige Code auch nicht in die
in der Klasse als öffentliche <code>public</code> [[Zustandsvariable]]n (instance variables)
SWF-Datei eingefügt. Das heißt, wenn dann später mit Hilfe von <code>new</code> ein Objekt für dieses
deklariert werden. Sie werden von Flash automatisch initialisiert.
Symbol erstellt werden soll, stürtzt die SWF-Datei mit einer Fehlermeldung ab.


Man könnte auf die Deklaration diese Variablen verzichten, erhält damit aber Code der schwerer zu lesen ist.
Dieses Problem kann man beheben, indem man einfach ein unsichtbares Objekt für dieses Symbol
Falls man den Code nicht mit Flash, sondern mit dem [[Flash Builder]] bearbeitet, würde
auf die Bühne legt, bevor der Compiler eine SWF-Datei erzeugt. Genau diese Arbeit nimmt einen
man außerdem Fehlermeldungen erhalten, sobald man im Code auf diese Objekte zugreift.
Flash ab, wenn man einen Haken vor die Option <code>Export in Bild 1 </code> aktiviert.


Der eigentlich Code aus der Zeitleiste des ursprünglichen Movies wird in zwei Teile
Sie sollten allerdings darauf achten, dass die Bibliothek keine Symbole enthält, bei denen diese
geteilt:
Option aktiviert ist, die aber gar nicht in Ihrem Movie verwendet werden. Dies hätte nämlich
zur Folge, dass sich die SWF-Datei unnötig aufbläht, weil der Code für alle diese Symbole
mit eingebunden wird.


* Im Konstruktor <code>public function Main()</code> wird derjenige Code eigefügt, der in der Zeitleiste direkt ausgeführt wird.
==Mehrere Movie-Clips mit der Klasse <code>ButterflyMovie</code> verknüpfen==
* Hinter den Konstruktor werden alle Methoden eingefügt, die in der Zeiltleiste definiert wurden. Diese Methoden werden i. Allg. als <code>private</code> markiert, da der Zugriff auf diese Methoden i. Allg. nur innerhalb der Klasse erfolgt.
<noinclude>


Im Code können und sollten Kommentare eingefügt werden (siehe [[ASDoc]]).
<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/Butterfly06MultiFlash11.swf</swf>
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS5)]'''
([http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/ SVN-Repository])


== Das Problem mit der nicht-existierenden Bühne==
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs4/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS4)]'''
Ein Problem existiert jedoch noch. Wenn in der Zeitleiste Befehle ausgeführt werden,
([http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs4/butterfly/butterfly_06_external_code_multi/ SVN-Repository])
die direkt auf die Bühne (<code>stage</code>) zugreifen, können diese nicht einfach in den Konstruktor übernommen werden,
</noinclude>
da zum Zeitpunkt der Konstruktion des zugehörigen Objekte die Bühnen nicht nicht existiert.
Man erhält für derartige Befehle beim Starten des Filmes <code>Null</code>-Pointer-[[Ausnahmebehandlung|Exception]]s.


In der Zeitleiste passieren derartige Fehler nicht, da der Code im ersten Frame erst ausgeführt wird,
Wenn man so vorgeht, wie oben beschrieben, kann man nicht mehrere Movie Clips mit der Klasse <code>ButterflyMovie</code> verknüpfen.
wenn die Bühne bereits existiert.  
Sollte man dies vorhaben (weil man z.B. wie in der erweiterten Musterlösung zwei verschiedene Schmetterlinge gleichzeitig Runden drehen lassen will), muss man <code>ButterflyMovie</code> als Basisklasse definieren. Dies wird im Folgenden etwas genauer beschrieben.


In [[Flex]] gibt es ein spezielles Ereignis <code>APPLICATION_COMPLETE</code>, sobald die Bühne erzeugt wurde.
<gallery widths="355px" heights="76px" perrow="2">
In Flash gibt es ein derartiges EReignis leider nicht. Man kann sich allerdings behelfen,
  Datei:Flash CS5 Butterfly Klasse Basisklasse 01 Ausschnitt.png | Vorgabe von Flash
indem man das Ereignis <code>ENTER_FRAME</code> abfängt. Sobald der erste Frame des Movies betreten
  Datei:Flash CS5 Butterfly Klasse Basisklasse 02 Ausschnitt.png | Ergebnis, wenn man die Flash-Vorgabe übernimmt und nachträglich die Klasse <code>Butterfly</code> explizit definiert
wird existiert die Bühne bereits.
  Datei:Flash CS5 Butterfly Klasse Basisklasse 03 Ausschnitt.png | Definition von <code>ButterflyMovie</code> als Basisklasse
  Datei:Flash CS5 Butterfly Klasse Basisklasse 04 Ausschnitt.png | Definition von <code>ButterflyMovie</code> als Basisklasse
</gallery>


=== Beispiel ===
Bild 1 zeigt die Vorgabe von Flash: Der Name <code>ButterflyMovie</code> des ausgewählten Symbols wird als Klasse vorgeschlagen und <code>flash.display.MovieClip</code> als Basisklasse. Dies ist ein guter Defaultwert, wenn die Klasse <code>ButterflyMovie</code>
gar nicht explizit definiert werden soll. Flash erzeugt dann selbstständig eine neue Klasse <code>ButterflyMovie</code>, die alle
Eigenschaften von <code>flash.display.MovieClip</code> erbt, aber keine weiteren Eigenschaften hat.


<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_05_external_code/multi/butterfly_05_external_code_multi.swf</swf>
Im obigen Tutorium wurde diese Voreinstellung gewählt. Wenn man anschließend das Eigenschafts-Fenster des Symbols <code>ButterflyMovie</code> wieder öffnet, ist die Basisklasse entfernt worden (siehe 2. Bild). Flash hat erkannt,
'''[http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_05_external_code/multi/ Erweiterte Musterlösung]: butterfly_05_external_code_multi.swf'''
dass die Klasse <code>ButterflyMovie</code> in der Datei <code>ButterflyMovie.as</code> als Subklasse von
<code>flash.display.MovieClip</code> definiert wurde. Flash braucht also nicht selbstständig eine Klasse aus
einer vorgegebenen Basisklasse abzuleiten. Daher wird der Eintrag der Basisklasse automatisch gelöscht.


Bei Filmstart soll der Fokus auf das Eingabe-Feld gesetzt werden (ein blauer Rahmen wird um das Eingabe-Feld gezeichnet und Tastatureingabe werden direkt in dieses Feld geschrieben, siehe die erweiterte Musterlösung):
Eine existierende Klasse nicht als Basisklasse, sondern wie oben beschrieben direkt als Klasse einzutragen, hat allerdings einen
gravierenden Nachteil. Es darf keine zwei Symbole geben, denen dieselbe Klasse zugeordnet ist. Der Grund ist dafür,
dass man für ein Symbol auch mit Hilfe des <code>new</code>-Operators Objekte zur Laufzeit erzeugen kann:


<source lang="actionscript">package example.main
<source lang="actionscript3">
mc_user_input.mc_input_rounds.setFocus();
  var v_butterfly_movie: ButterflyMovie = new ButterflyMovie();
</source>
</source>


Leider greift die Methode <code>setFocus</code> auf die Bühne zu.
Wäre zwei Symbolen diese Klasse zugeordnet, wüsste Flash bei obigem Befehl nicht, für welches dieser beiden Symbole ein zugehöriges Objekt erzeugt werden soll.


Der folgende Konstruktor erzeugt also eine <code>Null</code>-Pointer-Exception.
Abhilfe bringt hier, <code>ButterflyMovie</code> als Basisklasse aller Schmetterlings-Movies einzutragen und
den Symbolen jeweils einen eindeutigen Klassennamen zuzuordnen (Bilder 3 und 4). Für die eigentlichen Klassennamen
(hier <code>ButterflyMovieBlue</code> und <code>ButterflyMovieRed</code>)
gibt man dann keine Definitionen mehr an. Flash leitet diese Klassen automatisch aus der Basisklasse ab.
Allerdings geschieht dies nicht ohne einen Warnhinweis. Hier kann, ja muss man OK klicken:


<source lang="actionscript">package example.main
<gallery widths="519px" heights="173px" perrow="1">
...
  Datei:Flash CS5 Butterfly Klasse Warnung.png | '''Warnung''', wenn die angegebene Klasse nicht existiert
    public function Main()
</gallery>
    {
 
      mc_user_input.mc_input_rounds.setFocus();
Nun ist es möglich, für jedes Symbol beliebig viele Schmetterlinge auch dynamisch zur Laufzeit zu erzeugen:
      mc_user_input.mc_button_start.addEventListener(MouseEvent.CLICK, o_start);  
 
    }
<source lang="actionscript3">
...
  var v_butterfly_movie_blue: ButterflyMovie = new ButterflyMovieBlue(); // Man beachte: Beiden Variablen wurde
  var v_butterfly_movie_red:  ButterflyMovie = new ButterflyMovieRed();   // die Basisklasse als Typ zugordent!
</source>
</source>


Das Problem lässt sich lösen, indem man die Initialisierung erst beim Betreten des ersten Frames durchführt.
Eine Kleinigkeit gilt es noch zu beachten. Man kann nur existierende Klassen als Basisklassen eintragen.
Wenn man eine Klasse einträgt, die noch nicht definiert wurde, erhält man folgende Fehlermeldung.
 
<gallery widths="524px" heights="173px" perrow="1">
  Datei:Flash CS5 Butterfly Basisklasse Fehler.png | '''Fehlermeldung''', wenn die angegebene Basisklasse nicht existiert
</gallery>
 
Prinzipiell gilt also: '''Eine existierende Klasse sollte immer als Basisklasse eingetragen werden''' (Default: <code>flash.display.MovieClip</code>).
Als Klassennamen werden danach eindeutige Klassen-Bezeichner vergeben. Diese Klassen werden jedoch nicht definiert.
 
Eine kleine Unsauberkeit ist in dem obigen Beispiel noch enthalten. Um nicht den Überblick aufgrund zahlreicher Klassen im Hauptordner zu verlieren und um Namenskonflikte zu vermeiden, sollte man jede Klasse grundsätzlich in ein geeignetes Paket stecken.
Zum Beispiel könnte man das Paket <code>hsa.tutorial.butterfly</code> definieren. Dazu legt man den Orner <code>hsa</code>
in dem Ordner an, in dem sich die <code>fla</code>-Datei des Schmetterling-Movies befinden. Im Ordner <code>hsa</code> definiert man einen Unterordner <code>tutorial</code> und darin den Unterordner <code>butterfly</code>. In diesem letzen Ordner fügt man die Dateien <code>Main.as</code> und <code>ButterflyMovie.as</code> ein.


<source lang="actionscript">package example.main
Als nächstes ersetzt man in beiden Dateien in der ersten Zeile <code>package</code> durch <code>package hsa.tutorial.butterfly</code>.
...
 
    public function Main()
Zu guter Letzt muss man noch die Klassenzuordnungn in Flash anpassen. Im Eigenschaftsfenster des Haupt-Movies wird der Klassenname
    {
<code>Main</code> durch <code>hsa.tutorial.butterfly.Main</code> ersetzt:
      // Wenn das Ereignis ENTER_FRAME eintritt, rufe o_init auf
 
      this.addEventListener(Event.ENTER_FRAME, o_init);
<gallery widths="309px" heights="183px" perrow="1">
    }
  Datei:Flash CS5 Butterfly Package Main.png | Klasse <code>Main</code> mit Paketnamenpfad <code>hsa.tutorial.butterfly</code>
   
</gallery>
    /////////////////////////////////////////////////////////////////////////////
 
    // Observer methods
Und in den Eigenschaftsfenstern der Butterfly-Symbole
    /////////////////////////////////////////////////////////////////////////////
werden folgende Klassennamen eingetragen:
   
 
    private function o_init(p_event: Event): void
<gallery widths="355px" heights="76px" perrow="2">
    {
  Datei:Flash CS5 Butterfly Klasse Basisklasse 05 Ausschnitt.png | Erweiterung des Klassennamens um den Paketnamen <code>hsa.tutorial.butterfly</code>
      // Da die Initialisierung nur im ersten Frame erfolgen soll,
  Datei:Flash CS5 Butterfly Klasse Basisklasse 06 Ausschnitt.png | Erweiterung des Klassennamens um den Paketnamen <code>hsa.tutorial.butterfly</code>
      // muss der Event-Listener gleich wieder entfernt werden.
</gallery>
      this.removeEventListener(Event.ENTER_FRAME, o_init);     
 
Die [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code/multi/ erweiterte Musterlösung]
wurde gegenüber der einfachen Musterlösung auf genau diese Weise modifiziert.
 
=Probleme der Implementierung=
 
Die im [[AS3-Tutorium: Flash: Butterfly 04 variable number of rounds#Probleme_der_Implementierung|vierten ]] und
[[AS3-Tutorium: Flash: Butterfly 05 external code#Probleme_der_Implementierung|fünften Teil des Flash-Tutoriums]]
genannte Problem wurden behoben:
*Der Code kann jetzt gelesen werden, ohne sich durch Zeitleisten zu wühlen.
*Die Klasse <code>ButterflyMovie</code> kann (als Basisklasse!) beliebig vielen Symbolen zugeordnet werden.


      // Nun existiert die Bühne!
Allerdings wurden bislang weder für den Schmetterlings-Movie noch für die Anwendung selbst saubere Schnittstellen definiert.
      mc_user_input.mc_input_rounds.setFocus();
Außerdem wurden die Aufgaben der Anwendung noch nicht sauber getrennt (vgl. [[Programmierprinzipien]], insbesondere [[Separation of Concerns]]).
      mc_user_input.mc_button_start.addEventListener(MouseEvent.CLICK, o_start);
    }
...
</source>


=Quellen=
=Quellen=
<noinclude>
<noinclude>
* [[Kowarschick, W.: Multimedia-Programmierung]]</noinclude>
* [[Kowarschick, W.: Multimedia-Programmierung]]</noinclude>
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_2/ butterfly_06_external_code_2 (Flash CS5)]
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS5)]
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs4/butterfly/butterfly_06_external_code_2/ butterfly_06_external_code_2 (Flash CS4)]
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs4/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS4)]
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs5/butterfly/butterfly_06_external_code_2/ SVN-Repository (Flash CS5)]
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS4)]
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs4/butterfly/butterfly_06_external_code_2/ SVN-Repository (Flash CS4)]<noinclude>[[Kategorie: AS3-Tutorium: Flash: Butterfly]][[Kategorie: Flash-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]
* [http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs4/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS5)]
 
== [[Subversion/HowTo|SVN]]-Repository-Verweise ==
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs5/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS5)]
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs4/butterfly/butterfly_06_external_code/ Musterlösung (Flash CS4)]
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS4)]
* [http://glossar.hs-augsburg.de/webdav/tutorium/flash_cs4/butterfly/butterfly_06_external_code_multi/ Erweiterte Musterlösung (Flash CS5)]<noinclude>[[Kategorie: AS3-Tutorium: Flash: Butterfly]][[Kategorie: Flash-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]
{{{{SITENAME}}-konformer Artikel}}
{{{{SITENAME}}-konformer Artikel}}
</noinclude>
</noinclude>

Aktuelle Version vom 6. März 2014, 11:18 Uhr

Dieser Artikel ist veraltet und wird künftig evtl. entfernt.

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 4
(großteils überprüft)
Umfang: 3
(einige wichtige Fakten fehlen)
Quellenangaben: 5
(vollständig vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 4
(sehr gut)

AS3-Tutorium: Butterfly: Flash | Flex

Flash: Übersicht | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Teil 7a | Teil 7b | Teil 7c | Teil 8 | Teil 9 | Teil 10

Verbesserung der fünften Version des Schmetterling-Movies

In AS3-Tutorium: Flash: Butterfly 05 external code wurde der Code aus der Hauptzeitleiste in eine Klasse ausgelagert. Nun soll auch noch der Code vom Schmetterlings-Movie so weit wie möglich ausgelagert werden (ohne das Verhalten des Filmes zu ändern.)


<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code/Butterfly06Flash11.swf</swf> Musterlösung (Flash CS5) (SVN-Repository)

Musterlösung (Flash CS4) (SVN-Repository)


Der Code des Schmetterlingsmovies wird ausgelagert

  1. Die Datei Butterfly05Flash.fla unter dem Namen Butterfly06Flash.fla speichern und mit dieser Datei weiterarbeiten.
  2. In der Bibliothek: Doppelklick auf das Icon vor dem Symbol ButterflyMovie → Die Definition des Symbols wird in der Bühne geöffnet.
  3. In der Bibliothek: Rechtsklick auf das Icon vor dem Symbol ButterflyMovieEigenschaftenErweitert aufklappen → Haken vor Export für ActionScript, Haken vor Export in Bild 1, Klasse: ButterflyMovieOKOK
  4. DateiNeuActionScript 3.0-Klasse (CS5) bzw. ActionScript-Datei (CS4 und früher) → OK
    Nur in CS5: -> Klassenname: ButterflyMovieOK
  5. DateiDatei speichern unterButterflyMovie.as (im selben Ordner wie die zugehörige fla-Datei.)

Achtung: Die scripts-Ebene des Butterfly-Movies wird — im Gegensatz zur scripts-Ebene des Main-Movies — nicht gelöscht. Der ActionScript-Code wird allerdings deutlich vereinfacht: In einem Frame steht zum Schluss höchstens ein Methodenaufruf (siehe weiter unten).

In die Datei ButterflyMovie.as wird folgender Code eingefügt:

package
{
  import flash.display.MovieClip;

  public class ButterflyMovie extends MovieClip
  {
    /////////////////////////////////////////////////////////////////////////////
    // Attributes
    /////////////////////////////////////////////////////////////////////////////
    
    public var roundsToFly: int = 0;

    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function ButterflyMovie()
    {
      stop();
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // Methods called from within the timeline
    /////////////////////////////////////////////////////////////////////////////

    public function testNumberOfRounds(): void
    {
      if (roundsToFly == 0)
        gotoAndPlay("lb_end");
    }

    public function decrementNumberOfRounds(): void
    {
      roundsToFly--;
//    if (roundsToFly > 0)
      gotoAndPlay("lb_start");
    }
		
    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

Die öffentlich zugängliche Zustandasvariable roundsToFly wurde in die Klasse verlagert. Außerdem wurden zwei Methoden definiert, die den Test-Code aus der Zeitleiste des Butterfly-Movies enthalten (wobei die zweite If-Bedingung überflüssig ist und daher auskommentiert wurde).

Der stop-Befehle aus dem ersten Frame wurde in den Konstruktor ausgelagert.

Damit kann der Code in der Zeitleiste auf drei simple Methodenaufrufe reduziert werden:

Frame 1
kein Code mehr
Frame 2
testNumberOfRounds();
Frame 150
decrementNumberOfRounds();
Frame 220
stop();

Vergessen Sie nicht, bei den obigen Frames Schlüsselbilder in der Ebene scripts zu erzeugen (sofern diese noch nicht vorhanden sind). Sonst können Sie den entsprechenden Frames keinen Code zuweisen.

Die Label lbStart und lbEnd werden in der Zeitleiste in lb_start und lb_end umbenannt. Damit wird ausgedrückt, dass auf diese Labels nur noch inter, d.h. von der dem MovieClip zugeordneten Klasse aus, auf diese Labels zugegriffen wird.

Export in Bild 1

Verknüpfen einer Klasse mit einem Symbol

Wie oben gezeigt wurde, kann eine Klasse mit einem Symbol ganz einfach werknüpft werden:

  • In der Bibliothek: Rechtsklick auf das Icon vor dem gewünscheten Symbol → EigenschaftenErweitert aufklappen.

Daraufhin erscheint das rechts abgebildete Menü.

Der Menü-Punkt Export in Bild 1 sollte immer dann gewählt werden, wenn die Chance besteht, dass keine zugehörigen Objekte direkt auf der Bühne abgelegt werden, sondern nur zur Laufzeit mit Hilfe von new ButterflyMovie erzeugt werden sollen.

Der Grund ist, dass der ActionScript-Compiler bestrebt ist, möglichst kleine SWF-Dateien zu erzeugen. Er analisiert dazu, welche Objekte (direkt oder innerhalb anderer Movie Clips) auf der Bühne liegen und fügt nur den Code für diejenigen Symbole ein, die auf der Bühne auch tatsächlich verwendet werden.

Wenn nun für ein Symbol keine Objekte auf der Bühne liegen, wird der zugehörige Code auch nicht in die SWF-Datei eingefügt. Das heißt, wenn dann später mit Hilfe von new ein Objekt für dieses Symbol erstellt werden soll, stürtzt die SWF-Datei mit einer Fehlermeldung ab.

Dieses Problem kann man beheben, indem man einfach ein unsichtbares Objekt für dieses Symbol auf die Bühne legt, bevor der Compiler eine SWF-Datei erzeugt. Genau diese Arbeit nimmt einen Flash ab, wenn man einen Haken vor die Option Export in Bild 1 aktiviert.

Sie sollten allerdings darauf achten, dass die Bibliothek keine Symbole enthält, bei denen diese Option aktiviert ist, die aber gar nicht in Ihrem Movie verwendet werden. Dies hätte nämlich zur Folge, dass sich die SWF-Datei unnötig aufbläht, weil der Code für alle diese Symbole mit eingebunden wird.

Mehrere Movie-Clips mit der Klasse ButterflyMovie verknüpfen

<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_06_external_code_multi/Butterfly06MultiFlash11.swf</swf> Erweiterte Musterlösung (Flash CS5) (SVN-Repository)

Erweiterte Musterlösung (Flash CS4) (SVN-Repository)


Wenn man so vorgeht, wie oben beschrieben, kann man nicht mehrere Movie Clips mit der Klasse ButterflyMovie verknüpfen. Sollte man dies vorhaben (weil man z.B. wie in der erweiterten Musterlösung zwei verschiedene Schmetterlinge gleichzeitig Runden drehen lassen will), muss man ButterflyMovie als Basisklasse definieren. Dies wird im Folgenden etwas genauer beschrieben.

Bild 1 zeigt die Vorgabe von Flash: Der Name ButterflyMovie des ausgewählten Symbols wird als Klasse vorgeschlagen und flash.display.MovieClip als Basisklasse. Dies ist ein guter Defaultwert, wenn die Klasse ButterflyMovie gar nicht explizit definiert werden soll. Flash erzeugt dann selbstständig eine neue Klasse ButterflyMovie, die alle Eigenschaften von flash.display.MovieClip erbt, aber keine weiteren Eigenschaften hat.

Im obigen Tutorium wurde diese Voreinstellung gewählt. Wenn man anschließend das Eigenschafts-Fenster des Symbols ButterflyMovie wieder öffnet, ist die Basisklasse entfernt worden (siehe 2. Bild). Flash hat erkannt, dass die Klasse ButterflyMovie in der Datei ButterflyMovie.as als Subklasse von flash.display.MovieClip definiert wurde. Flash braucht also nicht selbstständig eine Klasse aus einer vorgegebenen Basisklasse abzuleiten. Daher wird der Eintrag der Basisklasse automatisch gelöscht.

Eine existierende Klasse nicht als Basisklasse, sondern wie oben beschrieben direkt als Klasse einzutragen, hat allerdings einen gravierenden Nachteil. Es darf keine zwei Symbole geben, denen dieselbe Klasse zugeordnet ist. Der Grund ist dafür, dass man für ein Symbol auch mit Hilfe des new-Operators Objekte zur Laufzeit erzeugen kann:

  var v_butterfly_movie: ButterflyMovie = new ButterflyMovie();

Wäre zwei Symbolen diese Klasse zugeordnet, wüsste Flash bei obigem Befehl nicht, für welches dieser beiden Symbole ein zugehöriges Objekt erzeugt werden soll.

Abhilfe bringt hier, ButterflyMovie als Basisklasse aller Schmetterlings-Movies einzutragen und den Symbolen jeweils einen eindeutigen Klassennamen zuzuordnen (Bilder 3 und 4). Für die eigentlichen Klassennamen (hier ButterflyMovieBlue und ButterflyMovieRed) gibt man dann keine Definitionen mehr an. Flash leitet diese Klassen automatisch aus der Basisklasse ab. Allerdings geschieht dies nicht ohne einen Warnhinweis. Hier kann, ja muss man OK klicken:

Nun ist es möglich, für jedes Symbol beliebig viele Schmetterlinge auch dynamisch zur Laufzeit zu erzeugen:

  var v_butterfly_movie_blue: ButterflyMovie = new ButterflyMovieBlue();  // Man beachte: Beiden Variablen wurde
  var v_butterfly_movie_red:  ButterflyMovie = new ButterflyMovieRed();   // die Basisklasse als Typ zugordent!

Eine Kleinigkeit gilt es noch zu beachten. Man kann nur existierende Klassen als Basisklassen eintragen. Wenn man eine Klasse einträgt, die noch nicht definiert wurde, erhält man folgende Fehlermeldung.

Prinzipiell gilt also: Eine existierende Klasse sollte immer als Basisklasse eingetragen werden (Default: flash.display.MovieClip). Als Klassennamen werden danach eindeutige Klassen-Bezeichner vergeben. Diese Klassen werden jedoch nicht definiert.

Eine kleine Unsauberkeit ist in dem obigen Beispiel noch enthalten. Um nicht den Überblick aufgrund zahlreicher Klassen im Hauptordner zu verlieren und um Namenskonflikte zu vermeiden, sollte man jede Klasse grundsätzlich in ein geeignetes Paket stecken. Zum Beispiel könnte man das Paket hsa.tutorial.butterfly definieren. Dazu legt man den Orner hsa in dem Ordner an, in dem sich die fla-Datei des Schmetterling-Movies befinden. Im Ordner hsa definiert man einen Unterordner tutorial und darin den Unterordner butterfly. In diesem letzen Ordner fügt man die Dateien Main.as und ButterflyMovie.as ein.

Als nächstes ersetzt man in beiden Dateien in der ersten Zeile package durch package hsa.tutorial.butterfly.

Zu guter Letzt muss man noch die Klassenzuordnungn in Flash anpassen. Im Eigenschaftsfenster des Haupt-Movies wird der Klassenname Main durch hsa.tutorial.butterfly.Main ersetzt:

Und in den Eigenschaftsfenstern der Butterfly-Symbole werden folgende Klassennamen eingetragen:

Die erweiterte Musterlösung wurde gegenüber der einfachen Musterlösung auf genau diese Weise modifiziert.

Probleme der Implementierung

Die im vierten und fünften Teil des Flash-Tutoriums genannte Problem wurden behoben:

  • Der Code kann jetzt gelesen werden, ohne sich durch Zeitleisten zu wühlen.
  • Die Klasse ButterflyMovie kann (als Basisklasse!) beliebig vielen Symbolen zugeordnet werden.

Allerdings wurden bislang weder für den Schmetterlings-Movie noch für die Anwendung selbst saubere Schnittstellen definiert. Außerdem wurden die Aufgaben der Anwendung noch nicht sauber getrennt (vgl. Programmierprinzipien, insbesondere Separation of Concerns).

Quellen

SVN-Repository-Verweise


Dieser Artikel ist GlossarWiki-konform.