Hi,
für meinen 2D Dungeoncrawler habe ich ein Entity-Component-System implementiert und lasse die Systeme über Events miteinander kommunizieren. So sendet das InputSystem ein InputEvent (ObjektID, Bewegungsrichtung) an das ActionSystem. Das ActionSystem prüft ob die Bewegung möglich ist (ggf. ist der Spieler gelähmt, tot oder schlimmeres
). Dann geht das Event weiter an's MovementSystem, wo die eigentliche Bewegung initiiert wird. Da geht ein MoveEvent raus und wird vom CollisionSystem weiterverarbeitet. Das prüft ob es zu einer Kollision kommt. Wenn ja sendet es (an verschiedene Systeme) ein CollisionEvent. Dann weiß das MovementSystem z.B. dass es das Objekt zurücksetzen und die Bewegung beenden soll. Ansonsten geht vom CollisionSystem ein MoveEvent (im Stile "Tile was Left") raus um verschiedene andere Sachen darüber zu informieren.
Ähnlich laufen bei mir Kampfberechnungen: Wenn der Spieler die Attack-Taste drückt geht ein ActionEvent (ObjektID, AktionsID -- d.h. Attack) vom Input- ans ActionSystem. Darf der Spieler angreifen wird ein AnimationEvent ausgelöst und das ActionEvent verzögert an das CombatSystem weitergeleitet (damit der Schaden berechnet wird wenn die Animation weit genug fortgeschritten ist). Ich denke wie es weiterläuft könnt ihr erahnen ... da gibt es noch DamageEvents, ExperienceEvents etc. pp.
Inzwischen bin ich an einer Stelle angelangt wo ich die verschiedenen Systeme in eine großen Topf werfe und der Gameloop seine Arbeit vollbringt. Dazu muss ich jedoch die Systeme miteinander verbinden.
Jedes System dass ein Event Foo sendet, erbt von einem entsprechenden Listener (analog für das Senden). D.h. ich kann z.B. das MovementSystem als InputListener (Bewegungseingabe), CollisionListener (weil es auf CollisionEvents vom CollisionSystem hört) und als MoveSender (klar
) auffassen. FooListener und FooSender können miteinander verbunden werden, so dass der Sender an den Listener sendet. Allerdings wird das Verbinden ziemlich laang und groß. Hier ein Ausschnitt:
|
C-/C++-Quelltext
|
1
2
3
4
5
|
animation.bind<AnimationEvent>(action); // ActionSystem blockiert Ausführung von Aktionen bis zum nächsten Idle
action.bind<AnimationEvent>(animation); // ActionSystem löst die FrameAnimations aus
item.bind<AnimationEvent>(animation); // (*)
perk.bind<AnimationEvent>(animation); // (*)
animation.bind<AnimationEvent>(ai); // KI benachrichtigen --> onIdle()
|
(*) Items und Perks (verwende ich als Oberbegriff für Zauber und Fertigkeiten) lösen Animationen aus, aber erst wenn sie durch das Item- bzw. PerkSystem "durchgingen". So wird z.B. bei NotEnoughMana keine Zauberanimation ausgelöst - oder ein nicht vorhandener Trank löst keine Trink-Animation aus etc.
Hier noch ein Beispiel:
|
C-/C++-Quelltext
|
1
2
3
4
|
collision.bind<CollisionEvent>(movement); // Unterbrechen der Bewegung
collision.bind<CollisionEvent>(action); // (**)
collision.bind<CollisionEvent>(projectile); // (***)
collision.bind<CollisionEvent>(ai); // KI benachrichten --> onCollision() --> z.B. neuen Pfad suchen
|
(**) Das ActionSystem löst auch Bewegungsanimationen aus. Im Falle einer Kollision wird es informiert, dass die Bewegung abbricht.
(***) Kollisionserkennung (CollisionSystem) und -behandlung (ProjectileSystem, lässt Geschosse explodieren und den Kampf auslösen) sind getrennt.
Ich denke ihr erahnt wie das insgesamt aussieht .. übersichtlich ist anders! Zwecks Übersichtlichkeit habe ich schon versucht das ganze in Diagrammform zu packen. Aber da sind zu viele Kanten (Eventverbindungen zwischen Systemen) drinnen, als dass das übersichtlich wird.
Hat jemand Erfahrungen wie ich hier die Übersicht behalte? Ich habe zu jedem System dokumentiert welche Events woher kommen bzw. wohin gehen sollten und was sie ausdrücken.. aber dennoch fühle ich mich .. nicht verirrt, aber viel fehlt nicht
LG Glocke