Interaktion#
on_setup und act#
Bisher hast du Befehle einfach untereinander geschrieben und die Befehle wurden dann von oben nach unten abgearbeitet.
Wenn du ein interaktives Programm schreiben willst, dann musst du dies etwas durchbrechen.
Dazu kannst du Methoden registrieren, die zu bestimmten Zeiten aufgerufen werden oder auf bestimmte Ereignisse reagieren.
Wir fangen mit zwei einfachen Methoden an, on_setup
und act
on_setup
wird einmal aufgerufen, wenn dasWorld
erstellt wurde.act
wird immer und immer wieder aufgerufen, einmal pro Zeiteinheit.
Das folgende Programm:
from miniworlds import *
world = World()
world.size = (120,210)
@world.register
def on_setup(self):
print("setup")
@world.register
def act(self):
print("act")
liefert z.B. folgende Ausgabe
setup
act
act
act
Code-Blöcke#
Die Zeile def on_setup(self):
endet mit einem Doppelpunkt. Darunter siehst du einen Codeblock:
Die Inhalte der Funktion sind alle eingerückt, alles was gleich weit eingerückt ist, gehört zu einem Block.
from miniworlds import *
world = World()
world.size = (120,210)
@world.register
def on_setup(self):
print("Dies ")
print("ist ")
print("Teil ")
print("eines Codeblocks ")
print("Dies aber nicht")
Beim Aufruf von on_setup
werden die vier Zeilen darunter aufgerufen, nicht aber die 5. Zeile.
… note:: In der Regel verwendet man in Python 4 Leerzeichen, wenn man einen Codeblock einrückt. Es ist zwar kein Fehler, wenn du nur 3,2,1 oder 5 Leerzeichen oder ein Tab verwendest, solange du immer gleich weit einrückst - Dies wird von erfahrenen Programmierern aber als schlecher Stil empfunden.
Frame Rate - Wie oft wird act() aufgerufen#
Man kann einstellen, wie oft act()
aufgerufen wird, indem man die Attribute world.fps
und world.speed
konfiguriert.
world.fps
definiert dieframe rate
. Analog zu einem Daumenkino, bei dem du mit festgelegter Geschwindigkeit die Seiten umblätterst, definiert die Framerate wie oft pro Sekunde das Bild neu gezeichnet wird.world.fps
hat den Standardwert 60, d.h. es werden 60 Bilder pro Sekunde angezeigt.Im Attribut
world.frame
wird der aktuelle frame gespeichert. Die Frames seit Programmstart werden hochgezählt.world.speed
definiert wie oft die Programmlogik (z.B. act) pro Sekunde aufgerufen wird. Ein Wert von 60 bedeutet, dass die act()-Methode jeden 60. Frame aufgerufen wird.
from miniworlds import *
world = World()
world.size = (120,210)
@world.register
def on_setup(self):
world.fps = 1
world.speed = 3
@world.register
def act(self):
print(world.frame)
world.run()
Das Programm oben hat die Ausgabe:
3
6
9
12
15
Es wird sehr langsam hochgezählt, weil genau ein Frame pro Sekunde abgespielt wird und jeden 3. Frame
(also alle 3 Sekunden) die Funktion act()
aufgerufen wird.
Warning
Achtung: Es kann zu unvorhergesehenen Nebenwirkungen führen, wenn man Code falsch einrückt, betrachte z.B. folgendes Programm:
from miniworlds import *
world = World()
world.size = (120,210)
@world.register
def on_setup(self):
print(1)
print(2)
@world.register
def act(self):
print(3)
print(4)
world.run()
Das Programm hat die Ausgabe:
1
2
4
1
3
3
Dies liegt daran, dass zuerst on_setup()
ausgeführt wird, nachdem in Zeile 3 das World erstellt wurde.
Anschließend werden die beiden nicht eingerückten Befehle ausgeführt und sobald run()
gestartet wird, wird die Funktion
act()
aufgerufen. Achte darauf, dass deine Anweisungen sich innerhalb der Code-Blöcke von act und on_setup befinden.
Maus-Interaktionen#
Interaktionen finden im miniworlds über Events statt. Events können durch unterschiedlichste Systemereignisse aufgerufen werden, z.B. wenn der Benutzer eine Eingabe mit der Tastatur oder mit der Maus getätigt hat.
Zunächst schauen wir uns Mausinteraktionen an:
Mit der Methode get_mouse_position
kannst du die Mausposition abfragen:
from miniworlds import *
world = World()
@world.register
def on_setup(self):
world.size = (200,200)
@world.register
def act(self):
Ellipse(world.get_mouse_position(), 10, 10)
world.run()
Der Kreis folgt nun deiner Mausposition:
Wenn du Linien zeichnen möchtest, benötigst du die aktuelle und die letzte Mausposition. Dies geht z.B. wie folgt:
from miniworlds import *
world = World()
@world.register
def on_setup(self):
world.size = (200,200)
@world.register
def act(self):
Line(world.get_prev_mouse_position(), world.get_mouse_position())
world.run()
Listener-Methoden#
Schön wäre es, wenn wir noch auf spezifische Events reagieren können, z.B. auf Tastendrücke oder Mausklicks.
Dafür können wir bestimmte Listener-Methoden registrieren, z.B. on_mouse_pressed
from miniworlds import *
world = World()
@world.register
def on_setup(self):
world.size = (200,200)
@world.register
def act(self):
Ellipse(world.get_mouse_position(), 10, 10)
@world.register
def on_mouse_left(self, position):
world.fill_color = (255, 0, 0)
@world.register
def on_mouse_right(self, position):
world.fill_color = (255, 255, 255)
world.run()
Tastaturabgaben abfragen#
Du kannst auch Angaben von der Tastatur abfragen:
from miniworlds import *
world = World()
@world.register
def on_setup(self):
world.size = (200,200)
@world.register
def on_key_down_a(self):
a = Ellipse.from_center((100, 100), 100, 100)
a.fill_color = (255, 0, 0)
@world.register
def on_key_down_b(self):
a = Ellipse.from_center((100, 100), 100, 100)
a.fill_color = (0, 255, 0)
world.run()
Dieses Programm reagiert auf die Tasten a und b, beim Drücken der Taste a wird eine rote Ellipse gezeichnet, beim Drücken der Taste b eine grüne Ellipse.
Arbeiten mit dem Zufall#
Python stellt mit der random Bibliothek einige Möglichkeiten zur Verfügung, wie man interessante graphische Effekte erzeugen kann:
So wird z.B. ein Kreis in einer zufälligen Farbe erstellt:
from miniworlds import *
import random
world = World()
@world.register
def on_setup(self):
world.size = (200,200)
@world.register
def on_key_down_a(self):
a = Ellipse.from_center((100, 100), 100, 100)
a.fill_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
world.run()
Ausgabe: