Wir wollen die neue Technik nun dazu einsetzen, das Vererbungsbeispiel "Warhol's Flowers" zu überarbeiten. Eine unschöne Eigenheit der Blumen war bisher, dass sie plötzlich verschwinden, wenn der Cursor die Zeichenfläche verlässt. Schöner wäre es, wenn sie wie echte Blumen nach einer Weile verwelken würden.
Da jede Blume unabhängig von den anderen welkt, bietet sich der Einsatz der actorList an. Wir verzichten auf den Aufruf der zeichnen()-Methode im exitFrame-Handler und verlegen dies in den stepFrame-Handler des Blumen-Prototyp-Objekts. Als neue Objekteigenschaften definieren wir mZustand, mBluehzeit und mPhase. mZustand hält fest, ob die Blume gerade wächst oder welkt, mBluehzeit gibt die Zeit in Frames an, die der Blume bis zum Welken noch bleibt und mPhase die Nummer der gerade angezeigten Grafik in mMemberListe.
Wird die Animation mit der Methode startAnimation() gestartet, fügt sich das Objekt der actorList hinzu und wird ab jetzt automatisch in jedem Frame gezeichnet. Das Objekt nimmt sich selbst aus der actorList, wenn das Ende des Welken erreicht ist. Dazu benutzt es das statische ObjektLoeschenObjekt, das im Unterkapitel "Vererbung mit the ancestor" beschrieben wird, um ein Stocken der anderen Blumenanimationen zu verhindern. Ansonsten wird die Zeit bis zum Welken heruntergezählt und schließlich mZustand auf #welken gesetzt. Je nachdem, welchen Wert mZustand hat, wird die aktuell angezeigte Phase von der Methode zeichnen() herauf- oder heruntergezählt. Ist die letzte Phase erreicht, wird die Animation gestoppt.
Dies ist das neue Skript für das BlumePrototyp-Objekt:
global gSpriteManagerObj
property mSpriteNummer, mPosition
property mMemberListe, mAnimationEin
property mZustand, mBluehzeit, mPhase
on new me, spritenummer, position
mSpriteNummer = spritenummer
mPosition = position
mMemberListe = ["Blume01", "Blume02", "Blume03",
"Blume04",
"Blume05", "Blume06", "Blume07", "Blume08",
"Blume09", "Blume10"]
mAnimationEin = false
-- wächst oder welkt die Blume?
mZustand = #wachsen
-- nach wievielen Frames verblüht die Blume?
mBluehzeit = 50
-- aktuell angezeigte Phase
mPhase = 1
return me
end new
on zeichnen me
-- zeichnet die Blume
sprite(mSpriteNummer).member = member(mMemberListe[mPhase])
sprite(mSpriteNummer).loc = mPosition
if mAnimationEin then
case mZustand of
#wachsen:
if mPhase < mMemberListe.count() then
mPhase = mPhase + 1
else
mAnimationEin = false
end if
#welken:
if mPhase > 1 then
mPhase = mPhase - 1
else
me.loeschen()
mAnimationEin = false
end if
end case
end if
end zeichnen
on startAnimation me
-- startet die Animation
mAnimationEin = true
-- das Objekt der actorlist hinzufügen
(the actorlist).add(me)
end startAnimation
on loeschen me
-- löscht die Blume und gibt das Sprite frei
gSpriteManagerObj.spriteFreigeben(mSpriteNummer)
end loeschen
on stepframe me
me.zeichnen()
if (not mAnimationEin) and (mZustand = #welken) then
-- Blume aus der actorlist löschen
script("ObjektLoeschenObjekt").loeschen(me)
else
-- Blühzeit herunterzählen
mBluehzeit = mBluehzeit - 1
if mBluehzeit < 0 then
mZustand = #welken
mAnimationEin = true
end if
end if
end stepframe
Im Gegensatz zur ersten Version des Beispielprogramms ist die neue Version effizienter, da nicht mehr in jedem Frame geprüft werden muss, ob die Blume im Moment animiert werden muss oder nicht, sondern am Ende des Animationszyklus' einfach das Objekt aus der actorList gelöscht wird.
Da sich die Anzahl der für die Blumen benutzten Sprites ständig ändert, arbeite ich mit einer dynamischen Verwaltung der Sprites. Diese Aufgabe wird vom Objekt SpriteManagerObjekt übernommen. Der new-Handler des Objektes erhält als Argument die Nummer des ersten Sprites, das benutzt werden kann. Dadurch wird verhindert, dass die Grafik des Hintergrundes in Sprite 1 von einer Blume ersetzt wird. Der Spritemanager implementiert die Methode spriteAnfordern(), um die Nummer eines freien Sprites zu erhalten, sowie die Methode spriteFreigeben(), um ein Sprite wieder für andere Animationen freizugeben. Mit dem Befehl puppetSprite(spriteNummer, TRUE) wird die Kontrolle über das angeforderte Sprite automatisch an Lingo weitergegeben; analog dazu geht beim Freigeben eines Sprites mit dem Befehl puppetSprite(spriteNummer, FALSE) die Kontrolle wieder an das Drehbuch zurück.
Hier ist der Programmcode des Spriteverwalter-Objektes:
-- Objekt, das die Sprites verwaltet
property mUsedSprites, mFirstSprite
on new me, erstesSprite
-- Liste, die alle benutzen Sprites enthält
mUsedSprites = []
-- das erste Sprite, das benutzt werden kann
mFirstSprite = erstesSprite
return me
end new
on spriteFreigeben me, spriteNummer
-- gibt ein Sprite wieder frei
puppetSprite(spriteNummer, FALSE)
mUsedSprites.deleteOne(spriteNummer)
end spriteFreigeben
on spriteAnfordern me
-- gibt ein Sprite zurück und reserviert dieses,
-- bis es freigegeben wird
spriteNummer = mFirstSprite
repeat while mUsedSprites.getPos(spriteNummer) > 0
spriteNummer = spriteNummer + 1
end repeat
mUsedSprites.add(spriteNummer)
puppetSprite(spriteNummer, TRUE)
return spriteNummer
end spriteAnfordern
![]() |
|||
![]() |
4.15 Synchronisation mit dem Drehbuch durch on stepframe und the actorlist | 4.17 Aufruf von Methoden mit call und callAncestor | ![]() |