Dieses Beispiel wurde in einer anderen Frage verwendet, um zu veranschaulichen, wie Korotinen zum Erstellen von Zwischensequenzen in einem Videospiel verwendet werden können:
%Vor%Jede Funktion liefert die Hauptmaschine, die Animation, Timing usw. vor der Wiederaufnahme der Coroutine ausführt. Eine mögliche Alternative zu Coroutinen wäre eine Ereigniswarteschlange anstelle von Code, aber dann muss man Steuerlogik und Schleifen als Ereignisse implementieren. Gibt es noch andere Alternativen zu Coroutinen, mit denen diese Art von Funktionalität implementiert werden kann? Ich habe in einigen Artikeln Callbacks gesehen, aber ich bin mir nicht sicher, wie der Code aussehen würde.
Koroutinen sind dafür gut geeignet, da Sie alle Ihre lokalen Statusvariablen mühelos verwalten können. I.e. ohne es irgendwo in einem Kontext manuell speichern zu müssen.
Aber ich sehe kein Event-System als Alternative. Mehr als eine Ergänzung, die Sie wahrscheinlich zusätzlich zu einem Coroutine-basierten Skript-System haben möchten.
Beispiel (in etwas kohärentem C ++):
Sie haben ein Verhalten implementiert, das Koroutinen in diesen Zeilen verwendet:
%Vor%Stellen Sie sich vor, dass die Methoden auf den NPCs selbst NPCBehavior-Objekte erstellen, sie auf eine Art Verhaltensstapel schieben und vom Aufruf zurückkommen, wenn diese Verhalten abgeschlossen sind.
Der Sleep(1.0f)
-Aufruf führt zu Ihrem Skript-Scheduler und ermöglicht das Ausführen anderer Skripts. Die WalkTo
, FaceObject
, PlayAnimation
und OpenDoor
rufen auch Sleep
auf, um zu liefern. Entweder basierend auf einer bekannten Animationsdauer, um regelmäßig zu wachen, um zu sehen, ob der Pfadfinder und das Fortbewegungssystem gehend laufen oder was auch immer.
Was passiert, wenn der NPC auf eine Situation trifft, mit der er auf dem Weg zur Tür zu tun haben wird? Sie möchten nicht alle diese Ereignisse überall in Ihrem Coroutine-basierten Code überprüfen müssen. Ein Event-System, das die Coroutines ergänzt, macht das einfach:
Ein Mülleimer kippt um : Der Mülleimer kann ein Ereignis an alle in der Nähe befindlichen NSCs senden. Das NPC-Objekt beschließt, ein neues Verhaltensobjekt auf seinen Stapel zu schieben, um es zu reparieren. Das WalkTo
Verhalten befindet sich irgendwo in einem ergebenden Sleep
Aufruf, aber jetzt läuft das FixTrashcan
Verhalten aufgrund des Ereignisses. Wenn FixTrashcan
abgeschlossen ist, wird das WalkTo
-Verhalten von Sleep
aktiviert und weiß nie etwas über den Mülleimer-Vorfall. Aber es wird immer noch auf dem Weg zur Tür sein, und darunter laufen wir immer noch EnterHouse
.
Eine Explosion passiert: Die Explosion überträgt ein Ereignis genau wie der Mülleimer, aber dieses Mal entscheidet das NPC-Objekt, das Verhalten zurückzusetzen und ein FleeInPanic
-Verhalten zu setzen. Er wird nicht zu EnterHouse
zurückkehren.
Ich hoffe, Sie sehen, was ich meine, wenn Ereignisse und Korotinen in einem KI-System zusammenleben. Sie können Coroutinen verwenden, um den lokalen Status beizubehalten, während Sie weiterhin Ihrem Skript-Scheduler nachgeben, und Sie können Ereignisse verwenden, um Unterbrechungen zu behandeln und die Logik zentral zu behandeln, ohne Ihr Verhalten zu belasten.
Wenn Sie diesen Artikel von Thomas Tong nicht bereits kennengelernt haben, wie Sie Single-Threaded implementieren können Korotinen in C / C ++ kann ich sehr empfehlen.
Er verwendet nur das kleinste bisschen Inline-Assembly (eine einzelne Anweisung), um den Stack-Pointer zu speichern, und der Code ist leicht auf eine ganze Reihe von Plattformen portierbar. Ich habe es auf Wintel, Xbox 360, PS3 und Wii laufen lassen.
Eine weitere nette Sache über das Scheduler / Skript-Setup ist, dass es trivial wird, Off-Screen- oder ferne AI-Charaktere / Script-Objekte zu verhungern, wenn Sie die Ressourcen für etwas anderes brauchen. Verbinden Sie es einfach mit einem Prioritätssystem in Ihrem Scheduler und Sie können loslegen.
Sie haben nicht erwähnt, welche Sprache Sie verwenden, also schreibe ich diese in Lua mit Objektorientierung von Mittelschicht - Ссылка (Haftungsausschluss: Ich bin ein Mittelständler)
Eine andere Möglichkeit wäre, Ihre Zwischensequenzen in "Aktionslisten" aufzuteilen. Dies wird wahrscheinlich besser mit Ihrem Code verschmelzen, wenn Sie bereits eine Spielschleife haben, die eine 'Update'-Methode für Objektlisten aufruft.
So:
%Vor% Aktionen würden ein Attribut status
mit drei möglichen Werten haben: 'new'
, 'running'
, 'finished'
. Alle "Aktionsklassen" wären Unterklassen von Action
, die die Methoden start
und stop
definieren und den Status standardmäßig auf 'new'
initialisieren würden. Es würde auch eine Standardmethode update
geben, die einen Fehler
Unterklassen der Aktion können diese Methoden verbessern und update
implementieren. Zum Beispiel, hier ist WaitAction
:
Der einzige fehlende Implementierungsteil ist CutScene. Ein CutScene wird hauptsächlich drei Dinge haben: * Eine Liste der auszuführenden Aktionen * Eine Referenz auf die aktuelle Aktion oder den Index dieser Aktion in der Aktionsliste * Eine Update-Methode wie die folgende:
%Vor% Bei dieser Struktur brauchen Sie nur Ihre Spielschleife, die helloJane:update(dt)
bei jeder Schleifeniteration aufruft. Und Sie beseitigen die Notwendigkeit von Korotinen.
Callbacks (C # -Stil-Pseudocode):
%Vor%Definitiv nicht der bequemste Weg.
Ein anderer Ansatz ist Futures (auch bekannt als Versprechen):
%Vor%Eine interessante Sprache, die man sich ansehen sollte, ist E - es hat eingebaute Unterstützung für Futures, mit einer besseren Syntax als oben.
>Tags und Links coroutine