Time-based Animations mit TimeOut Objekten (05/2001, Dir 8)

In diesem Bereich befinden sich Artikel und Tutorials zum Thema Director.

Moderatoren: Bär, Admin

Antworten
Admin
Site Admin
Beiträge: 41344
Registriert: 07.02.2006, 2006 16:09
Wohnort: München
Kontaktdaten:

Time-based Animations mit TimeOut Objekten (05/2001, Dir 8)

Beitrag von Admin » 12.02.2006, 2006 19:42

Time-based Animations mit TimeOut Objekten

Director ist schon aufgrund seiner Historie ein hervorragendes Animationswerkzeug. Mit sehr geringem Aufwand lassen sich Objekte im Drehbuch oder durch Lingo auf vielfältige Art und Weise auf der Bühne animieren. Dabei ist die Performance der Animation zunächst primär von der Leistung des Abspielsystems, also der Hardware, und sekundär von den verwendeten Darstellertypen, sowie deren Einstellungen (Farbeffekte, Farbtiefe etc.) abhängig. Diese Abhängigkeit führt dazu, dass z.B. eine Animation oder ein Spiel besonders als Shockwave unterschiedlichen Benutzern eine eventuell unterschiedliche Performance bietet, da im Internet nicht von einer homogenen Rechnerperformance ausgegangen werden kann.

Dieses Problem lässt sich zum einen über eine allgemeine Optimierung der Darsteller und ihrer Einstellungen lösen. Doch selbst dann kann es, gerade bei animationsreichen Spielen im Internet noch zu starken Unterschieden bei unterschiedlichen Abspielsystemen führen. Um dieses Problem zu lösen, sollte zunächst analysiert werden was genau der Grund für diese unterschiedliche Performance ist:

Ein Sprite Objekt bewegt sich bei einer Animation auf der Bühne. Die Bewegung macht sich bemerkbar, indem der Sprite seine Position bei jedem Frame-Durchlauf verändert. Die Geschwindigkeit der Bewegung ist dabei abhängig von der Geschwindigkeit mit der die Frames in einem bestimmten Zeitraum durchlaufen werden. Diese Frame-Geschwindigkeit lässt sich manuell oder durch Lingo (puppetTempo) einstellen. Je schneller also das allgemeine Frame-Tempo, desto schneller läuft auch die Animation ab. Diese Tatsache ist ziemlich offensichtlich und bedarf eigentlich keiner weiteren Erklärung. Eine weniger bekannte Tatsache ist jedoch, dass die Angabe des Frame-Tempo’s in Director nicht ein absolutes Zieltempo, sondern einen Grenzwert der Geschwindigkeit festlegt. Das bedeutet bei einer Angabe von 15fps wird Director angewiesen, dass nicht mehr als 15 Frames pro Sekunde durchlaufen werden dürfen. Daraus folgt jedoch, dass bei geringer Leistung die Geschwindigkeit aber auch durchaus darunter liegen kann.

Bei aufwendigen Animationen kann es deshalb dazu kommen, dass die reale Geschwindigkeit unter dem angegebenen Grenzwert (z.B. 60fps) liegt. In diesem Fall würde man von einer schlechten Performance sprechen. Aber auch der andere Fall kann eintreten. Eine Animation kann auf einem sehr leistungsstarken Rechner schneller als vom Autor gewünscht abgespielt werden, weil die bei der Erstellung eingestellte Grenzwertgeschwindigkeit von 120fps auf dem Autorensystem nie tatsächlich erreicht wurde. Besonders unerwünscht ist dieser Effekt bei Shockwave-Spielen, die eigentlich eine möglichst gleichbleibende Performance bieten sollten.

Betrachten wir nun die Tatsache, dass Bewegung nichts anderes ist als eine Positionsveränderung im Raum über ein bestimmtes Zeitintervall ist, so ergibt sich daraus, dass der Zeitfaktor der eigentlich entscheidende Regulator ist. Anstatt also die Positionsveränderung bei jedem Frame vorzunehmen, können wir stattdessen ein Zeitintervall in Form eines „Timeout“ Objektes verwenden. Wir verlegen also die Frame-basierte Animationssteuerung auf eine Zeit-basierte Steuerung.

Beim Start des Films rufen wir dazu zunächst eine Initialisierungsroutine auf, welche die interne Zeitsteuerung startet:

Code: Alles auswählen

on startMovie ()
  initTime(60)
end startMovie

on initTime (step)
  the timeOutList = []
  puppetTempo 1
  the idleHandlerPeriod = 0
  timeOut("Timer").new((1000/step), #stepTime)  
end initTime
Im Rahmen der Initialisierung wird zuerst die globale „timeoutList“ geleert. Anschließend wird der Tempokanal zum „Puppet“ gemacht und damit der Kontrolle durch Lingo unterworfen. Die Frame-Geschwindigkeit wird auf lediglich einen Frame pro Sekunde festgelegt. Dadurch wird erreicht, dass Director nicht häufiger als notwendig die Bühne neu zeichnen muss. Dies ist eine wichtige Performance Maßnahme, da in vielen Fällen keinerlei Notwendigkeit besteht 30 oder sogar 60 Mal pro Sekunde die Bühne zu rendern.

Außerdem wird die „idleHandlerPeriod“ auf 0 gesetzt. Die Einstellung bewirkt, dass Director so viele „idle“ Events wie möglich sendet und damit mehr Zeit für z.B. komplexe Berechnungen bereithält.

Anschließend wird ein neues „Timeout“ Objekt mit dem Namen „Timer“ erzeugt. Da „Timeout“ Objekte als Parameter für das Zeitintervall eine Angabe in Millisekunden erwarten, man aber gewohnt ist das Tempo eher in „fps“ anzugeben, kann man es einfach bei dieser Einheit belassen. Der zweite Paramter gibt dem „Timeout“ Objekt den Namen des, in diesem Fall globalen Timeout-Handler „stepTime“ an.

Code: Alles auswählen

on stepTime ()
  sendAllSprites(#stepTime)
end stepTime
Alle 1/60 Sekunden wird also nun dieser Handler aufgerufen. Um nun den Sprites auf der Bühne bzw. ihren Behavior Instanzen mitzuteilen, dass ein Zeitintervall abgelaufen ist, werden sie über den „sendAllSprites“ Befehl darüber informiert.

Code: Alles auswählen

-- simple animation
on stepTime (me)
  sprite(me.spritenum).locH = sprite(me.spritenum).locH mod the stageRight + 10
end stepTime
Jeder Sprite bzw. jedes Sprite Behavior, dass sich nach diesem Taktgeber richten soll benötigt nun diesen Handler. Anderenfalls wird der Sprite nicht animiert, was ja andererseits auch in vielen Fällen gar nicht notwendig ist. Events wie Mausklicks oder Tastaturkommandos sind sowieso Realtime-Events, die stets unabhängig vom Frame-Tempo ausgelöst werden. In diesem Fall wird der Sprite einfach in einer endlosen Animation von links nach rechts über die Fläche der Bühne bewegt. Das was normalerweise beim „exitFrame“ Event stattgefunden hat, wurde also nun einfach in einen anderen Handler verschoben.

Der große Vorteil ist nun, dass die Animation unabhängig vom Frame-Tempo stets gleich abläuft. Es lassen sich sogar einfach mehrere Animationen zu einander synchronisieren, oder eine Animation mit halber oder doppelter Geschwindigkeit abspielen.

Code: Alles auswählen

on pauseTime ()
  timeOut("Timer").time = -1
end pauseTime

on continueTime ()
  timeOut("Timer").time = 0
end continueTime
Ebenso einfach kann nun die gesamte Animation angehalten und auch wieder fortgeführt werden indem das „time“ Property des „Timeout“ Objektes gesetzt wird.

Um die Performance noch ein bisschen weiter zu optimieren, sollte man entgegen der üblichen Praxis KEINE 1-Frame-Loops erstellen, sondern die Sprites immer über z.B. 10 Frames oder mehr animieren und dann im 10. bzw. letzten Frame wieder zu Frame 1 springen:

Code: Alles auswählen

on exitFrame me
  go the frame - 10
end
Der Grund dafür ist relativ einfach. Director ist ursprünglich als Animationswerkzeug konzipiert worden. Daher kennt die interne Engine keine Rückwertsbewegung, sondern springt lediglich immer zum jeweils nächsten Frame. Wird in diesem Frame eine Lingo Anweisung gegeben die bestimmt, dass der Abspielkopf zu einen vorherigen Frame springen soll, so muss dieser neue Zielframe erst im Drehbuch lokalisiert werden bevor er angesprungen werden kann.

Bei einem 1-Frame-Loop mit einer „go the frame“ Anweisung wird Director instruiert stets den jeweils aktuellen Frame zu identifizieren, um anschließend exakt dort hin zu springen. Director macht sich nämlich in der Regel keinerlei Gedanken in welchem Frame sich der Abspielkopf gerade befindet, es sei denn er wird explizit danach gefragt. Aus diesem Grund muss Director also bei einem Frame-Tempo von 60fps genau 60 Mal pro Sekunde den eigenen Frame finden, was natürlich zu Lasten der Performance geht. Im Gegensatz dazu müsste Director diesen Vorgang bei einem Frame-Tempo von 1 und einer Sprunkmarke alle 10 Frames nur alle 10 Sekunden einmal machen, was nur 1/600 des Aufwands bei gleichem Resultat bedeutet!


Fazit

Die Technik der „Time-based Animation“ ist im Gegensatz zur klassischen „Frame-based Animation“ besonders was die Performanceoptimierung betrifft zu empfehlen und letztlich sogar leichter zu kontrollieren. Alle Änderungen können dynamisch jederzeit auch während der Laufzeit vorgenommen werden. Das betrifft vor allem die Problematik der unterschiedlichen Geschwindigkeiten abhängig vom jeweiligen Abspielsystem. Im Bereich der Shockwave-Spiele ist diese Technik daher eine wichtige Maßnahme um eine gleichbleibende Performance zu gewährleisten.

Aber auch für Anwendungen bei denen jeweils die optimale Performance erzielt werden soll, ist dieser Ansatz gut geeignet. Im Rahmen einer Initialisierungsroutine kann beispielsweise die tatsächliche Geschwindigkeit des jeweiligen Rechners getestet und anhand der Testergebnisse die tatsächliche Geschwindigkeit festgelegt werden, so dass bei bestimmten Anwendungen die jeweils bestmögliche Performance erzielt werden kann.


Autor: Martin Kloss

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste