Der prominenteste Fall von Koroutinen sind wahrscheinlich alte grafische Point & klicken Sie auf Adventure-Spiele, wo sie zum Erstellen von Zwischensequenzen und andere animierte Sequenzen im Spiel verwendet wurden. Ein einfacher Code-Beispiel würde wie folgt aussehen:
# script_file.scr
bob.walkto(jane)
bob.lookat(jane)
bob.say("How are you?")
wait(2)
jane.say("Fine")
...
Diese ganze Sequenz nicht als normaler Code geschrieben werden kann, wie Sie bob tun, um seine Wanderung Animation sehen möchten, nachdem Sie bob.walkto(jane)
statt springen direkt in die nächste Zeile tat . Für die Walk-Animation, die Sie spielen, müssen Sie jedoch die Kontrolle über die Game-Engine zurückgeben, und das ist der Punkt, an dem Korotinen ins Spiel kommen.
Diese ganze Sequenz wird als Coroutine ausgeführt, was bedeutet, dass Sie die Funktion beliebig anhalten und fortsetzen können.Ein Befehl wie bob.walkto(jane)
teilt dem motorseitigen Bob-Objekt sein Ziel mit und unterbricht dann die Coroutine und wartet auf einen Weckruf, wenn Bob sein Ziel erreicht hat.
auf der Motorseite Dinge könnte wie dieser (Pseudo-Code) aussehen:
class Script:
def __init__(self, filename):
self.coroutine = Coroutine(filename)
self.is_wokenup = True
def wakeup(self):
self.is_wokenup = False;
def update():
if self.is_wokenup:
coroutine.run()
class Character:
def walkto(self, target, script):
self.script = script
self.target = target
def update(self):
if target:
move_one_step_closer_to(self.target)
if close_enough_to(self.target):
self.script.wakeup()
self.target = None
self.script = None
objects = [Character("bob"), Character("jane")]
scripts = [Script("script_file.scr")]
while True:
for obj in objects:
obj.update()
for scr in scripts:
scr.update()
Ein litte Wort der Warnung jedoch während Koroutinen Codierung dieser Sequenzen sehr einfach zu machen, nicht alle Implementierungen Sie von ihnen finden wird Wenn Sie Serialisierung im Hinterkopf haben, wird das Speichern von Spielen zu einem ziemlich lästigen Problem, wenn Sie Coroutinen intensiv nutzen.
Dieses Beispiel ist auch nur der einfachste Fall einer Coroutine in einem Spiel, Coroutinen selbst können für viele andere Aufgaben und Algorithmen verwendet werden.
Coroutines haben einige Synchronisierungsprobleme, aber nur, wenn ihr Zustand zwischen yield() -Aufrufen nicht konsistent sein kann. Eine implizite Sperre für den gesamten Code zwischen yield() -Aufrufen kann die Dinge erheblich vereinfachen. Der größte Fehler ist, dass bei jeder Erstellung einer Routine entschieden werden sollte, ob die Routine immer abgeschlossen werden kann, bevor sie ausgeführt werden muss(). Wenn der Aufrufer einer Routine nicht erwartet, dass eine Routine Ergebnisse liefert, befinden sich die Objekte möglicherweise nicht in einem konsistenten Zustand, wenn die Routine aufgerufen wird. Das Hinzufügen einer Rendite() wäre eine bahnbrechende Änderung. – supercat
Das Problem ist, dass Sie in der Regel in der Lage sein können, für solche Routinen jeden Nutzen zu erbringen (wie in UnrealScript, wo "latente Funktionen" implizit ergeben), aber dies führt zu Kombinationen von Koroutinen, die auf unvorhersehbare Weise interagieren. z.B. Wenn man eine Patrouillen-Koroutine ist, die sagt: "Geh nach Norden; sieh nach; geh nach Süden; schau; wiederhole;" und die andere ist eine Reaktionsroutine, die sagt: "Wenn (Ton gehört in den Westen) {gehe nach Westen; schau; gehe nach Osten;}", dann könnte die Verschachtelung der beiden dazu führen, dass sich der Schauspieler eher unvorhersehbar bewegt. Deshalb erlaubt UnrealScript solche Funktionen nur in genau einer "Coroutine". – Kylotan
Und selbst wenn Sie nur 1 Koroutine pro Akteur haben, reicht das immer noch nicht aus, um sicherzustellen, dass die Logik immer auf der Sprachebene funktioniert: wenn Ihre Koroutine sagt: "Schwert ziehen; 1 Sekunde warten; Gegner mit Schwert angreifen" dann passiert, wenn das Schwert verschwindet, weil du von einem anderen Spieler entwaffnet wurdest? Insbesondere, wenn Ihre Sprache diese Coroutine implementiert, indem Sie eine lokale Variable für ein Schwert verwenden, das sich jetzt auf ein Null-Objekt bezieht? Es ist sehr schwierig, all diese Fälle zu berücksichtigen, wenn Sie eine allgemeine Sprache in der üblichen Weise verwenden. – Kylotan