AS3-Tutorium: Flash: Butterfly 07a character
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
Weiterentwicklung der sechsten Version des Schmetterling-Movies
<swf width="367" height="267">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_07a_character/Butterfly07aFlash11.swf</swf> Musterlösung (Flash CS5) (SVN-Repository)
Musterlösung (Flash CS4) (SVN-Repository)
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 (Teil 7b, Teil 7c) 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.
Zu guter Letzt (Teil 8) wird das Symbol ButterflyMovie
ebenfalls in eine „Spielfigur“ umgewandelt.
Das Datenmodell
Bevor mit der Programmierung einer Anwendung begonnen wird, sollte zunächst ein Datenmodell (Klassendiagramm, Zustandsdiagramm etc.) erstellt werden. Folgendes Klassendiagramm wird in diesem Teil des Tutorium realisiert:
Ordner mit StarUML-Diagramm und von StarUML erzeugtem AS3-Code-Rahmen (SVN-Repository)
Es gibt eine Klasse zur Visualisierung einer Spielfigur (eine so genannte View-Klasse):
Butterfly
, eine Spielfigur, die sich nicht vom Platz bewegt, aber verschiedene Zustände annehmen kann.
Diese Klasse ist, da sie Symbolen zugeordnet wird, Subklassen der ActionScript-Klasse MovieClip
.
Ein Schmetterling kann drei Zustände annehmen:
- Flügel offen (
OPEN
) - Flügel geschlossen (
CLOSE
) - flatternd (
FLUTTERING
)
Dieser Zustand kann über das Attribut state
gelesen und modifiziert werden.
Mit Hilfe des Attributs stateAnimation
kann erfragt werden, in welchem Zustand sich die
Animation gerade befindet (Flügel offen oder geschlossen). Dies ändert sich insbesondere während des Flatterns
ständig.
Der Schmetterling informiert mittels Signalen (Events) interessierte Beobachter (Observers, Event Listeners) sowohl
dann, wenn sich der Zustand (state
) ändert, als auch dann, wenn sich der Zustand der Animation
(stateAnimation
), d.h. der Flügel ändert. Dazu wird die Signal-Klasse ButterflyEvent
(eine Subklasse der ActionScript-Klasse Event
) definiert, die zwei Konstanten zur Beschreibung dieser Ereignistypen bereithält.
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 sollgotoAndPlay(lb_
x
);
, falls die dem Zustand zugeordnete Animation dauerhaft abgespielt werden soll
Zunächst wird das Schmetterlingssymbol auf diese Weise umgestaltet.
- In der Bibliothek: Das Symbol
Butterfly
mit einem Doppelklick öffnen. - In der Zeitleiste: Zwei neue Ebenen (ganz oben) einfügen:
scripts
labels
- 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.
- 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. - 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
. - In der Zeitleiste, Ebene
wings
: Klick auf Frame 20 → Rechtsklick auf Frame 20 →Schlüsselbild einfügen
. - 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
. - In der Zeitleiste, Ebene
wings
: Klick auf Frame 1 → Rechtsklick auf Frame 1 →Bilder einfügen
(nichtBild einfügen
!!). - 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
. - In der Zeitleiste, Ebene
wings
: Klick auf Frame 20 → Rechtsklick auf Frame 20 →Bilder einfügen
(nichtBild einfügen
!!). - In der Zeitleiste, Ebene
labels
: Klick auf Frame 1 → Eigenschaften-Fenster öffnen → Name:lb_open
- In der Zeitleiste, Ebene
labels
: Klick auf Frame 20 → Rechtsklick auf Frame 20 →Schlüsselbild einfügen
→ Eigenschaften-Fenster, Name:lb_close
- In der Zeitleiste, Ebene
labels
: Klick auf Frame 40 → Eigenschaften-Fenster, Name:lb_fluttering
- In der Zeitleiste, Ebene
scripts
folgenden Code eintragen (Schlüsselbilder nicht vergessen!):- Frame 19
stop();
- Frame 39
stop();
- Frame 59
gotoAndPlay("lb_fluttering");
Als nächstes wird der Code zur Steuerung des Zustandswechsels dem Schmetterlings-Symbol zugeordnet:
- Im Menü:
Datei
→Neu
→ActionScript 3.0-Klasse
(CS5) bzw.ActionScript-Datei
(CS4 und früher) →OK
Nur in CS5: -> Klassenname:Butterfly
→OK
- Im Menü:
Datei
→Datei speichern unter
→ Im Ordner derfla
-Datei folgende Unterordner anlegen:hsa/tutorial/butterfly/view
→ Datei unter dem NamenButterfly.as
im zuvor angelegten Unterordner speichern. - In der Bilbliothek: Rechtsklick auf das Symbol
Butterfly
→Eigenschaften
→ falls notwendig: Klick auf Dreieck hinterErweitert
→ Häckchen vorExport für ActionScript
→ Klasse:hsa.tutorial.butterfly.view.ButterflyBlue
(oder eine andere Farbe), Basisklassehsa.tutorial.butterfly.view.Butterfly
→OK
→OK
Nun kann in die Datei Butterfly.as
folgendener Code einfügt werden:
package hsa.tutorial.butterfly.view
{
import flash.display.MovieClip;
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_";
/////////////////////////////////////////////////////////////////////////////
// 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(c_label_prefix + p_state);
v_state = p_state;
};
}
/////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////
public function Butterfly(p_state: String = OPEN)
{
this.state = p_state;
}
/////////////////////////////////////////////////////////////////////////////
// End of class
/////////////////////////////////////////////////////////////////////////////
}
}
Anmerkung 1
Man beachte, dass im Gegensatz
zu den vorangegangen Tutorien die Labelbezeichnungen nicht
mehr lbOpen
, lbClose
und lbFluttering
lauten, sondern lb_open
, lb_close
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 (die Attribute state
und stateAnimation
).
Nur über diese Schnittstelle darf von außen auf ein Schmetterlingsobjekt zugegriffen werden.
Wenn man einen Schmetterling
auf die Bühne legt und ihm den „Instanznamen“ d_butterfly
gibt,
kann man mit folgenden Befehlen dessen Zustand verändern:
import hsa.tutorial.butterfly.view.Butterfly;
d_butterfly.state=Butterfly.OPEN;
d_butterfly.state=Butterfly.CLOSE;
d_utterfly.state=Butterfly.FLUTTERING;
Außerdem kann man den aktuellen Zustand des Schmetterling und auch seiner Flügel jederzeit lesen.
Allerdings wurde das obige Klassendiagramm noch nicht vollständig implementiert. Es fehlen noch zwei „Event Dispatcher“. Wie diese realisiert werden, wird im Folgenden gezeigt.
Signale
Bei jeder Zustandsänderung soll das Schmetterlings-Objekt laut Klassendiagramm alle interessierten Objekte, d.h. alle Observer (bzw. in ActionScript: Event 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 ButterflyEvent
-Konstanten einzuführen.
Die zugehörige Datei ButterflyEvent.as
muss, wenn als Package-Name ebenfalls hsa.tutorial.butterfly.event
angegeben wird, im Unterordner hsa/tutorial/butterfly/event
gespeichert werden.
Der Inhalt dieser Datei könnte folgendermaßen aussehen:
package hsa.tutorial.butterfly.event
{
import flash.events.Event;
public class ButterflyEvent extends Event
{
/////////////////////////////////////////////////////////////////////////////
// Constants
/////////////////////////////////////////////////////////////////////////////
public static const CHANGE_BUTTERFLY: String
= "change butterfly";
public static const CHANGE_BUTTERFLY_ANIMATION: String
= "change butterfly animation";
/////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////
public function ButterflyEvent(type: String = CHANGE_BUTTERFLY)
{
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(c_label_prefix + p_state);
v_state = p_state;
this.dispatchEvent(new ButterflyEvent());
};
}
Damit jede Änderung der Flügelstellung ebenfalls mit Hilfe eines Signals (der Art CHANGE_STATE_ANIMATION
) angezeigt wird, ist
ein wenig mehr Aufwand notwendig. In der Zeitleiste des Symbols Butterfly
müssen geeignete Methodenaufrufe eingefügt werden:
- In der Zeitleiste des Symbols
Butterfly
, Ebenescripts
folgenden Code eintragen (Schlüsselbilder nicht vergessen!):- Frame 1
m_new_wings_state(OPEN);
- Frame 20
m_new_wings_state(CLOSE);
- Frame 40
m_new_wings_state(OPEN);
- Frame 50
m_new_wings_state(CLOSE);
Nun müssen noch die Methode m_new_wings_state
sowie
das Attribut stateAnimation
in die Klasse Butterfly
eingefügt werden. Man beachte, dass es
keine Setter-Methode gibt. Das Attribut kann von außen nur gelesen werden.
private var v_state_animation: String;
public function get stateAnimation(): String
{
return v_state_animation;
}
// 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;
this.dispatchEvent
(new ButterflyEvent(ButterflyEvent.CHANGE_BUTTERFLY_ANIMATION));
};
}
Insgesamt sieht der Inhalt der Datei Butterfly.as
nun folgendermaßen aus:
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_";
/////////////////////////////////////////////////////////////////////////////
// Instance variables
/////////////////////////////////////////////////////////////////////////////
private var v_state: String;
private var v_state_animation: String;
////////////////////////////////////////////////////////////////////////////
// Methods to be accessed from within the timeline!
/////////////////////////////////////////////////////////////////////////////
// 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;
this.dispatchEvent
(new ButterflyEvent(ButterflyEvent.CHANGE_BUTTERFLY_ANIMATION));
};
}
////////////////////////////////////////////////////////////////////////////
// Attributes
/////////////////////////////////////////////////////////////////////////////
public function get state(): String
{
return v_state;
}
public function set state(p_state: String): void
{
trace(v_state + " ---> " + p_state);
if (p_state != v_state)
{
this.gotoAndPlay(c_label_prefix + p_state);
v_state = p_state;
this.dispatchEvent(new ButterflyEvent());
};
}
public function get stateAnimation(): String
{
return v_state_animation;
}
/////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////
public function Butterfly(p_state: String = OPEN)
{
this.state = p_state;
}
/////////////////////////////////////////////////////////////////////////////
// End of class
/////////////////////////////////////////////////////////////////////////////
}
}
Damit ist es z.B. möglich, einen Flügelschlag-Sound mit dem Movie zu synchronisieren. Im folgenden Beispiel wird der aktuelle Zustand des Flügels in einem zweiten Textfeld ausgegeben. Ein drittes Textfeld simuliert den Flip-Flap-Sound (da mir derzeit leider kein echter Flügelschlag-Sound vorliegt).
Testen der Klassen
<swf width="183" height="133">http://glossar.hs-augsburg.de/beispiel/tutorium/flash_cs5/butterfly/butterfly_07a_character/Butterfly07aFlash11.swf</swf>
Um diese Verhalten zu erreichen, wird auf die Bühne ein Schmetterlingsobjekt gelegt und der Name d_butterfly
zugeordnet.
Anschließend wird in der Hauptzeitleiste in regelmäßigen Abständen
einer der folgenden drei Befehle eingefügt:
d_butterfly.state=Butterfly.OPEN;
d_butterfly.state=Butterfly.CLOSE;
d_butterfly.state=Butterfly.FLUTTERING;
Zuletzt wird der Bühne
die Klasse hsa.tutorial.butterfly.Main
zugeordnet
(wobei sich die zugehörige Datei Main.as
im Unterordner hsa/tutorial/butterfly
befindet):
package hsa.tutorial.butterfly
{
import flash.display.MovieClip;
import hsa.tutorial.butterfly.event.ButterflyEvent;
import hsa.tutorial.butterfly.view.Butterfly;
import fl.transitions.Tween;
import fl.transitions.easing.None;
public class Main extends MovieClip
{
/////////////////////////////////////////////////////////////////////////////
// Instance Variables
/////////////////////////////////////////////////////////////////////////////
private var v_tween: Tween;
/////////////////////////////////////////////////////////////////////////////
// MovieClips on the stage
/////////////////////////////////////////////////////////////////////////////
public var d_butterfly: Butterfly;
/////////////////////////////////////////////////////////////////////////////
// Constructor
/////////////////////////////////////////////////////////////////////////////
public function Main()
{
d_butterfly
.addEventListener(ButterflyEvent.CHANGE_BUTTERFLY, o_change);
d_butterfly
.addEventListener(ButterflyEvent.CHANGE_BUTTERFLY_ANIMATION, o_wings);
}
/////////////////////////////////////////////////////////////////////////////
// Observer methods
/////////////////////////////////////////////////////////////////////////////
private function o_change(p_event: ButterflyEvent): void
{
d_label_state.text = d_butterfly.state;
}
private function o_wings(p_event: ButterflyEvent): void
{
d_label_wings.text = d_butterfly.stateAnimation;
d_label_flap.text = (d_butterfly.stateAnimation == Butterfly.OPEN)
? "flip"
: "flap";
if (v_tween != null && v_tween.isPlaying)
v_tween.stop();
v_tween =
new Tween
( d_label_flap, // the object to be animated
"alpha", // animation attribute: "x", "y", "alpha", "rotation", ...
None.easeNone, // animation type
1.0, 0.0, // start and end value (of alpha)
15, // Dauer der Animation ...
false // duration in frames (not in seconds)
);
v_tween.start();
}
/////////////////////////////////////////////////////////////////////////////
// End of class
/////////////////////////////////////////////////////////////////////////////
}
}
Quellen
- Kowarschick, W.: Multimedia-Programmierung
- Musterlösung (Flash CS5)
- Musterlösung (Flash CS4)
- Erweiterte Musterlösung (Flash CS4)
- Erweiterte Musterlösung (Flash CS5)
SVN-Repository-Verweise
- Musterlösung (Flash CS5)
- Musterlösung (Flash CS4)
- Erweiterte Musterlösung (Flash CS4)
- Erweiterte Musterlösung (Flash CS5)