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 |  |