AS3-Tutorium: Flash: Butterfly 07b character

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Wechseln zu:Navigation, Suche

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

1 Das Schmetterlingssymbol als Spielfigur mit weichen Übergängen

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

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


Einen Nachteil hat die im Teil 7a angegebene Implementierung des Schmetterlingssymbols noch. Ein Übergang von einem Zustand zu einem anderen erfolgt im Allgemeinen ruckartig. Wenn man z.B. von CLOSE ind FLUTTERING wechselt, werden die Flügel schlagartig geöffnet.

In beiden folgenden Filmen (links: Lösung gemäß Teil 7a, rechts: Lösung gemäß Teil 7b) wird zunächst alle 30 Frames und danach kurzeitig viel häufiger der Zustand des Schmetterlings geändert. Man beachte den Unterschied.

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_open abändern.
  2. In der Zeitleiste, Ebene labels: Folgenden Labelnamen in Frame 50 einfügen lb_fluttering_close.
  3. In der Zeitleiste, Ebene scripts;
    Frame 59
    gotoAndPlay("lb_fluttering_open"); // an Stelle von gotoAndPlay("lb_fluttering");

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
OPEN FLUTTERING gotoAndPlay("lb_fluttering_open") ⇒ der neue Status wird sofort erreicht
CLOSE FLUTTERING gotoAndPlay("lb_fluttering_close") ⇒ der neue Status wird sofort erreicht

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

Aktueller Zustand Neuer Zustand Aktion
OPEN CLOSE gotoAndPlay("lb_fluttering_open")
Aufruf von m_new_wings_state(CLOSE) ⇒ neuer Status ist erreicht
CLOSE OPEN gotoAndPlay("lb_fluttering_close")
Aufruf von m_new_wings_state(OPEN) ⇒ neuer Status ist erreicht
FLUTTERING CLOSE Aufruf von m_new_wings_state(CLOSE) ⇒ neuer Status ist erreicht
FLUTTERING OPEN Aufruf von m_new_wings_state(OPEN) ⇒ 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. (Dies ist ein ganzt typisches Problem bei der Entwicklung von Multimedia-Anwendungen: Der Benutzer oder andere Komponenten können zu jeder Zeit Zustandsänderungen veranlassen, auch wenn die Anwendung eine andere Aufgabe noch nicht vollständig erledigt hat.)

Folgende zusätzlichen Fälle müssen betrachtet werden:

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.
OPEN oder
CLOSE
CLOSE Aufruf von m_new_wings_state(CLOSE) ⇒ neuer Status ist erreicht
OPEN oder
CLOSE
OPEN Aufruf von m_new_wings_state(OPEN) ⇒ 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.view
{
  import flash.display.MovieClip;
  import hsa.tutorial.butterfly.event.ButterflyEvent;
  
  public class Butterfly extends MovieClip
  {
    /////////////////////////////////////////////////////////////////////////////
    // Constants
    /////////////////////////////////////////////////////////////////////////////
    
    public static const OPEN:       String = "open";
    public static const CLOSE:      String = "close";
    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;
    private var v_state_animation: String;
    
    // Auxiliary variable (for being able to perform delayed state changes)
    private var v_next_state: String = null;
    
    /////////////////////////////////////////////////////////////////////////////
    // Private methods
    /////////////////////////////////////////////////////////////////////////////

    // Should be private, but cannot as it is accessed from within the timeline!
    public function m_new_wings_state(p_state: String): void
    {
      if (p_state != v_state_animation)
      {
        v_state_animation = p_state;      
        // The state of the wings has changed. Inform the observers!
        this.dispatchEvent
          (new ButterflyEvent(ButterflyEvent.CHANGE_BUTTERFLY_ANIMATION));
      };

      // If the wings are in the correct position,
      // perform the delayed state change!
      if (v_next_state == p_state)
      {  
        this.gotoAndPlay(c_label_prefix + v_next_state);
        m_set_state(v_next_state); // Make up for the state change now!
        v_next_state = null;
      };
    }

    private function m_set_state(p_state: String): void
    {
      trace(v_state + " ===> " + p_state);
      
      if (v_state != p_state)
      {
        v_state = p_state;
        this.dispatchEvent(new ButterflyEvent());
      }
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // Attributes
    /////////////////////////////////////////////////////////////////////////////
    
    /**
     * The current state of the butterfly: 
     *   <code>OPEN</code>, <code>CLOSE</code> or <code>BUTTERFLY</code>.
     */
    public function get state(): String
    {
      return v_state;
    }
    
    public function set state(p_state: String): void
    {
      trace(v_state + " ---> " + p_state);
      
      if (p_state != OPEN && p_state != CLOSE && 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 (v_state != FLUTTERING)
          this.gotoAndPlay(  c_label_prefix_fluttering
                           + ((v_state == null) ? OPEN : v_state)
                          );

        if (p_state == FLUTTERING)
          m_set_state(p_state); // Do the state change now!
        else // p_state == OPEN || CLOSE
          v_next_state = p_state; // Delay the stage change.
      }
      else // Currently a delayed state change is performed!
      {
        if (p_state == FLUTTERING)
        {
          v_next_state = null;  // Stop the delayed state change.
          m_set_state(p_state); // Do the state change now!
        }
        else
          v_next_state = p_state; // Update the delayed state change;
      }
    }
    
    /**
     * The current state of the wings: 
     *   <code>OPEN</code> or <code>CLOSE</code>.
     */
    public function get stateAnimation(): String
    {
      return v_state_animation;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////////////
    
    public function Butterfly(p_state: String = OPEN)
    {
      this.state = p_state;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // End of class
    /////////////////////////////////////////////////////////////////////////////
  }
}

1.1 Anmerkung

Man beachte, dass hier nur eine verbesserte, wenn auch viel aufwändigere Implementierung des Symbols Butterfly angegeben wurde. An der zuvor definierten Schnittstellte ändert sich 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.

2 Quellen

2.1 SVN-Repository-Verweise


Dieser Artikel ist GlossarWiki-konform.