AS3-Tutorium: Flash: Butterfly 07a character: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Zeile 8: Zeile 8:
=Weiterentwicklung der sechsten Version des Schmetterling-Movies=
=Weiterentwicklung der sechsten Version des Schmetterling-Movies=


In [[AS3-Tutorium: Flash: Butterfly 06 external code]] wurde der Code aus den Zeitleisten des Hauptmoivies sowie der Symbole weitestgehend in Klassen ausgelagert.
In [[AS3-Tutorium: Flash: Butterfly 06 external code]] wurde der Code aus den Zeitleisten des Hauptfilms sowie der Symbole weitestgehend in Klassen ausgelagert.
Allerdings wurde bei der Implementierung bislang nicht das Prinzip [[Separation of Concerns]] (siehe auch [[Programmierprinzipien]]) beachtet.
Allerdings wurde bei der Implementierung bislang nicht das Prinzip [[Separation of Concerns]] (siehe auch [[Programmierprinzipien]]) beachtet.
Um dies zu erreichen, werden in einem ersten Schritt
Um dies zu erreichen, werden in einem ersten Schritt
Zeile 18: Zeile 18:


Im Folgenden wird zunächst das Symbol <code>Butterfly</code> in eine Spielfigur (im zuvor beschrieben Sinn) umgewandelt, um das Grundprinzip klar zu machen.
Im Folgenden wird zunächst das Symbol <code>Butterfly</code> in eine Spielfigur (im zuvor beschrieben Sinn) umgewandelt, um das Grundprinzip klar zu machen.
Danach wird das Symbol <code>ButterflyMovie</code> in eine „Figur“ umgewandelt. Hierbei wird insbesondere die Progammlogik (fliegen einer via <code>roundsToFly</code> vorgegebenen Anzahl von Runden)
In zwei weiteren Schritten wird die Implementierung verbessert, so dass die Übergänge von einem Zustand in den anderen „weich“ erfolgen.
Auf die zur Verfügung gestellte Schnittstelle hat dies keine Auswirkungen.
 
Danach wird das Symbol <code>ButterflyMovie</code> in eine „Figur“ umgewandelt.
Hierbei wird insbesondere die Progammlogik (fliegen einer via <code>roundsToFly</code> vorgegebenen Anzahl von Runden)
aus der Klasse <code>ButterflyMovie</code> in die Hauptklasse <code>Main</code> verlagert.
aus der Klasse <code>ButterflyMovie</code> in die Hauptklasse <code>Main</code> verlagert.
<noinclude>
<noinclude>

Version vom 18. November 2010, 18:20 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

Dieser Artikel wird derzeit von einem Autor gründlich bearbeitet. Die Inhalte sind daher evtl. noch inkonsistent.

Datenmodell

FEHLT NOCH

Weiterentwicklung der sechsten Version des Schmetterling-Movies

In AS3-Tutorium: Flash: Butterfly 06 external code wurde der Code aus den Zeitleisten des Hauptfilms sowie der Symbole weitestgehend in Klassen ausgelagert. Allerdings wurde bei der Implementierung bislang nicht das Prinzip Separation of Concerns (siehe auch Programmierprinzipien) beachtet. Um dies zu erreichen, werden in einem ersten Schritt die Symbole Butterfly und ButterflyMovie in „Spielfiguren“ (characters) umgewandelt.

Eine Spielfigur kann verschiedene Zustände einnehmen, wie z.B. „stehen“, „laufen nach links“, „laufen nach rechts“, „hüpfen“ etc. Dabei sollte ein Figur-Objekt nicht selbst entscheiden, wann es in welchen Zustand übergeht. Die wird von außen (z.B.) über eine Logik-Komponente gesteuert. Das heißt, eine Figur hat nur noch eine einzige Aufgabe: Den Zustand dieser Figur (der im Allgemeinen in einem Datenobjekt gespeichert wird) zu visualisieren.

Im Folgenden wird zunächst das Symbol Butterfly in eine Spielfigur (im zuvor beschrieben Sinn) umgewandelt, um das Grundprinzip klar zu machen. In zwei weiteren Schritten wird die Implementierung verbessert, so dass die Übergänge von einem Zustand in den anderen „weich“ erfolgen. Auf die zur Verfügung gestellte Schnittstelle hat dies keine Auswirkungen.

Danach wird das Symbol ButterflyMovie in eine „Figur“ umgewandelt. Hierbei wird insbesondere die Progammlogik (fliegen einer via roundsToFly vorgegebenen Anzahl von Runden) aus der Klasse ButterflyMovie in die Hauptklasse Main verlagert.


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

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


Das Schmetterlingssymbol als Spielfigur

Die Grundidee ist folgende: Für jeden Zustand der Spielfigur wird im Movie Clip ein eigener Abschnitt (d.h. ein zusammenhängender Bereich von Frames) definiert.

Das erste Frame eines jeden Abschnittes wird mit einen Label versehen, dessen Name sich aus dem zugehörigen Zustand ableitet (z.B. lb_x, wobei x durch den aktuellen Zustand ersetzt wird).

Das letzte Frame eines jeden Abschnittes wird mit einem ActionScript-Befehl versehen:

  • stop();, falls die dem Zustand zugeordnete Animation nur einmal abgespielt werden soll
  • gotoAndPlay(lb_x);, falls die dem Zustand zugeordnete Animation dauerhaft abgespielt werden soll

Zunächst wird das Schmetterlingssymbol auf diese Weise umgestaltet.

  1. In der Bibliothek: Das Symbol Butterfly mit einem Doppelklick öffnen.
  2. In der Zeitleiste: Zwei neue Ebenen (ganz oben) einfügen:
    • scripts
    • labels
  3. In der Zeitleiste: Alle Ebenen (und damit alle Frames) markieren und den Block mit allen Frames nach rechts verschieben, so dass das erste Schlüsselbild auf Frame 40 liegt.
  4. In der Zeitleiste, Ebene body: Klick auf das Schlüsselbild bei Frame 40 → Alt-Taste drücken und festhalten → Linke Maustaste über Schlüsselbild bei Frame 40 drücken, festhalten und nach links bis Frame 1 verschieben ⇒ Der Schmetterlingskörper ist ab Frame 1 vorhanden; eer entsprechende Bereich in der Zeitleiste hat sich grau eingefärbt.
  5. In der Zeitleiste, Ebene body: Das Schlüssenbild bei Frame 40 entfernen: Klick auf das Schlüsselbild → Rechtsklick auf das Schlüsselbild → Schlüsselbild löschen.
  6. In der Zeitleiste, Ebene wings: Klick auf Frame 20 → Rechtsklick auf Frame 20 → Schlüsselbild einfügen.
  7. In der Zeitleiste, Ebene wings: Strg/Ctrl-Taste drücken und festhalten → Klick auf das Schlüsselbild bei Frame 40 → Rechtsklick auf das Schlüsselbild → Bilder kopieren.
  8. In der Zeitleiste, Ebene wings: Klick auf Frame 1 → Rechtsklick auf Frame 1 → Bilder einfügen (nicht Bild einfügen!!).
  9. In der Zeitleiste, Ebene wings: Strg/Ctrl-Taste drücken und festhalten → Klick auf das Schlüsselbild bei Frame 50 → Rechtsklick auf das Schlüsselbild → Bilder kopieren.
  10. In der Zeitleiste, Ebene wings: Klick auf Frame 20 → Rechtsklick auf Frame 20 → Bilder einfügen (nicht Bild einfügen!!).
  11. In der Zeitleiste, Ebene labels: Klick auf Frame 1 → Eigenschaften-Fenster öffnen → Name: lb_opened
  12. In der Zeitleiste, Ebene labels: Klick auf Frame 20 → Rechtsklick auf Frame 20 → Schlüsselbild einfügen → Eigenschaften-Fenster, Name: lb_closed
  13. In der Zeitleiste, Ebene labels: Klick auf Frame 40 → Eigenschaften-Fenster, Name: lb_fluttering
  14. In der Zeitleiste, Ebene scripts folgenden Code eintragen (Schlüsselbilder nicht vergessen!):
    Frame 10
    stop();
    Frame 39
    stop();
    Frame 59
    gotoAndPlay("lb_fluttering");

Als nächstes wird der Code zur Steuerung des Zustandswechsels dem Schmetterlings-Symbol zugeordnet:

  1. Im Menü: DateiNeuActionScript 3.0-Klasse (CS5) bzw. ActionScript-Datei (CS4 und früher) → OK
    Nur in CS5: -> Klassenname: ButterflyOK
  2. Im Menü: DateiDatei speichern unter → Im Ordner der fla-Datei folgende Unterordner anlegen: hsa/tutorial/butterfly → Datei unter dem Namen Butterfly.as im zuvor angelegten Unterordner speichern.
  3. In der Bilbliothek: Rechtsklick auf das Symbol ButterflyEigenschaften → falls notwendig: Klick auf Dreieck hinter Erweitert → Häckchen vor Export für ActionScript → Klasse: hsa.tutorial.butterfly.ButterflyBlue (oder eine andere Farbe), Basisklasse hsa.tutorial.butterfly.ButterflyOKOK

Nun kann in die Datei Butterfly.as folgendener Code einfügt werden:

package hsa.tutorial.butterfly
{
  import flash.display.MovieClip;
  
  public class Butterfly extends MovieClip
  {
    /////////////////////////////////////////////////////////////////////////////
    // Constants
    /////////////////////////////////////////////////////////////////////////////

    public static const OPENED:     String = "opened";
    public static const CLOSED:     String = "closed";
    public static const FLUTTERING: String = "fluttering";

    /////////////////////////////////////////////////////////////////////////////
    // Instance variables
    /////////////////////////////////////////////////////////////////////////////

    private var v_state: String;

    ////////////////////////////////////////////////////////////////////////////
    // Attributes
    /////////////////////////////////////////////////////////////////////////////
    
    public function get state(): String
    {
      return v_state;
    }
    
    public function set state(p_state: String): void
    {
      if (p_state != v_state)
      {
        this.gotoAndPlay("lb_"+ p_state);
        v_state = p_state;
      };
    }

    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function Butterfly(p_state: String = OPENED)
    {
      this.state = p_state;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

Anmerkung 1

Man beachte, dass im Gegensatz zu den vorangegangen Tutorien die Labelbezeichnungen nicht mehr lbOpened, lbClosed und lbFluttering lauten, sondern lb_opened, lb_closed und lb_fluttering.

Gemäß den hier verwendeten Namenskonventionen bedeutet dies, dass von außen nicht mehr direkt auf die Zeitleistenlabels zugegriffen werden soll. Sie werden als private angesehen (auch wenn dies in Flash nicht realisierbar ist). Das heißt, auf die Labels wird nur noch innerhalb der Klasse Butterlfy zugegrifen (konkret: in der Setter-Methode set state).

Anmerkung 2

Für den Schmetterling wurde eine saubere Schnittstelle definiert (das Attribut state). Nur über diese Schnittstelle soll von außen auf das Objekt zugegriffen werden.

Wenn man einen Schmetterling auf die Bühne legt und ihm den „Instanznamen“ sp_butterfly gibt, kann man mit folgenden Befehlen dessen Zustand verändern:

import hsa.tutorial.butterfly.*;

sp_butterfly.state=Butterfly.OPENED;
sp_butterfly.state=Butterfly.CLOSED;
sp_butterfly.state=Butterfly.FLUTTERING;

Anmerkung 3

Bei jeder Zustandsänderung sollte das Schmetterlings-Objekt alle interessierten Objekte, d.h. alle Observer (bzw in ActionScript: Listener) mit Hilfe eines Signals (in ActionScript Event genannt) über die erfolgte Zustandsänderung informieren. Dies wäre mit Hilfe des Befehls

this.dispatchEvent(new Event(Event.CHANGE));

problemlos möglich.

Allerdings ist es sauberer, eine eigene Klasse ButterflyEvent als Subklasse von Event zu definieren und dort spezielle BuuterflyEvent-Konstanten zu definieren.

Die zugehörige Datei ButterflyEvent.as muss, wenn als Package-Name ebenfalls hsa.tutorial.butterfly angegeben wird, im selben Ordner wie die anderen as-Dateien abgespeichert werden: hsa/tutorial/butterfly. Der Inhalt dieser Datei könnte folgendermaßen aussehen:

package hsa.tutorial.butterfly
{
  import flash.events.Event;
  
  public class ButterflyEvent extends Event
  {
    /////////////////////////////////////////////////////////////////////////////
    // Constants
    /////////////////////////////////////////////////////////////////////////////
    
    public static const CHANGE_STATE:          String = "change state";
    public static const CHANGE_STATE_TIMELINE: String = "change state timeline";
    
    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function ButterflyEvent(type: String = CHANGE_STATE)
    {
      super(type);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

Sobald man diese Datei erstellt hat, kann man die Setter-Methode set state in der Datei Butterfly.as erweitern:

    public function set state(p_state: String): void
    {
      if (p_state != v_state)
      {
        this.gotoAndPlay("lb_"+ p_state);
        v_state = p_state;
        this.dispatchEvent(new ButterflyEvent());
      };
    }

Dies wird z.B. im nachfolgenden Beispiel ausgenutzt, um den aktuellen Zustand in einem Textfeld ausgeben zu können. Hierzu wurde in der Haupt-Timeline der zugehörigen fla-Datei folgender Code eingefügt (da der Movie nur zum Testen der Klasse Butterfly dient wurde der Code nicht ausgelagert):

import hsa.tutorial.butterfly.ButterflyEvent;

// sp_butterfly ist der Schmettrling auf der Bühne.
sp_butterfly.addEventListener(ButterflyEvent.CHANGE_STATE, o_change);

function o_change(p_event: ButterflyEvent): void
{
  // sp_label_state ist ein Textfeld auf der Bühne.
  sp_label_state.text = sp_butterfly.state;
}

<swf width="183" height="133">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_07_character/Butterfly07ButterflyRoughFlash11.swf</swf>

Das Schmetterlingssymbol als Spielfigur mit weichen Übergängen

Einen Nachteil hat die vorangegangene Implementierung noch. Ein Übergang von einem Zustand zu einem anderen erfolgt im Allgemeinen ruckartig. Wenn man z.B. von CLOSED ind FLUTTERING wechselt, werden die Flügel schlagartig geöffnet.

Sowohl beim vorangegangenen Beispielfilm, als auch bei nachfolgenden Beispielsfilm wird zunächst alle 30 Frames und danach kurzeitig viel häufiger der Zustand des Schmetterlings geändert. Man beachte den Unterschied.

<swf width="183" height="133">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_07_character/Butterfly07ButterflySmoothFlash11.swf</swf>

Um das Problem mit den ruckartigen Zustandsübergängen zu beheben, muss der flatternde Schmetterling regelmäßig melden, wenn seine Flügel ganz offen oder geschlossen sind. Außerdem muss es möglich sein, im „Fluttering-Movie“ sowohl zu dem Frame, an dem die Flügel ganz geöffnet sind, als auch zu dem Frame, an dem die Flügel ganz geschlossen sind, zu springen. Dazu sind folgende Änderungen am Symbol Butterfly notwendig:

  1. In der Zeitleiste, Ebene labels: Labelnamen von Frame 40 in lb_fluttering_opened abändern.
  2. In der Zeitleiste, Ebene labels: Folgenden Labelnamen in Frame 50 einfügen lb_fluttering_closed.
  3. In der Zeitleiste, Ebene scripts folgenden zusätzlichen Code eintragen (Schlüsselbilder nicht vergessen!):
    Frame 40
    m_new_wings_state(OPENED);
    Frame 50
    m_new_wings_state(CLOSED);

Die Implementierung der Setter-Methode set state ist nun allerdings sehr viel aufwändiger. Zunächst gibt es sechs Fälle, die berücksichtigt werden müssen. Den Fall dass sich alter und neuer Zustand nicht unterscheiden, braucht man (zunächst!) nicht zu betrachten.

Der einfachste Fall ist, dass der Schmetterling sich nicht bewegt und mit dem Flattern beginnen soll:

Aktueller Zustand Neuer Zustand Aktion
OPENED FLUTTERING gotoAndPlay("lb_fluttering_opened") ⇒ der neue Status wird sofort erreicht
CLOSED FLUTTERING gotoAndPlay("lb_fluttering_closed") ⇒ der neue Status wird sofort erreicht

In den übrigen vier Fällen muss der Statuswechsel verzögert werden:

Aktueller Zustand Neuer Zustand Aktion
OPENED CLOSED gotoAndPlay("lb_fluttering_opened")
Aufruf von m_new_wings_state(CLOSED) ⇒ neuer Status ist erreicht
CLOSED OPENED gotoAndPlay("lb_fluttering_closed")
Aufruf von m_new_wings_state(OPENED) ⇒ neuer Status ist erreicht
FLUTTERING CLOSED Aufruf von m_new_wings_state(CLOSED) ⇒ neuer Status ist erreicht
FLUTTERING OPENED Aufruf von m_new_wings_state(OPENED) ⇒ neuer Status ist erreicht

Leider reicht es nicht, diese sechs Fälle zu betrachten. Der Zustand des Schmetterlings kann ja erneut geändert werden, während sich dieser bereits in einer verzögerten Zustandsänderung befindet (und daher zurzeit flattert). Hier gibt es folgende zusätzlichen Fälle:

Aktueller Zustand Neuer Zustand Aktion
irgendein Zustand FLUTTERING Der Schmetterling hat den neuen Zustand bereits erreicht, da er bereits flattert.
Die verzögerte Zustandsänderung muss(!) unterbrochen werden.
OPENED oder
CLOSED
CLOSED Aufruf von m_new_wings_state(CLOSED) ⇒ neuer Status ist erreicht
OPENED oder
CLOSED
OPENED Aufruf von m_new_wings_state(OPENED) ⇒ neuer Status ist erreicht

Wenn man die obigen Tabellen in Code umsetzt, ändert sich der Inhalt der Datei Butterfly.as wie folgt:

package hsa.tutorial.butterfly
{
  import flash.display.MovieClip;
  
  public class Butterfly extends MovieClip
  {
    /////////////////////////////////////////////////////////////////////////////
    // Constants
    /////////////////////////////////////////////////////////////////////////////

    public static const OPENED:     String = "opened";
    public static const CLOSED:     String = "closed";
    public static const FLUTTERING: String = "fluttering";
    
    private static const c_label_prefix:            String = "lb_";
    private static const c_label_prefix_fluttering: String = "lb_fluttering_";

    /////////////////////////////////////////////////////////////////////////////
    // Instance variables
    /////////////////////////////////////////////////////////////////////////////

    // Instance variables of the attributes
    private var v_state:          String;
    
    // Auxiliary variable (for being able to perfor delayed state changes)
    private var v_next_state: String = null;

    ////////////////////////////////////////////////////////////////////////////
    // Attributes
    /////////////////////////////////////////////////////////////////////////////

    /**
     * The current state of the butterfly: 
     *   <code>OPENED</code>, <code>CLOSED</code> or <code>BUTTERFLY</code>.
     */
    public function get state(): String
    {
      return v_state;
    }
    
    public function set state(p_state: String): void
    {
      if (p_state != OPENED && p_state != CLOSED && p_state != FLUTTERING)
        throw (new Error("Butterfly: State '" + p_state + "' is unknown!"));

      if (v_next_state == null) // Currently no delayed state change is performed!
      { 
        if (p_state != v_state) // A real state change is to be performed.
        {
          if (p_state == FLUTTERING) // Do the state change immediatedly!
          {
            this.gotoAndPlay(c_label_prefix_fluttering + v_state);
            v_state = p_state;
            this.dispatchEvent(new ButterflyEvent());
          }
          else // p_state == OPENED || CLOSED
          {
            if (v_state != FLUTTERING)
              this.gotoAndPlay(c_label_prefix_fluttering + v_state);
            
            // Delay the stage change until the wings are in the correct position.
            v_next_state = p_state;
          };
        };
      }
      else // Currently a delayed state change is performed!
      {
        if (p_state == FLUTTERING)
        {
          v_next_state = null; // Stop the delayed state change.
          v_state = p_state;   // Do the state change now!
          this.dispatchEvent(new ButterflyEvent());
        }
        else
          v_next_state = p_state; // Update the delayed state change;
      }
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // Methods called from within the timline (should be private, but cannot)
    /////////////////////////////////////////////////////////////////////////////
    
    public function  m_new_wings_state(p_state: String): void
    {
      // If the wings are in the correct position,
      // perform the delayed state change!
      if (v_next_state == p_state)
      {  
        v_state = v_next_state;
        v_next_state = null;
        this.gotoAndPlay(c_label_prefix + v_state);
        this.dispatchEvent(new ButterflyEvent());
      };
    }
 
    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function Butterfly(p_state: String = OPENED)
    {
       v_state = p_state;
       if (v_state == FLUTTERING)
         this.gotoAndPlay(c_label_prefix_fluttering + OPENED);
       else
         this.gotoAndPlay(c_label_prefix + p_state);
       
       this.dispatchEvent(new ButterflyEvent());
    }

    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

Anmerkung 1

Man beachte, dass hier nur eine verbesserte, wenn auch viel aufwändigere Implementierung des Symbols Butterfly angegeben wurde. An der zuvor definierten Schnittstellte nichts. Man kann sich allerdings nicht mehr darauf verlassen, dass die Zustandswechsel sofort in dem Moment angezeigt wird, in dem die Setter-Methode set state aufgerufen wird.

Das Schmetterlingssymbol als Spielfigur mit weichen Übergängen: Vereinfachte Version

Der Code, der im vorangegangenen Abschnitt erstellt wurde, ist ziemlich umfangreich und schwer zu verstehen. Wenn Spielfiguren komplexere Bewegungsabläufe aufweisen, ist es i.Allg noch schwieriger, einen weichen Übergang von Zustand zu Zustand zu realisieren. Eine Spielfigur eines Jump'n'Run-Spiels beispielsweise dreht sich daher so gut wie immer schlagartig um 180 Grad, wenn der Benutzer die Bewegungsrichtung ändert.

Die Kompelxität der zuvor definierten Butterfly-Klasse ist vor allem der Tatsache geschuldet, dass für jeden Zustand eine eigener Frames-Block definiert wurde. Obwohl dies i.Allg. notwendig ist (und daher dieser allgemein Fall auch im Tutorium demonstriert wurde), soll nicht verschwiegen werden, dass es für den Schmetterling eine wesentlich einfache Implementierung gibt, die fast genau dasselbe Verhalten wie zuvor realisiert (es werden lediglich ein ein paar mehr Zustandsänderungen „dispatched“).

Im dritten Frame-Block sind alle gewünschten Zustände enthalten: Flügelschlagender Schmetterling, Schmetterling mit offenen Flügeln und Schmetterling mit geschlossenen Flügeln. Dehalb reicht es, den Flügelschlag im richtigen Moment anzuhalten bzw. zu starten, um zwischen den einzelen Zuständen zu wechseln. Ein Sprung über mehrer Frames hinweg ist (außer beim Rücksprung auf das erste Bild der Framesequenz) gar nicht notwendig.

Folgende Änderungen können am Schmetterling vorgenommen werden:

  1. In der Zeitleiste des Symbols Butterfly: Die Frames 1 bis 39 in allen vier Ebenen gleichzeitig markieren → Rechtsklick in den markierten Bereich → Bilder entfernen.
  2. In der Zeitleiste, Ebene labels: Die Label lb_butterfly_opened und lb_butterfly_closed in lb_opened und lb_closed umbenennen.

Den Code in der Datei Butterfly.as durch folgenden Code ersetzen:

package hsa.tutorial.butterfly
{
  import flash.display.MovieClip;
  
  public class Butterfly extends MovieClip
  {
    /////////////////////////////////////////////////////////////////////////////
    // Constants
    /////////////////////////////////////////////////////////////////////////////

    public static const OPENED:     String = "opened";
    public static const CLOSED:     String = "closed";
    public static const FLUTTERING: String = "fluttering";

    /////////////////////////////////////////////////////////////////////////////
    // Instance variables
    /////////////////////////////////////////////////////////////////////////////

    // Instance variables of the attributes
    private var v_state:          String;
    private var v_state_timeline: String;
    
    // Auxiliary variable (for being able to perfor delayed state changes)
    private var v_stop_state: String = null;

    ////////////////////////////////////////////////////////////////////////////
    // Attributes
    /////////////////////////////////////////////////////////////////////////////

    /**
     * The current state of the wings: 
     *   <code>OPENED</code> or <code>CLOSED</code>.
     */
    public function get stateTimeline(): String
    {
      return v_state_timeline;
    }
    
    /**
     * The current state of the butterfly: 
     *   <code>OPENED</code>, <code>CLOSED</code> or <code>BUTTERFLY</code>.
     */
    public function get state(): String
    {
      return v_state;
    }
    
    public function set state(p_state: String): void
    {
      if (p_state == FLUTTERING)
      {
        v_stop_state = null; // Don't stop fluttering!
        v_state = p_state;   // Do the state change now!
        this.play();         // Start the movie (if it currently is stoped).
        this.dispatchEvent(new ButterflyEvent());
      }
      else if (p_state == OPENED || p_state == CLOSED)
      {
        v_stop_state = p_state;
        this.play(); // Start the movie (if it currently is stoped).
      }
      else
        throw (new Error("Butterfly: State '" + p_state + "' is unknown!"));
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // Methods called from within the timline (should be private, but cannot)
    /////////////////////////////////////////////////////////////////////////////
    
    public function  m_new_wings_state(p_state: String): void
    {
      // The state of the wings has changed. Inform the observers!
      v_state_timeline = p_state;
      this.dispatchEvent
        (new ButterflyEvent(ButterflyEvent.CHANGE_STATE_TIMELINE));

      // If the wings are to be stoped, stop them.
      if (v_stop_state == p_state)
      {
        this.stop();
        v_stop_state = null;
        v_state = p_state;
        this.dispatchEvent(new ButterflyEvent());
      }
      else
        this.play();
    }
 
    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function Butterfly(p_state: String = OPENED)
    {
       this.state = p_state;
    }

    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

Anmerkung 1

<swf width="183" height="133">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_07_character/Butterfly07ButterflySimplifiedFlash11.swf</swf>

Beachten Sie, dass der Code viel einfacher ist, als im vorangegangen Beispiel. Insbesondere in der Setter-Methode set state und im Konstruktor steht deutlich weniger und damit auch verständlicherer Code.

Der Code wäre sogar noch kürzer, wenn nicht zusätzlich noch ein zweiter Event-Dispatcher eingefüt wurde. Bei jedem Öffnen oder Schließen der Flügel wir zusätzlich ein Event der Art CHANGE_STATE_TIMELINE gemeldet.

Damit ist es z.B. möglich, einen Flügelschlag-Sound mit dem Movie zu synchronisieren. Im obigen Beispiel wird (da mir derzeit leider kein Flügelschlag-Sound vorliegt) der aktuelle Zustand des Flügels in einem zweiten Textfeld ausgegeben.

Der entsprechende Code im ersten Frame der Haupt-Zeitleiste des Test-Movies lautet:

import hsa.tutorial.butterfly.Butterfly;
import hsa.tutorial.butterfly.ButterflyEvent;
import fl.transitions.Tween;
import fl.transitions.easing.*;

sp_butterfly.addEventListener(ButterflyEvent.CHANGE_STATE,          o_change);
sp_butterfly.addEventListener(ButterflyEvent.CHANGE_STATE_TIMELINE, o_wings);

function o_change(p_event: ButterflyEvent): void
{
  sp_label_state.text = sp_butterfly.state;
}

function o_wings(p_event: ButterflyEvent): void
{
  sp_label_wings.text = sp_butterfly.stateTimeline;
  
  if (sp_butterfly.stateTimeline == Butterfly.OPENED)
    sp_label_flap. text = "flip";
  else
    sp_label_flap. text = "flap";

  new Tween(sp_label_flap, // object to be animated 
            "alpha",       // animation attribute: "x", "y", "alpha", "rotation", ...
            None.easeIn,   // animation type
            1.0, 0.0,      // start and end value (of alpha)
            15,            // Dauer der Animation ...
            false          // duration in frames (not in seconds)
           );
}

Der Schmetterlings-Movie als Spielfigur

Probleme der Implementierung

Quellen

SVN-Repository-Verweise


Dieser Artikel ist GlossarWiki-konform.