EINFÜHRUNG |
Die Computergrafik kann ähnlich wie in einem Film zur Darstellung von zeitlich veränderlichen Inhalten verwendet werden. Man nennt ein so eingesetztes Programm eine Computeranimation. Um den zeitlichen Ablauf sichtbar zu achten, wird in einer Animationsschleife immer nach einem gleich grossen Zeitschritt ein neues Bild gezeichnet, das sich nur wenig vom vorhergehenden unterscheidet. Werden mehr als 25 Bilder pro Sekunde erzeugt, so ergibt sich für das Auge eine fliessende Bewegung. |
FIGUREN BEWEGEN |
Das Prinzip der Animation kannst du an einer sich scheinbar bewegenden Figur ausprobieren. Dabei zeichnest du die Figur in kurzen Zeitschritten an leicht verschobenen Positionen. Die vorangehende Figur musst du immer wieder löschen.
from gturtle import * def drawFigure(): repeat 3: fillToPoint(0, 0) rightArc(100, 90) right(90) rightArc(100, 90) right(90) left(120) makeTurtle() hideTurtle() setPenColor("black") while True: drawFigure() delay(100) clear() right(20) |
MEMO |
In einer Animationsschleife zeichnest du die Figur periodisch an leicht verschobenen Positionen. Um die vorangehende Figur zu löschen, löschst du den ganzen Bildschirm. |
BILDSCHIRMFLACKERN VERMEIDEN |
Üblicherweise ist jeder Zeichnungsbefehl sofort auf dem Bildschirm sichtbar. Daher erscheint beim Löschen des Bildschirmes mit clear() kurz ein leeres Grafikfenster, was zu einem unschönen Bildschirmflackern führen kann. Um dies zu vermeiden, verwendest du die sogenannte Doppelbufferung. Du rufst den Befehl enableRepaint(False) auf, der bewirkt, dass die Grafikbefehle in einem unsichtbaren Bildbuffer ausgeführt werden und nicht mehr automatisch im Grafikfenster erscheinen. Erst wenn das neue Bild vollständig im Buffer aufgebaut ist, stellst du mit repaint() den ganzen Buffer auf einmal auf dem Bildschirm dar.
Da du enableRepaint(False) verwendest, musst du jedesmal nach dem Zeichnen repaint() aufrufen, damit der Inhalt des Bildbuffers auf dem Bildschirm sichtbar wird. Zum Löschen des Bildschirmes verwendest du den Befehl clear("lightSkyBlue"). Dadurch erhältst du eine hellblaue Hintergrundfarbe. from gturtle import * def drawBird(angle): dot(20) right(angle) rightArc(100, 90) home() left(angle) leftArc(100, 90) home() def move(start, end, step): for a in range(start, end, step): clear("lightSkyBlue") drawBird(a) repaint() delay(40) makeTurtle() hideTurtle() setLineWidth(5) setPenColor("black") enableRepaint(False) while True: move(55, 5, -2) move(5, 55, 2) |
MEMO |
Der Befehl enableRepaint(False) bewirkt, dass die Grafikbefehle nicht automatisch im Turtlefenster sichtbar sind, sondern nur im Bildbuffer ausgeführt werden. Damit das neue Bild angezeigt wird, musst du aber an geeigneter Stelle repaint() aufrufen. |
GLEICHMÄSSIGE BEWEGUNG |
Die Animationsschleife sollte in möglichst gleichen Zeitticks durchlaufen werden, da sonst die Bewegung ruckelt. Die Operationen in der Animationsschleife können aber unterschiedlich viel Zeit in Anspruch nehmen, selbst wenn der Code immer derselbe ist, der Computer im Hintergrund noch mit anderen Aufgaben beschäftigt ist. Um die verschieden lange Ausführung der Animationsschleife auszugleichen, wird daher folgender Trick angewendet: Man merkt sich in der Variable startTime vor den Zeichnungsoperationen die aktuelle Systemzeit, die du als Dezimalzahl mit time.time() erhältst.
from gturtle import * import time def wall(): setPenColor("green") setLineWidth(10) setPos(-200, -50) forward(100) setPos(200, -50) forward(100) makeTurtle() hideTurtle() enableRepaint(False) x = -170 v = 10 while True: startTime = time.time() clear() wall() setPos(x, 0) setPenColor("red") dot(60) repaint() x = x + v if x > 165 or x < -165: v = -v while (time.time() - startTime) < 0.020: delay(1) |
MEMO |
Ein gleichmässig bewegtes Bild erreichst du, indem du in gleichen zeitlichen Abständen die Figur an der neuen Position anzeigst. Dazu taktest du die Animation unter Verwendung der Systemzeit. Auch in diesem Beispiel wendest du das Prinzip der Doppelbufferung an, um das Flackern zu vermeiden. |
TURTLE ALS LEITFIGUR FÜR SPRITES VERWENDEN |
Statt das Bild mit der Turtle zu zeichnen, kannst du auch ein Computerimage verwenden, das als png-, gif- oder jpg-Datei vorliegt. In der Gameprogrammierung nennt man ein solches Bild ein Sprite und das bewegte Bildschirmobjekt einen Aktor. Um ein Sprite zu verwenden, rufst du drawImage() auf und gibst dabei den Pfad zur Bilddatei an (als absoluter Dateipfad, als Dateipfad relativ zum Verzeichnis, in dem sich dein Programm befindet, oder als Internet URL).
from gturtle import * import time makeTurtle() hideTurtle() penUp() setPos(-180, 0) enableRepaint(False) while True: startTime = time.time() clear() drawImage("sprites/car0.png") repaint() forward(3) right(1) while (time.time() - startTime) < 0.04: delay(1) |
MEMO |
Bewegte Figuren, Aktoren genannt, spielen in Computergames eine zentrale Rolle. Mit der Turtle kannst das Spritebild auf dem Bildschirm bewegen und rotieren. |
ANIMIERTE AKTOREN |
from gturtle import * import time makeTurtle() hideTurtle() penUp() wrap() enableRepaint(False) right(90) i = 0 while True: startTime = time.time() clear("lightblue") drawImage("sprites/person_" + str(i) + ".png") repaint() forward(10) i += 1 if i == 5: i = 0 while (time.time() - startTime) < 0.1: delay(1) |
MEMO |
Du kannst eine Computeranimation auf verschiedene Arten programmieren. Am einfachsten ist, es, das Bild der Turtle zu ersetzen, indem du in makeTurtle() einen Bildpfad angibst. Du kannst sodann mit Grafikbefehlen ein sich veränderndes Bild zeichnen oder schliesslich die Turtle als Leitfigur dazu verwenden, geladene Bilder zu bewegen. Willst du eigene Spritebilder einbinden, so müssen sie in der gewünschten Pixelgrösse im png-, gif- oder jpg-Format erstellt sein. Sie sollten meinst einen transparenten Hintergrund haben, damit die rechteckige Bildumgebung nicht sichtbar ist, wenn du sie in einem Fenster mit farbigem Hintergrund verwendest oder die Bilder sich überlappen. Die Dateinamen der Bilder person_0.png, .... person_4.png werden mit der Variablen i zusammengesetzt. |
AUFGABEN |
|
ZUSATZSTOFF |
ERSTELLEN EINES VIDEO-FILMS |
In fast allen modernen Kinofilmen werden einzelne Sequenzen oder sogar der ganze Film aus computererzeugten Bildern dargestellt. In TigerJython kannst du mit wenig Aufwand eine Animationssequenz mit kleiner bis hoher Auflösung in einer Video-Datei im hoch-komprimierten MP4-Format abspeichern. Die dabei erzeugte Video-Datei kannst du mit einem beliebigen MP4-Player abspielen, der das H.264/AVC-Format unterstützt, beispielsweise mit dem VLC Media Player, dem Quick-Time-Player oder mit Video-Apps auf praktisch allen modernen Smartphones. Du kannst sogar deinen Film im HD-Format auf einem modernen Fernsehgerät oder Beamer wiedergeben. Die Anzahl der Bilder, die pro Sekunden abgespielt werden, ist von der gewählten Auflösung abhängig, beträgt aber üblicherweise 25 Bilder/Sekunde. Beim Erzeugen der Bilder spielt es aber keine Rolle, wie lange die Berechnung eines einzelnen Bildes mit dem Computeer dauert, du brauchst die Bilder nicht einmal auf dem Bildschirm zu rendern. Darum brauchst du dich auch nicht um Flackern und Ruckeln zu kümmern. Es liegt vollständig in der Verantwortung des Video-Players, Bild um Bild flacker- und ruckelfrei wiederzugeben. Im ersten Beispiel nimmt du die oben gezeigte Animation des Vogelfluges. Zuerst erzeugst du mit rec = VideoRecorder(t, "bird.mp4", "640x480")
Die Graphikelemente (Turtles, Spuren, Bilder) des Turtlefensters kopierst du mit rec.captureImage() in die Video-Datei. Am Schluss musst du diese Datei mit rec.finish() schliessen. from gturtle import * def drawBird(angle): dot(20) right(angle) rightArc(100, 90) home() left(angle) leftArc(100, 90) home() def move(start, end, step): for a in range(start, end, step): clear("lightSkyBlue") drawBird(a) rec.captureImage() Options.setPlaygroundSize(640, 480) t = makeTurtle() rec = VideoRecorder(t, "bird.mp4", "640x480") hideTurtle() setLineWidth(5) setPenColor("black") nbSwings = 5 n = 0 while n < nbSwings: move(55, 5, -2) move(5, 55, 2) n += 1 rec.finish() print("all done") |
MEMO |
Manchmal ist es nötig, dass ein einzelnes Bild mehrmals abgespeichert wird. Willst du beispielsweise eine Sequenz von Bewegungen erstellen, die nur jede 1/5 Sekunde ändern, so muss du bei einer Bildrate von 25 Bildern/Sekunde genau 5 gleiche Bilder hintereinander abspeichern. Statt einer eigenen Wiederholschleife kannst du dies einfacher mit rec.captureImage(5) programmieren. |
from gturtle import * from random import randint Options.setPlaygroundSize(1280, 1024) t = makeTurtle() hideTurtle() clear("lightcyan") rec = VideoRecorder(t, "painting.mp4", "1280x1024") for i in range(50): x = randint(-300, 300) y = randint(-300, 300) setPos(x, y) r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) c = makeColor(r, g, b) setPenColor(c) d = randint(50, 400) dot(d) rec.captureImage(5) rec.finish() |
from gturtle import * Options.setPlaygroundSize(640, 480) t = makeTurtle() rec = VideoRecorder(t, "person.mp4", "640x480") hideTurtle() penUp() setPos(-320, -30) right(90) i = 0 nbFrames = 140 n = 0 while n < nbFrames: clear("grey") drawBkImage("sprites/catbg.png") drawImage("sprites/person_" + str(i) + ".png") rec.captureImage() forward(5) i += 1 if i == 5: i = 0 n += 1 rec.finish()
|