Map Event Trigger

Einstiegsfragen, Mathematik, Physik, künstliche Intelligenz, Engine Design
Antworten
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Map Event Trigger

Beitrag von BeRsErKeR »

Hallo ich habe für mein RPG Projekt ein Map Event System entworfen. Dabei besteht ein Map Event aus 3 Teilen:

Bedingungen
Trigger
Aktionen


Die Bedingungen müssen erfüllt sein, damit ein Event ausgelöst werden kann. Z.B. das Erreichen eines Mindestlevels, der Wert einer Variable usw.

Die Aktionen führen etwas aus wie Spieler warpen, Variablenwert ändern usw.

Der Trigger löst das Event dann tatsächlich aus (sofern die Bedingungen erfüllt sind).

Nun das Problem. Es gibt folgende Trigger:

Enter Area (man betritt ein vordefiniertes Gebiet beliebiger Größe auf der Map)
Enter Tile (man betritt ein bestimmtes Tile)
Elapsed Time (die Zeit auf der Map ist größer-gleich einem bestimmten Wert)
Enter Map (man betritt eine bestimmte Map)
Other Event (ein anderes Event wurde gerade ausgeführt)

Es existiert nun ein MapEventManager welcher die MapEvents auslöst. Die Events prüfen dabei ob die Bedingungen erfüllt sind und ob der für sie nötige Trigger aktiv ist.

Meine Frage ist nun: Wie realisiere ich das Triggern?

Ich habe da 2 Ideen im Kopf:

1. Der EventManager holt sich permanent die Informationen über Maps, Spielerposition usw und generiert dadurch die Trigger.
2. Die betroffenen Objekte (z.B. die Map) prüft ihre Zeit und generiert den Trigger und leitet ihn an den EventManager weiter.


Bei 1. seh ich das Problem, dass der EventManager so ziemlich alles kennen muss und auf alles Zugriff braucht. Und es ist ziemlich schlecht erweiterbar wenn weitere Trigger hinzu kommen.

Bei 2. seh ich das Problem, dass die Map usw nicht wirklich wissen welche Triggereigenschaft die Events benötigen. Also ein Map weiß z.B. nicht dass ein Event existiert, welches einen ElapsedTime-Trigger von 5 Sekunden hat und muss daher ständig ElapsedTime-Trigger generieren, die meistens von den Events verworfen werden, da die Zeit noch nicht groß genug ist usw.


Habt ihr da Ideen/Vorschläge?
Ohne Input kein Output.
joeydee
Establishment
Beiträge: 1039
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Map Event Trigger

Beitrag von joeydee »

Schreit nach einem "richtigen" Eventsystem: http://de.wikipedia.org/wiki/Ereignis_(Programmierung)
Das verhindert in der Regel, dass jeder jeden kennen muss, und vor allem das neu-Kennenlernen bei Erweiterungen. Falls dir das nichts sagt:
Die Levelobjekte (Map, Spieler, Tiles, Areas,...) erben alle von einem "EventDispatcher", d.h. können Events verschiedener Typen feuern, und man kann jeweils mehrere Listener auf dieser Typen bei ihnen registrieren (ist kein Listener registriert, erübrigt sich natürlich auch das Feuern). An die Listener wird beim Feuern ein Datenobjekt mit den relevanten Informationen (z.B. wer, wo, wann) weitergegeben.

Dein Eventmanager muss so nicht alle Details kennen (nur was er bei wem "fragen" darf) und vor allem nicht ständig wachsam sein, und der Dispatcher muss jeweils nicht wissen was mit den Daten geschieht und an wen sie überhaupt gehen.
Durch genormte Schnittstellen und Vererbung kannst du das sehr flexibel auf neue Events von neuen Objekten erweitern.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

Der Vollständigkeit halber noch einen Link zum Listener- beziehungsweise Observer-Pattern und zum Functor
http://de.wikipedia.org/wiki/Observer_% ... smuster%29
http://www.newty.de/fpt/functor.html

Ich bevorzuge für Event-Handling den Functor, da man sich für die Callbacks das Ableiten von einer Observer / Listener-Klasse sparen kann. Der Observer muss immer von dem Observer-Interface erben, der Functor kann davon frei sein.

Gruß Kimmi
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Vielen Dank ersteinmal für die nützlichen Antworten. Allerdings bleibt dabei immer noch eine Frage offen. Sagen wir mal ich implementiere die Map als EventDispatcher (was ja Sinn macht). Woher weiß die Map wann sie Events auslösen soll? Ok bei manchen Events wie "Betrete Map" mag das ja recht einfach sein, aber bei "Elapsed Map Time" kann ich ja eigentlich nur ständig ein Event auslösen und nicht immer nur dann wenn es nötig ist. Prinzipiell ist "Elapsed Map Time" eigentlich das einzige Event was mir ein wenig Kopfschmerzen bereitet, da es zeitabhängig ist und nicht wie die anderen Events einen konkreten Auslöser hat.

Ich benutzte zur Zeit übrigens eine abgewandelte Version des Observer-Patterns. Allerdings gibt es nur einen Observer, der Events entgegennimmt und diese an die richtigen Stellen verteilt. Genauer löst z.B. der Spieler bei einer Bewegung ein Game-Event "PlayerMove" aus und sendet dies an einen GameManager (zentrales Objekt). Dieser generiert daraus z.B. ein MapEvent "Betrete Tile" und gibt es an den MapEventManager weiter. Beim Laden einer Map wird dann halt ein Event "Betrete Map" generiert usw.

Das Event "Elapsed Map Time" (welches mit dem Wert 0 übrigens einem "Always" entspricht), generiere ich zur Zeit in jedem Zyklus und gerade hier weiß ich nicht ob das eine tolle Lösung ist. Aber selbst mit dem Observer-Pattern oder einem ähnlichen Event-System müsste dieses Event ja irgendwann ausgelöst werden.
Ohne Input kein Output.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

Implementiere doch deine eigenen Event-Triggerer: Für einen Timeout beispielsweise zählst du die Game-Time bei jedem Frame-Update mit und triggerst dann deine Elapsed-Time-Message, wenn der Timer abgelaufen ist. Du musst halt nur gewährleisten, dass die konkreten Event-Implementierungen den gewünschten Callback bzw. das Notify-Signal auch erhalten.
Beispielsweise könnte sich ein Timer auf On-Frame-Update ( also für jeden neuen Frame ) updaten lassen, während andere Event-Triggerer das halt anders implementieren.
Und ich würde das Ganze als Model-View-Controller-Pattern implementieren.

Gruß Kimmi
joeydee
Establishment
Beiträge: 1039
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Map Event Trigger

Beitrag von joeydee »

Irgendwo musst du ja pro Frame/Sekunde/sonstwas eine Prüfung vornehmen. Am besten natürlich vor einem Listener-Aufruf, da hast du recht. Dann übergib doch bei einem neuen Listener auch den Zeitwert, der mit in die Queue der Listener in der Map geschrieben wird. Die Map testet alle an ihr registrierten TimeElapsed-Listener in einer Funktion (bzw. zählt jeden runter) und feuert den entsprechenden, wenn er abgelaufen ist.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Hmm also bräuchte die Map quasi noch eine Update oder Tick Funktion, die vom GameManager in jedem Durchlauf aufgerufen wird. Die Map speichert intern eh alle MapEvents. Das wäre eine Möglichkeit. Theoretisch könnte ich das ganze sogar in die Draw-Funktion der Map packen. Denn einige Events können auch visuelle Effekte hervorrufen oder Grafiken/Texte anzeigen. Daher müssen Events theoretisch eh immer im Draw-Zyklus ausgeführt werden.
Ohne Input kein Output.
nurF
Beiträge: 10
Registriert: 26.02.2010, 15:28
Kontaktdaten:

Re: Map Event Trigger

Beitrag von nurF »

joeydee hat geschrieben:Schreit nach einem "richtigen" Eventsystem: http://de.wikipedia.org/wiki/Ereignis_(Programmierung)
Ja !
joeydee hat geschrieben: Die Levelobjekte (Map, Spieler, Tiles, Areas,...) erben alle von einem "EventDispatcher", d.h. können Events verschiedener Typen feuern.
Nein ! - Das würde ich generell nicht machen, denn das ist schon spezifisches Implementierungsdetail.
Man muss nicht unbedingt vom Dispatcher erben, nur um Events zu feuern.
Dafür reicht auch der Aufruf einer statischen Funktion oder sowas boost::signal.

Viel wichtiger ist doch der architekturelle Gedanke bei dem Konzept. Wenn sich etwas ändert, werden andere darüber informiert.
Das Ziel einer eventbasierten Architektor sollte also sein jegliches Polling aus dem Programm zu verbannen.
Coder-Lead von USP
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

nurF hat geschrieben: ...
Viel wichtiger ist doch der architekturelle Gedanke bei dem Konzept. Wenn sich etwas ändert, werden andere darüber informiert.
Das Ziel einer eventbasierten Architektor sollte also sein jegliches Polling aus dem Programm zu verbannen.
Daher MVC-Pattern :)...

Gruß Kimmi
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Ok nun mal der Stand:

Maps besitzen eine Update-Methode, die in jedem Zyklus aufgerufen wird. Dabei geht die Map alle MapEvents durch und sucht jene heraus, die einen "Elapsed Map Time"-Trigger besitzen. Ist die MapTime größer als der Wert des Triggers so wird ein Event (kein MapEvent) generiert. Die Events gehen immer zuerst an den GameManager (quasi ein zentraler Observer/Listener). Dieser generiert MapEventTrigger-Events (tolles Wort :D ), die er an den MapEvent-Manager weitergibt. Dieses Event-Umwandeln mag zwar nach Overhead klingen aber es hat einen Grund:

Der GameManager erhält die Events zu allen möglichen Zeiten. Die Ausführung von MapEvents muss jedoch im Draw-Cycle aufgerufen werden, da Events auch Dinge anzeigen können. Daher legt der GameManager zunächst eine Liste aller eingetroffenen Events an und dispatcht diese in der Draw-Methode an den MapEventManager, welcher dann die MapEvents ausführt. Danach wird die Liste gelöscht.


Ich komme nun aber zu einer weiteren Frage. Ein "ElapsedTime >= xxx ms"-Trigger ist ja quasi dauerhaft aktiv, wenn die gegebene Zeit überschritten wurde. In der Regel soll ein MapEvent aber nur beim Überschreiten der Zeitmarke ausgeführt werden. Das MapEvent selber wird zwar nur einmal ausgeführt, allerdings wird das TriggerEvent von der Map permanent in der Update-Funktion generiert, sofern die Zeit überschritten wurde. Ein '==' anstelle eines '>=' würde dieses Problem zwar lösen, aber auf exakte Millisekunden zu prüfen halte ich doch für sehr gefährlich. Ein bool-Flag, ob das Event schon einmal ausgeführt wurde, könnte helfen, allerdings können bestimmte MapEvents auch mehrfach ausgeführt werden. Genauer bestimmen dies eigentlich die Conditions/Bedingungen und nicht die Trigger. Da muss ich mir nochwas überlegen.


Aber ich danke schonmal allen für die bisherige Hilfe. Hat mir schon sehr geholfen.
Ohne Input kein Output.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

Wie wäre es, wenn du den Elapsed-Time-Triggerer einfach nach Ablauf des TimeOuts inaktiv schaltest. Zum Beispiel könntest du ihn releasen, inaktiv schalten, auf eine Freelist zwischenparken etc. . Dazu würde ich die Suche über alle Map-Events vermeiden. Statt dessen könntest du dir einen Timer implementieren, der das macht. Loops über alles, um nach aktiven Membern zu suchen, ist irgendwann gern einmal ein Flaschenhals.

Gruß Kimmi
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Gute Idee. Ich hab mir eine Timer-Klasse gebaut, die man auch Deaktivieren kann und die nach Zeitablauf einen übergebenen Functor aufruft. Werd es nachher mal testen.
Ohne Input kein Output.
nurF
Beiträge: 10
Registriert: 26.02.2010, 15:28
Kontaktdaten:

Re: Map Event Trigger

Beitrag von nurF »

BeRsErKeR hat geschrieben:Dabei geht die Map alle MapEvents durch und sucht jene heraus, die einen "Elapsed Map Time"-Trigger besitzen.
Hört sich mir glatt nach einem Priority Queue an. Dann muss man auch nicht über alle iterieren.
Coder-Lead von USP
joeydee
Establishment
Beiträge: 1039
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Map Event Trigger

Beitrag von joeydee »

Ich hätte jetzt je Typ einfach eine eigene Liste gemacht, also im einfachsten Sinne nach der Art events[ELAPSED_TIME]=Array() - dann ist da null Overhead beim Durchgehen.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Ich habe der Map eine Liste aus TriggerTimern hinzugefügt. Die Timer werden beim Betreten der Map gestartet und erhalten in jedem Ablaufzyklus ein Tick. Dabei prüfen sie, ob ihre Zeit abgelaufen ist und rufen daraufhin einen Functor auf (außerdem deaktivieren sie sich danach). Beim Laden der Map und somit der Events werden die Timer angelegt und in eine Liste gepackt. Dabei wird ihnen ein Functor übergeben welcher intern ein TimeElapsed-Event auslöst und an den GameManager schickt. Dieser generiert daraus das entsprechende MapEvent für den MapEventManager. Ich muss nun zwar in der Update-Funktion alle Timer durchgehen um ihnen ein Tick zu schicken, aber es wird weit weniger ElapsedTime-Events geben als MapEvents an sich (vielleicht mal so 5). Und Timer müssen eh irgendwoher ihre Informationen bekommen bzw. ein Update/Tick erhalten (wenn man eine multithreaded Architektur vermeiden will, was ich tue).

Allerdings überlege ich tatsächliche eine Priority-Queue zu nutzen und dem Tick einen Rückgabewert mitzugeben, welcher aussagt ob der Timer ausgelöst wurde. Somit könnte ich ab einem nicht-ausgelösten Timer die restliche Iteration beenden.
Ohne Input kein Output.
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Ein weiteres Problem hat sich nun ergeben. Wie bereits erwähnt ist es von den Bedingungen abhängig ob ein Event ausgelöst werden kann. Nehmen wir nun mal das Beispiel "Elapsed-Time-Trigger" oder meinetwegen auch "Always-Trigger". Der Trigger wird nun ausgelöst, aber die Bedingungen sind noch nicht erfüllt. Ein paar Sekunden später ist die Bedingung jedoch erfüllt (z.B. wurde eine Variable auf den nötigen Wert gesetzt oder ein Spieler hatte ein Level-Up). Der Trigger wurde aber bereits ausgelöst und somit kann das Event nie wieder ausgelöst werden, was aber erwünscht ist, denn der "Elapsed-Time-Trigger" oder auch der "Always-Trigger" behalten ihre Gültigkeit.

Wie könnte ich das eventuell realisieren? Ich dachte schon an ein "Condition-Change"-Event, was dann nochmals die Timer abfragt. Allerdings werden die Bedingungen nur dann geprüft wenn ein Trigger aktiviert wurde. Ein Teufelskreis.

Eine andere Idee war, die Trigger in der Liste zu lassen, bis wirklich ein Event ausgelöst wurde und sie in jedem Zyklus erneut an den EventManager schicken. Dabei ergeben sich aber auch 2 Probleme:

Ein Trigger könnte mehr als eins oder sogar gar kein Event auslösen und wäre somit immer in der Liste oder würde zu früh gelöscht.


Edit:

Meine momentane Lösung:

Beim Ausführen aller Events guckt der EventManager im Normalfall ob die Bedingungen für ein Event erfüllt sind und führt das Event dann aus. Das Event prüft ob der Trigger aktiv ist und führt seinerseits dann die Aktionen aus. Stellt der EventManager fest, dass die Bedingungen nicht erfüllt sind, aber es sich um ein ElapsedTimeTrigger-Event handelt so fügt er den Trigger erneut der Liste der aktiven Trigger hinzu. Dies geschieht natürlich nur einmalig für alle Events, sofern mindestens ein Event diese Voraussetzungen erfüllt.
Ohne Input kein Output.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

Du könntest natürlich auch einfach States einfügen, die dann im Zustandswechsel Events triggern: http://en.wikipedia.org/wiki/Finite-state_machine . Diese Pattern leistet meiner Ansicht nach genau das, was du benötigst.

Gruß Kimmi
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4254
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Map Event Trigger

Beitrag von Chromanoid »

Nimm doch Zeit-Trigger als ganz normale Bedingungen in eine Liste von Bedingungen pro Trigger auf. Wenn du trotzdem nach Zeit sortieren möchtest damit du nicht alle Trigger jedes update testen musst, könntest du einfach eine zweite Liste haben, die Trigger enthält, die keine Zeit für ihre Bedingungen benötigen oder die jedes update geprüft werden müssen.
Also sobald die Zeitbedingung mit OR in der Trigger-Bedingung steht, die Aktivierungszeit abgelaufen ist oder keine Zeitbedingung vorhanden ist, kommen die Trigger in die Liste, die jedes Update einmal durchgeschaut wird. Alle anderen Trigger, die die Zeitbedingung mit AND in der Bedingung haben, werden in die Liste gepackt, die nach Triggerzeiten sortiert wird.

Einen endlicher Automat ist IMO auch keine schlechte Sache. Ich hab mal ein Tasten-Kombo-System mit einem endlichen Automaten gebaut. Das hat echt gut funktioniert. Jeder Zustand hat Transitionen, für jede Transition kann man eine Aktivierungszeit und eine Deaktivierungszeit angeben. Der Zeitwert mit dem die De-/Aktivierungszeiten geprüft werden ist die Anzahl der Millisekunden in denen sich das System im jew. Zustand befindet. Nach einem Zustandswechsel wird der Wert also zunächst 0 sein und dann nach jedem update hochzählen. Events des Keyboards werden als einfache Strings übergeben - für das loslassen der Pfeiltaste zum Beispiel "LEFTup". Jede Transition hat einen String der mit dem übergebenen String übereinstimmen muss, damit die Transition den Zustandswechsel auslösen kann (wenn sie durch die Zeitbegrenzung überhaupt aktiviert ist).
Du solltest natürlich noch abstrahieren, so dass es einfach Transitionen (~=Trigger) gibt, die einen Zustandswechsel auslösen, wenn eine Menge von mit OR oder AND verknüpften Bedingungen wahr sind. Eine allgemeine Bedingung könnte dann sein: WAHR, wenn ein bestimmter Wert zwischen einem Minimal- und einem Maximalwert ist - am besten wäre eine Transition die Gleichungssysteme verarbeiten kann. In einer GUI kann man dort dann zum Beispiel die Zeit anschließen oder die X-Koordinate des Spielers etc. Kompliziertere Triggerabhängigkeiten würdest du so in den Griff bekommen, weil der Zustand des Systems die Anzahl der Trigger begrenzt. Es kann natürlich mehrere Zustandsysteme pro Spiel geben. Außerdem gibt es Error und Exit Zustände mit denen man das Zustandssystem aus der Systemliste entfernen kann und Fehler loggt.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Map Event Trigger

Beitrag von kimmi »

Mach es vor allem nicht zu kompliziert. Den eigenen Code noch zu verstehen ist ebenfalls hilfreich :).

Gruß Kimmi
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Events können definitiv nur einen Auslöser haben, daher fallen OR-Verknüpfungen und dergleichen weg. Dazu gibt es separat ja die Bedingungen, welche verknüpft werden können. Zustandsautomaten sind sicher sehr mächtig, aber für meine bescheidenen Zwecke doch ein wenig zu aufwendig.

Derzeit habe ich eine kleine Unsauberkeit in Hinsicht auf Erweiterbarkeit begangen, indem ich Elapsed-Time-Triggern eine Art manuellen Sonderstatus hab zukommen lassen. Für diese Art von Trigger generiert die Map nämlich Timer, die das Trigger-Event nach Ablauf auslösen. Alle anderen Trigger werden über Game-Events wie "PlayerMove" (-> EnterTile, -> EnterArea), "LoadMap" (-> Enter Map) und dergleichen generiert.

Wenn ein Timer eine Elapsed-Time-Trigger-Event auslöst prüft der Event-Manager zudem ob alle Events, die diesen Trigger erwarten, ausgeführt werden können (abhängig von deren Bedingungen). Falls mindestens 1 Event existiert für das dies nicht der Fall ist, generiert der EventManager das Trigger-Event erneut. Da es letztlich wieder beim EventManager ankommt ergibt sich somit ein Kreislauf und solche Trigger werden dann zyklisch generiert, bis alle Events ausgelöst wurden. Ich generiere also doch zyklisch die Trigger, allerdings erst ab dem Zeitpunkt, ab dem sie erstmalig durch den Timer ausgelöst wurden.

Vielleicht nicht die schönste Lösung und auch sicher nicht uneingeschränkt erweiterbar, aber ich denke für meine Zwecke ist das ganze ausreichend.

Dazu habe ich die Timer in eine Priority-Queue gepackt und breche die Prüfungs-Iteration bzw. die Timer-Tick-Iteration ab, sofern ein Timer erkannt wird, der noch nicht abgelaufen ist.
Ohne Input kein Output.
Jaw
Beiträge: 54
Registriert: 14.07.2004, 01:00
Wohnort: Raum Düsseldorf

Re: Map Event Trigger

Beitrag von Jaw »

Ich komm von dem Gefühl nicht los, dass sich das irgendwie zu kompliziert anhört. Vielleicht versteh ich was falsch, oder vielleicht fehlen mit Details über dein System. oder ggf. hast du dich in einen unnötig schweren Denkansatz manövriert und findest keine Alternative aus nem ganz anderen Blickwinkel.

Zu den Events ganz allgemein wären mir zwei Dinge eingefallen:
1) Entweder hat jeder Event (Oder Gruppe von kombinierten Bedingungen) eine Art "prüfe" Funktion die man jedes Mal aufruft, oder angemessen oft, und die für sich in den Daten prüft, ob sie gerade erfüllt ist. Dann triggert sie.
2) Oder jeder dieser Events meldet sich an allen relevanten Teilen wie Tiles oder der Uhr als Listener an. Alternativ könnten sich die regionalen Events auch an der Spielfigur anmelden. Und erfahren da z.B. jedes Mal, wenn die Figur ihre Position ändert und können dann prüfen, ob die Position jetzt ihre Bedingung erfüllt. Die Uhr würde sich jeden Tick melden und der Event könnte dann auf sein Limit prüfen.

Was das triggern angeht: Ich würde normalerweise von ein Mal Ereignissen ausgehen, d.h. wenn alle Bedingungen zutreffen wird der Trigger ausgelöst und das ganze Event Trigger Ding danach inaktiv oder komplett entfernt. Meistens ist auch nur das sinnvoll. Zeitliche Trigger gibts eh nur ein Mal, es sei denn man baut einen "jede Minute" oder so etwas. Der könnte dann mit jedem Feuern die nächste Zeit bestimmten zu der er wieder feuert. Ein Area Trigger wird doch oft auch nur einmal benutzt, dann läuft etwas ab, und fertig.

Wenn es keine einmal Trigger sein sollen, hast du die Möglichkeit, sie jede Runde zu prüfen und zu feuern. Dann muss die Logik, die dann angestossen ist, das verarbeiten. Sagen wir mal es gäbe ein Tile mit einem Schalter und wenn die Figur da steht geht ein Licht an. Jeden Game Loop wäre der Event erfüllt, solange der Spieler da steht, und jedes Mal gäbe es den Trigger "Licht an". Die Logik müsste daraus machen "wenn es nicht schon an ist".

Alternativ dazu hat jeder Trigger eine "reset" Bedingung. Wenn alle "set" oder "fire" Bedingungen erfüllt sind, löst er seinen Trigger einmalig aus und ist dann im Zustand aktiviert. Dann gibt es andere Bedingungen, wie z.B: Figur verlässt den Bereich wieder, die für einen "reset" erfüllt sein müssen. Erst dann geht die Sache in den Zustand "auslösbar".


Das wären jetzt meine spontanen Konzepte zu einem Game Event System. Ich erhebe keinen Anspruch darauf, dass es richtig, sinnvoll oder gut ist.

Grüße
JAW
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: Map Event Trigger

Beitrag von BeRsErKeR »

Die "Prüfe"-Funktion gibt es für die Bedingungen eines Events. Für Trigger will ich aber gerade vermeiden, dass ich da permanent prüfen muss, ob sie ausgelöst wurden. Es soll halt event-basiert sein. Natürlich kommt man bei Timern nicht wirklich drum rum da zyklisch zu prüfen ob die Zeit abgelaufen ist. Das mit dem Listener mache ich ja nun quasi, nur dass ich halt nicht direkt bei Map und Spieler anfrage, sondern beim GameManager, der die aktuelle Map und den Spieler verwaltet. Diese wiederrum lösen GameEvents aus (eine Spielerbewegung bzw ein Mapwechsel muss ja eh erfasst werden). Der GameManager benachrichtigt bei GameEvents, die auch als MapEvent-Trigger fungieren können, den MapEvent-Manager, welcher dann die entsprechenden MapEvents triggert. Ich habe also quasi noch 2 Zwischenebenen durch die beiden Manager drin. Das finde ich in gewisser Weise sinnvoll, da z.B. nur der GameManager weiß, welche Map gerade aktiv ist.

Trigger sind in der Tat "Einmal-Ereignisse". Das ist ja gerade das Problem. Wenn der Trigger einmalig ausgelöst wird, aber die Bedingungen noch nicht erfüllt sind, würde das Event nie ausgelöst werden, obwohl vielleicht zu einem späteren Zeitpunkt das Event gültig wäre.

Ein Beispiel dazu: Der Spieler betritt ein Haus (Map). Dieses ist anfangs leer und erst nach einer beendeten Quest steht ein NPC im Raum, der einen anspricht sobald man den Raum betritt. Wenn das Event nur einmal ausgelöst werden würde, kann es passieren, dass einen der NPC nie anspricht, weil man schon im Haus war, als die Quest noch nicht abgeschlossen wurde. Man darf die Events also nur löschen/deaktivieren, wenn sie auch wirklich ausgelöst wurden. Ich denke mal, so meintest du das auch. Aber ich sehe das halt in Hinblick auf "Einmal"-Trigger. Das würde dann halt nicht gehen. Einmal-Event: ja, Einmal-Trigger: nein.

Es gibt aber auch Fälle, in denen auch Events nicht nur einmalig auftreten sollten. Z.B. wenn jedesmal sobald eine Map betreten wird ein Gesprächsfenster aufgehen soll oder ähnliches. Aber das ist ein anderes Problem. Dafür gibt es die Bedingung "First Execution", die aussagt, dass das Event nur einmal auftritt.

Das mit dem "Wenn das Licht schon an ist" muss halt durch den Event-Designer realisiert werden. In der Regel nutze ich dafür Variablen, die ich in den Event-Aktionen setze und durch die Event-Bedingungen prüfe.

Z.B. Bedingung: LightVar == 0, Aktion: SetVar(LightVar, 1);

Das mit dem Reset ist sicher eine gute Idee, aber auch das löse ich durch Variablen. Man kann diese ja dann wieder auf den Anfangswert zurücksetzen durch ein anderes Event etc.


Ich danke dir aber für deine Ideen. Es ist immer gut mehrere Sicht- und Heransgehensweisen zu sehen.
Ohne Input kein Output.
Antworten