Brain of teh Zwarm

Aus BP Wiki
Version vom 1. November 2014, 19:06 Uhr von RCL (Diskussion | Beiträge) (Ursprüngliche Idee: Bildgröße)
Wechseln zu: Navigation, Suche
Brain of teh Zwarm
BotZ IdeeNeu.png
Entwickler
Spiel-Engine Unity
Genre(s) Side-Scroller
Spielmodi Einzelspieler
Steuerung Maus und Tastatur
BotZ Internetseite

Brain of teh Zwarm[sic] ist ein 2D-Videospiel, das im Wintersemester 2013/14 im Rahmen des Moduls Mediengestaltung 1 des Studiengangs Media Systems des Department Medientechnik der Fakultät Design, Medien und Information der Hochschule für Angewandte Wissenschaften Hamburg entwickelt wird.

Idee

Das Ziel dieses MG1-Projekt ist es, ein 2D-Side-Scroller-Zombie-Spiel zu entwickeln. Der Spieler steuert einen einzelnen Zombie, der konstant eine Straße entlang geht (entlang der Bildschirmbreite, von links nach rechts) und sich dabei auf der Straße nach links und rechts bewegt (entlang der Bildschirmhöhe, nach oben und unten).

Auf der Straße jagt der vom Spieler gesteuerte Zombie Menschen, die versuchen, vor ihm wegzulaufen. Sollte er einen Menschen einfangen, hält er kurz an um sein Gehirn einzusammeln und läuft dann weiter. Gehirne sind die Währung des Spieles, aus ihr ergibt sich der Highscore und sie lassen sich einsetzen zum Forschen/Evolvieren/Mutieren.

Im Laufe des Spieles trifft man auf andere Zombies, die man einsammeln kann und die sich dann dem Spieler-Zombie anschließen. Alternativ haben eingefangene Menschen auch eine geringe Wahrscheinlichkeit zu Zombies zu werden und sich anzuschließen. Diese etwa vier bis sechs zusätzlichen Zombies folgen dem Zombie, der vom Spieler gesteuert wird, und erhöhen dessen Aktionsreichweite. Entweder sie werden zu einem festen Teil der Gruppe (Offset Pursuit) oder sie schließen sich nur lose an (Flocking) und lassen sich z.B. durch Hindernisse wieder verlieren. Vielleicht auch eine Mischung aus beiden, dass man eine feste Gruppe hat und sich zusätzlich lose Zombies für einen limitierten Zeitraum anschließen können. Fängt die Zombie-Gruppe einen Menschen, hält nicht die ganze Gruppe an um das Gehirn einzusammeln, sondern nur ein einzelner Zombie.

Das Spiel ist ein Endlosspiel und die gesamte Spielwelt soll zufällig und dynamisch generiert werden. Dazu werden mehrere Musterblöcke erstellt, von denen zufällig inkrementell einer an das Level hinten angehängt wird, wenn der Spieler sich dem momentanen Ende nähert - bereits durchquerte Gebiete werden zerstört um Systemressourcen freizugeben. Durch alle Musterblöcke verläuft die Straße, sie können z.B. sein: Wohngebiete mit mehreren verriegelten Häusern, Straßenkreuzungen, Waldgebiete, Tankstationen, Wüsten/Ödland oder Brücken über Flüsse. Damit der Spieler nicht immer wieder dieselben Musterblöcke sieht, besteht jeder Block selbst aus zufälligen Bestandteilen (Hindernissen, Verkehrsschildern, Menschen, Zombies).

Ein Beispiel dafür wären Wohnhäuser, die zufällig da sind oder nicht, und zufällig mit Brettern versperrt sind oder nicht. Ist ein Haus nicht versperrt, kann es zufällig offen (Menschen können hinein und fliehen), verschlossen (nichts passiert) oder geschlossen (ein Zombie oder Mensch kommt beim Näherkommen heraus) sein.

Um das Spiel für den Spieler herausfordernd zu gestalten, trifft der Spieler auch auf bewaffnete Menschen die versuchen ihn und seinen Zombie-Schwarm aufzuhalten, wenn sie nicht schnell überrannt werden.

Kampfablauf

Einfach nur in konstanter Geschwindigkeit vorwärts laufen und sich auf der Straße nur nach rechts und links bewegen können ist langweilig. Es führt auch kaum zum Erfolg, bei Menschen die versuchen vor einem wegzulaufen, und dabei auch noch schneller, intelligenter und besser ausgerüstet sind als die eigenen Zombies.

Deshalb sollen Menschen im Normalfall etwas langsamer als Zombies gehen. Erst wenn die Zombies ihnen zu nahe kommen beginnen Menschen wegzurennen. Nach kurzer Zeit haben sie allerdings keine Ausdauer mehr und können von den Zombies eingeholt werden.

Der Spieler hat die Möglichkeit Kampfschreie beim Zombie-Anführer auszulösen. Diese Fähigkeiten erhöhen für kurze Zeit z.B. Geschwindigkeit, Widerstandsfähigkeit gegen Schüsse oder Lebensregeneration der Gruppe. Auch denkbar sind negative Effekte, die auf Menschen in einem per Maus auswählbaren Zielbereich gewirkt werden. Alle Fähigkeiten haben eine Abklingzeit, d.h., es muss erst eine gewisse Zeit vergehen, bis eine Fähigkeit erneut gewirkt werden kann. Besonders starke Fähigkeiten sollen Ressourcen (1-2 Gehirne) zum Einsetzen kosten.

Upgrades / Forschung / Mutation

Upgrades kosten Gehirne um sie entwickeln zu können und sind nicht sofort verfügbar, sondern erst nach einer gewissen Entwicklungszeit. Jedes Upgrade lässt sich in mehrere Stufen bis zu einer Maximalstufe entwickeln. Die Stufen werden immer teurer und benötigen immer mehr Zeit. Es kann immer nur ein Upgrade gleichzeitig entwickelt werden.

  • neue Fähigkeiten erwerben
  • Abklingzeiten von Fähigkeiten verringern
  • Wirkungsdauer von Fähigkeiten erhöhen
  • Gehgeschwindigkeit erhöhen
  • Widerstandsfähigkeit erhöhen (weniger Schaden erhalten)
  • Trefferpunkte erhöhen
  • Regeneration von Trefferpunkten erhöhen
  • Wahrscheinlichkeit erhöhen in einem Menschen mehr als ein Gehirn zu finden (z.B. im Magen der Person)
  • Stolperwahrscheinlichkeit am Kantstein verringern

Grafik

Abb. 1: ein einzelner Zombie
Abb. 2: Zombie mit schwarzem Hut

Das Spiel soll eine Strichmännchen-Grafik haben, das heißt, dass die Figuren nur aus einfachen Linien bestehen und Gebäude, Hindernisse und Objekte nur aus durch ihre Konturen erkennbar sind.

Farblich soll das Spiel fast ausschließlich Schwarz und Weiß sein. Farbe wird, wenn überhaupt, nur in Ausnahmefällen eingesetzt (um z.B. den Spieler-Zombie von anderen Zombies zu unterscheiden, oder etwas Blut an den Zombies um sie von Menschen besser unterscheiden zu können).

Das dies nicht schlecht aussehen muss lässt sich gut an Zombies im Webcomic xkcd von Randall Munroe erkennen, an denen sich orientiert werden soll:

Aufgrund der Simplizität der Figuren bieten sich eigentlich einfache 3D-Modelle für die Strichmännchen an, da sich diese wesentlich einfacher animieren lassen als 2D-Zeichnungen. Dafür ist es aber schwieriger Details unterzubringen, der Kopf darf beim 3D-Modell z.B. nicht oval sein, da man die Kontur nicht unterbringen könnte. Denkbar: Nur den Körper in 3D animieren, um daraus 2D-Grafiken zu generieren.

Sound

Für die typischen Zombie-Geräusche (stöhnen, seufzen, ächzen, murren, jauchzen, usw.) werden idealerweise mehrere Sprecher verwendet, die selbstverständlich in den Credits aufgelistet werden würden. Dabei sollte der jeweilige Sprecher versuchen jedes Geräusch in unterschiedlichen Tonhöhen zu erzeugen. Aus der Menge aller Audioclips werden im Spiel dann zufällig welche ausgewählt und abgespielt.

Mit genügend Audioclips in vielen verschiedenen Tonhöhen zur Auswahl könnte man einen Soundtrack komponieren oder eine bekannte Melodie nachspielen. Dies wäre dann in den Credits und vielleicht auch während des Spieles zu hören.

Ursprüngliche Idee

Abb. 3: Erste Whiteboard-Spielidee zu Brain of teh Zwarm

Die ursprüngliche Idee aus dem Wintersemester 2012/13 war es einen Menschen zu spielen, der vor einer Masse von Zombies davonläuft. Am linkem Bildschirmrand hätte sich eine unaufhaltbare Wand aus Zombies befunden, die den Spieler die Straße entlang jagt. Der Spieler wäre immer weiter die Straße entlang gegangen und hätte Streunern (zufällig vor ihm auftauchende Zombies) ausweichen oder mit Waffengewalt ausschalten müssen.

Dies wurde hauptsächlich deshalb verworfen, weil von dieser Art Spiele unzählig viele existieren, wohingegen Spiele, in denen der Spieler die Kontrolle von Zombies übernimmt, selten sind (siehe Recherche).

Recherche: Ähnliche Spiele

Gegenstand dieser Recherche sind Zombie-Spiele, die auf den Internetseiten zombiegames.net (310 Spiele) und addictinggames.com (103 Spiele) vom Internet-Browser aus zu spielen sind. Die Recherche beschränkt sich auf den Zeitraum vom 26. bis 29.09.2013, in dem sich insgesamt - unter Berücksichtigung von 26 doppelten Spielen (die auf beiden Seiten angeboten werden) - etwa 387 Zombie-Spiele auf den Seiten befanden.

Von diesen 387 Spielen übernimmt man in lediglich 19 Spielen (4,9%) die Kontrolle über Zombies (Kategorie 1). In weiteren 8 Spielen (2,1%) hilft man entweder den Zombies direkt oder steht ihnen zumindest nicht feindlich gegenüber (Kategorie 2).

Zombie Spiele mit Strichmännchen-Grafik sind noch seltener. In lediglich 5 Spielen (1,3%) macht man als menschliche Strichmännchenzeichnung Jagd auf Zombies (Kategorie 3), in keinem einzigen Spiel steuert man einen Zombie.

Kategorie 1: Zombies steuern

Das Spielprinzip von Zombie Horde stimmt am meisten mit dem von diesem überein. Die Kamera ist in der richtigen Perspektive, die Bewegung nach oben und unten ist wie gedacht, und der Spieler-Zombie wird von mehreren kleineren verfolgt. Die Story ist hingegen eine andere, statt Menschen inmitten des Ausbruches der Zombie-Apocalypse zu jagen, werden die Menschen getötet um sie vom eigenen Friedhof zu vertreiben. Der Friedhof besteht aus einem ständig identisch aussehenden Feld ohne jegliche merkliche Randomisierung. Mit 30 folgenden Zombies sind dies weit mehr als die etwa vier bis sechs für dieses Spiel angedachten. Statt sich nur vorwärts bewegen zu können, ist es hier beschränkt möglich etwas zurückzugehen und anzuhalten.

Bei den Spielen Infectonator 1, Infectonator World Dominator, Infectonator 2, Zombie Farm und Zombies Inc geht es darum, die Menschheit zu vernichten und durch Zombies zu ersetzen. Bei den Infectonator Spielen wird dazu jedes Gebiet einzeln vom Spieler erobert, bei den restlichen beiden Spielen geschieht dies automatisch und der Spieler kümmert sich nur um die Verwaltung - im Falle von Zombie Inc um die einer Zombie-Firma.

Rollenspielelemente findet man in den Spielen Sonny, Sonny 2, Undead Throne und Zombie Knight. Es werden Items, Erfahrungspunkte und Geld gesammelt, um den einzelnen eigenen Zombie zu verbessern.

Springen als Zombie? In den Jump & Run Spielen Back to Zombieland, Zombie Bites und Zombie Mario[Anti-Spieleempfehlung] wird das scheinbar unmögliche möglich gemacht.

In Corpse Craft werden gleichfarbige Quadrate angeklickt um dadurch Ressourcen zu sammeln mit denen Zombies hergestellt werden können. Spookathlon ist eine Sammlung von Sportspielen, in denen man in 3 von 5 Spielen als Zombie spielt. Der Zombie Rider fährt auf einem Motorrad eine Strecke ab und absolviert Stunts. Wem Wasser eher liegt, kann auch auf einem Surfbrett in Zombie Surf[Anti-Spieleempfehlung] Stunts hinlegen.

Kategorie 2: Zombies unterstützen/verwenden

Erstelle einen Pet Zombie[Anti-Spieleempfehlung], füttere ihn und spiele mit ihm.

In Teelombies Infection seid ihr ein böser Wissenschaftler, der Zombies wie Schweine in Angry Birds verschießt, um dadurch Menschen zu infizieren und ihnen anschließend ein Gegenmittel zu verkaufen.

Tim the Zombie[Anti-Spieleempfehlung] ist ein animierter Zombie mit 6 Animationen und dazugehörigen Sounds.

Das Ankleidespiel Bad Guy & Girl Dressup[Anti-Spieleempfehlung] ermöglicht es einen weiblichen und männlichen Zombie mit Kleidung, Masken, Waffen und anderem anzuziehen.

Carol wird von Zombies gefangen genommen und soll verspeist werden, glücklicherweise kann sie kochen und überredet die Zombies im Spiel Feed Mee sie am Leben zu lassen, solange sie ihnen Essen zubereitet.

Aufgrund der Zombieapokalypse gibt es inzwischen viel mehr Zombies als Menschen, daraus lässt sich in Zombie Burger Profit schlagen, in dem ihnen Fast Food zubereitet wird.

In Zombie Drop werden Zombie-Einzelteile fallen gelassen und müssen in der richtigen Reihenfolge zusammengesetzt werden.

Als Fledermaus beschützt man im Zombie Hotel die friedlebigen Untoten vor angreifenden Spinnen.

Kategorie 3: Strichmännchen

Das Jump & Run Spiel I saw her standing there[Spieleempfehlung] erzählt die Liebesgeschichte eines Mannes, dessen Freundin zum Zombie wurde. Die Grafik ist sehr simpel gehalten - die Spielfiguren besitzen keine Arme und bestehen lediglich aus einem Rechteck als Körper und einem Kreis als Kopf.

Stickman Sam 2 navigiert mit Waffengewalt durch ein vertikales Labyrinth und stößt dabei auf Zombies und andere Monster. Die Strichmännchen-Figur und dessen Animationen sind deutlich digital erstellt worden, und das Level hat scheinbar ausschließlich gerade Kanten und Ecken.

Zombie Balloon Heads, sowie dessen Nachfolger Zombie Balloon Heads 2 und Zombie Balloon Heads Halloween, spielen in einer Fantasiewelt, in der ein gezeichnetes Strichmännchen mit Tinte u.a. auf Zombies schießt bis ihre Schädel so voller Tinte sind, dass sie platzen. Alle Spielobjekte und Oberflächen sehen aus wie von Hand gezeichnet und haben als Hintergrund eine Papiertextur.

Umsetzung

Arbeitsaufwand

Stand: 2013-12-19

h = Stunden (hours)

m = Minuten

nach Kalenderwoche

KW Planung Realität Zeitaufwand
39 Recherche, Wiki-Doku ~41h
40 0h
41 Wiki-Doku, Prototyp 1 (R11), Präsentation 1 13h 19m
42 Krank 0h
43 0h
44 Randomisierter Levelaufbau 0h
45 Bewegung, Schwarmverhalten Randomisierter Levelaufbau 5h 31m
46 Fähigkeiten, Prototyp 2 Schrift, Sounds, Bewegung, Schwarmverhalten, Prototyp 2 (R30) 15h 20m
47 Upgrades, Sounds Schrift 3h 23m
48 Wiki-Doku, Website Wiki-Doku, Website 13h 54m
49 Feinschliff 0h
50 Präsentation 2 Feinschliff 9h 58m
51 Präsentation 2 Feinschliff, Prototyp 3 (R58) 10h 53m

nach Arbeitsbereich

Arbeitsbereich Stundensatz bisheriger Zeitaufwand theoretische Kosten
Recherche 10 €/h ~30h 300,00 €
Dokumentation 15 €/h ~11h + 24h 28m 532,00 €
Grafiken 30 €/h 12h 5m 362,50 €
Sounds 20 €/h 1h 28m 29,33 €
Levelaufbau 25 €/h 11h 53m 297,08 €
K.I. 40 €/h 6h 35m 263,33 €
GUI 30 €/h 15h 49m 474,50 €
Summe ~19,94 €/h ~41h + 72h 18m 2258,74 €

Levelaufbau

In Unity werden alle Spielobjekte in einer hierarchischen Baumstruktur eingeordnet. Damit wesensgleiche Objekte nicht immer wieder neu erstellt werden müssen gibt es sogenannte Prefabs, das sind wiederverwendbare Vorlagen für Objekte, die sich identische Eigenschaften teilen. Prefabs entsprechen dem Prototype Entwurfsmuster [1] und lassen sich auch vom Quelltext aus durch eine neue Kopie erzeugen (instantiieren).

Um eine unendliche Spielwelt zu ermöglichen, existieren mehrere verschiedene Arten von Blöcken die jeweils Prefabs sind. Zu Beginn des Spieles werden sechs zufällige Blöcke instantiiert und in einem kleinen sechselementigen Feld (Array) referenziert, davon sind zwei Blöcke hinter dem Spieler, in einem befindet er sich und die verbleibenden drei Blöcke befinden sich vor ihm. Eine Ganzzahlvariable enthält als Wert den aktuellen Index des Blockes, in dem sich der Spieler befindet. Betritt der Spieler einen neuen Block vor ihm, wird der Index in ℤ6 inkrementiert, der am weitesten hinter ihm liegende Block und alle Spielobjekte, die sich in ihm befinden, zerstört und ein neuer zufälliger Block vor ihm instantiiert. Der neue Block nimmt die Feld-Position des zerstörten Blockes hinter dem Spieler ein, befindet sich geometrisch aber an einer Position vor dem Spieler. Dadurch wird die Anzahl aktiver Spielobjekte in der endlosen Spielwelt limitiert.

Damit die Blöcke nicht alle gleich aussehen, enthalten deren Prefabs mehrere alternierende Objekte, die zufällig ausgewählt werden. Dazu befinden sich die alternierenden Objekte in der Hierarchie unterhalb eines Entscheiderobjektes, das mittels Skript eines von beliebig vielen Kindobjekten zufällig auswählt und sich selbst sowie die nicht ausgewählten Kindobjekte zerstört. Damit die Welt dann nicht vollständig mit alternierenden Objekten an identischen Positionen zugepflastert ist, zerstören sich ausgewählte Objekte beim Erstellen mit einer individuellen Wahrscheinlichkeit zufällig selbst.

Auf jeden Block befinden sich manuell verteilte Spawn-Punkte, auf denen beim Erstellen des Blockes zufällig bis zu n Entitäten verteilt werden. Wobei n die Quadratwurzel der Anzahl der Spawn-Punkte dieses Blockes ist. Entitäten können sowohl Zombies als auch Menschen sein.

Schrift

Als Schriftart für GUI-Elemente wird, passend zum restlichen Spieldesign, eine am Whiteboard erstellte eigene Schriftart verwendet.

Grafik

Abb. 4: Eigene Schriftart, ohne Nachbearbeitung.

Zeichnen und Fotografieren sind einfach und schnell erledigt, aber die Nachbearbeitung nimmt etwas Zeit in Anspruch. Zunächst muss jedes Zeichen einzeln ausgeschnitten werden und dessen Hintergrund transparent gemacht werden. Damit nicht für jedes Zeichen eine einzelne Datei erstellt wird und jeweils separat geladen werden muss, werden alle Zeichen zusammen in einer Bilddatei in einem Raster aus 150 x 150 px Quadraten gespeichert. Jedes Quadrat enthält ein Zeichen, und die Höhe aller Zeichen muss normiert werden, um einen gleichmäßigen Textfluss zu erreichen.

Abb. 5: Nachbearbeitete eigene Schriftart.

Abzüglich 10 Pixel als Abstand an den Rändern zu anderen Quadraten habe ich mich auf folgende Zeichenhöhen festgelegt:

Minuskeln mit Oberlänge (b, d, f, h, k, l, t), i, Ä, Ö, Ü, Majuskeln und Ziffern: 115 px

Minuskeln mit Unterlänge ohne j (g, p, q, y), ä, ö, ü: 90 px

j, ß: 130 px

Verbleibende Minuskeln (a, c, e, i, m, n, o, r, s, u, v, w, x, z): 75px

GUI

Abb. 6: Anwendungsbsp. bei 1680x1050 px (16:10).
Abb. 7: Anwendungsbsp. bei 640x480 px (4:3).

Um meine Schriftart zu verwenden, implementiere ich eine eigene Klassenhierarchie für GUI-Objekte, die sich nach dem Motivationsbeispiel für das Flyweight Entwurfsmuster in Design Patterns[1] richtet. Das bedeutet, jedes Zeichen ist ein eigenes Objekt der Klasse GCharacter, das jedoch nur ein einziges Mal erstellt wird (Objekte der GCharacter-Klasse sind Flyweights). Um das zu gewährleisten, können GCharacter-Objekte nur über eine zentrale Factory Method[1] erstellt werden, die neue Objekte nur dann erstellt, wenn sie noch nicht existieren. Da bei mehrfacher Verwendung des gleichen Zeichens auf das identische Objekt referenziert wird, kann sich der intrinsische Zustand dieser Objekte nur auf das Zeichen selbst und dessen allgemeine Eigenschaften (Breitenverhältnis, Offset) beschränken. Extrinsische Zustände, wie die Position an der es gezeichnet werden sollen oder dessen Schriftgrößen, müssen an die entsprechenden Operationen (Draw, Width, Height) übergeben werden, um kontextabhängig die gewünschte Funktionalität erreichen zu können.

Da sich die Schriftgröße von Zeichen nur selten oder nie ändert (durch Wechseln der Auflösung), können viele Zwischenberechnungen der Operationen in mit der Schriftgröße assoziierten Feldern (Map, Dictionary) gespeichert werden.

Um aus einzelnen Zeichen ganze Wörter und Sätze zu konstruieren, findet das Composite Entwurfsmuster[1] Anwendung. Die Klasse GString beispielsweise fasst mehrere Zeichen zu einer Zeichenkette zusammen (Objekte der Klasse GString sind Composites). Dessen Breite ist die Summe der Breiten seiner GCharacter-Objekte und die Höhe deren Maximum. Zum Zeichnen eines GStrings wird beim Iterieren über alle GCharacter-Objekte deren Draw-Methode mit lokaler Position und Schriftgröße als Argumente aufgerufen. Die lokale Position berechnet sich aus der Ausgangsposition des GString-Objektes und den Breiten der vorherigen GCharacter-Objekte.

Für variable Zahlen wie die Anzahl gefundener Gehirne bietet sich eine Klasse GInteger an, die sich nur dann verändert, wenn sich auch dessen zugehörige Variable verändert. Diese sich verändernden Objekte können durch das Composite Entwurfsmuster[1] ebenso wie z.B. GCharacter-Objekte in GString aneinandergehängt werden. Dadurch wirkt sich die Veränderung einer Zahl nur auf dieses Objekt aus, und nicht auch auf die umliegenden Objekte in derselben Zeichenkette.

K.I.

Bewegung

Wander

Abb. 8: Die Entität strebt t auf dem Wander-Kreis mittels force an.

Damit die Zombies oder Menschen anfänglich nicht blöd in der Gegend rumstehen oder stur in eine Richtung gehen, wird das Wander Steering Behavior[2] angewendet. Dadurch wandert die Entität herum, sie bewegt sich zufällig durch den Raum, jedoch nicht in eine stockende und ständig wechselnde zufällige Richtung, sondern durch langsames Drehen der Zielrichtung.

Dieser Wander-Algorithmus hat drei Parameter, mit denen er eingestellt werden kann, eine Distanz |d|, einen Radius r und einen Jitter j. Diese Parameter wirken sich auf die in Abbildung 8 benannten Vektoren pos, d, t und force folgenderweise aus:

Die Distanz |d| bestimmt die Länge des Vektors d, der in die Blickrichtung der Entität zeigt. Der durch den Vektor d bestimmte Punkt ist der Mittelpunkt des Wander-Kreises mit Radius r, der sich durch die Bewegung der Entität laufend ändert. Auf dem Wander-Kreis befindet sich das Ziel, das, beschrieben durch den Vektor force, angestrebt werden soll. Dessen Position im lokalen Koordinatensystem vom Kreis-Mittelpunkt aus wird durch den Vektor t (target) beschrieben.

Der Vektor t wird bei jeder Iteration durch Vektoraddition mit einem zufällig erstellten Vektor der Länge j verschoben. Durch Normalisieren von t und anschließender Multiplikation mit Radius r wird der verschobene Vektor t wieder auf den Wander-Kreis projiziert. Das Ziel rotiert dadurch in kleinen Schritten zufällig entlang des Wander-Kreises, und der sich aus t berechnende Vektor force bewegt sich entsprechend mit. Auf die Entität wird der Vektor force als physikalische Kraft angewendet, wodurch sie sich in einer, abhängig von den eingestellten Parametern, flüssigen Art und Weise nach rechts und links dreht.

Offset Pursuit

Abb. 9: Zombie Z2 strebt Position o2t an und nicht o2.

Um die Zombies die zum Zwarm (Zombie Schwarm) gehören, relativ zur Spielfigur zu positionieren wird das Offset Pursuit Steering Behavior[2] verwendet. Hierbei werden vier Offset Vektoren oi mit 1 ≤ i ≤ 4 im lokalen Koordinatensystem der Spielfigur disjunkt an die jeweiligen Zombies Zi des Zwarms verteilt. Die Vektoraddition von oi mit der extrapolierten Position post der Spielfigur zum Zeitpunkt t (abhängig von Distanz zur Spielfigur, Bewegungsrichtung und Geschwindigkeiten) ergibt die Position oit im globalen Koordinatensystem die der Zombie anstreben muss, um seine Position zum Zeitpunkt t einnehmen zu können.

Die Zombies bewegen sich dadurch in einer festen Formation. Wird die Formation z.B. durch Hindernisse zerstört, renkt sie sich nach kurzer Zeit wieder ein (vorausgesetzt Zombies können sich etwas schneller als die Spielfigur bewegen).

Damit die Bewegungen der Zombies nicht zu glatt und gerade wirken, kann man Offset Pursuit auch mit Wander kombinieren. Hierbei berechnen beide Algorithmen jeweils einen Kraft-Vektor, die jedoch vor dessen Anwendung mit entsprechenden Gewichtungsfaktoren a und b gegeneinander ausbalanciert werden. Für die beiden Faktoren gilt: a, b ∈ (0.0, 1.0) und a + b = 1. Wander hat eine deutlich geringere Gewichtung als Offset Pursuit, da das herumtorkeln nur gering ausfallen soll.

Flocking

(Noch nicht implementiert)

Flocking[2] ist eine Kombination der Steering Behaviors Separation, Allignment und Cohesion.

Separation bewirkt das Zombies, die sich zu nahe kommen, sich gegenseitig abstoßen, damit es nicht zu Kollisionen kommt. Von einem Zombie ausgehend wird ein Kraft-Vektor von den zu nahen anderen Zombies weg berechnet. Umso näher der jeweilige Zombie, desto stärker die Kraft (größere Vektorlänge) in die entgegensetzte Richtung zum Zombie.

Allignment ist eine Normalisierung der eigenen Bewegungsrichtung, ausgehend von den Bewegungsrichtungen der umliegenden Zombies innerhalb eines beschränkten Radius.

Cohesion lässt nahe Zombies zusammenrücken, wodurch eine Gruppe gebildet wird, die sich mittels Allignment gemeinsam in eine Richtung bewegt.

Separation und Cohesion wirken entgegengesetzt und balancieren sich irgendwo in der Mitte aus.

Diese drei Steering Behaviors kombiniert ergeben ein Verhalten bei dem sich Zombies, die sich zufällig zu nahe kommen, einander anschließen. Es ist keine feste Verbindung wie beim Offset Pursuit bei der jeder Zombie eine feste Position hat, sondern eine lose Verbindung, die sich dynamisch ergibt und sich ebenso dynamisch wieder lösen kann.

Angewendet werden soll Flocking für Zombies die sich nicht fest der bereits vollen Offset Pursuit-Spielergruppe anschließen. Es soll zeitlich begrenzt sein, damit der Spieler nach etwas Spielzeit nicht Dutzende Zombies auf einmal steuert.

Aktionsauswahl

Da Zombies und Menschen ihr Verhalten zur Laufzeit dynamisch verändern sollen, bietet sich das State[2][1] Entwurfsmuster an. Dadurch wird das zustandsspezifische Verhalten in einem Objekt gekapselt. Möchte man das sich eine Entität anders verhält, wechselt man einfach deren Zustand. Bei einem Zustandswechsel wird einer lokalen Variable für den aktuellen Zustand lediglich eine neue Zustands-Referenz zugewiesen.

Das Verhalten der unterschiedlichen Zustände wird über mehrere Klassen verteilt, statt sich zu einem großen monolithischen Switch-Statement aufzublasen.

Hat ein Zustand wenige oder gar keine Instanzvariablen, lohnt es sich Zustände als Singleton[1] zu modellieren, wodurch zur Laufzeit pro Zustand nur ein Objekt erstellt wird, auch wenn sich mehrere Entitäten in demselben Zustand befinden. Bei wenigen Instanzvariablen müssen diese in die Entität verschoben werden.

Für zeitabhängige Abfolgen, sowie zur Kommunikation der Entitäten untereinander, bietet es sich an ein Nachrichtensystem (Messaging[2]) zu verwenden, welches eine verzögerte Auslieferung unterstützt. Dadurch können Timer als zeitverzögerte Nachrichten an sich selbst umgesetzt werden, statt zusätzliche Instanzvariablen in der Entität anlegen und ständig überprüfen zu müssen.

Fähigkeiten

(Noch nicht implementiert)

Fähigkeiten können sowohl durch einen Mausklick auf einen entsprechenden Button als auch durch einen Tastendruck ausgelöst werden. In beiden Fällen wird ein und dieselbe Rückruffunktion (Callback) ausgeführt.

Ein Mediator[1] sorgt für eine lose Kopplung der Rückruffunktionen mit den Spielobjekten auf die sie wirken. Die Rückruffunktionen müssen sich dadurch nicht selbst Referenzen auf Spielobjekte merken oder, falls sich diese zur Laufzeit ändern können, selbst herausfinden, sondern beschäftigen sich nur mit der gewünschten Funktionalität für diese Objekten.

Als Beispiel sei ein Kampfschrei, der eine Erhöhung der Geschwindigkeit des Zombie-Schwarms auslöst, beschrieben: Die Rückrufmethode, welche durch Tastendruck oder Buttonklick ausgelöst wird, schickt zwei Nachrichten an den Mediator, die dieser wiederum an alle Mitglieder des Schwarms weiterleitet: Nachricht 1 bewirkt das sich die Geschwindigkeit der Zombies erhöht. Nachricht 2, die dem Mediator zeitverzögert zugestellt wird, setzt die Geschwindigkeit der Zombies auf den ursprünglichen Wert zurück.

Quellenverzeichnis

  1. 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns. Elements of Reusable Object-Oriented Software. Boston: Addison-Wesley. Wikipedia
  2. 2,0 2,1 2,2 2,3 2,4 Buckland, M. (2004). Programming Game AI by Example. Plano: Wordware Publishing, Inc. TOC