Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Nachdem unser Konzept stand, haben wir als Gruppe beschlossen, dass wir als erstes Erstes einen kleinen spielbaren Prototyp haben wollen,
in welchem wir unsere Spielidee und unser Konzept testen können.

...

Sozusagen wurde an diesen Punkt entschieden, ob wir das Spiel so weiter führen können, wie geplant oder ob wir fundamentale Änderung vornehmen müssen.

...

Unser derzeitiger Stand ist ein Raum mit Spielelementen, wie einen Teich, einer Sandbank und diverse Felsen.
Zu diesen reiht sich eine saftige Wiese, die von Bäumen als Raumtrenner umgeben ist.
Unsere Hauptfigur muss sich im Prototyp - Raum gegen eine Armee von Explodierenden Teddybärenexplodierenden Lilabären, aggressiven, auf Nahkampf - fixierten Braunbären
und Pfeile schießende, kleine Hamster durchsetzen.
Dafür steht dem Spieler ein Arsenal an Waffen zur Verfügung: Pistole, MG, Shotgun, Raketenwerfer.

Der Spieler erleidet passend zum Angriff schaden, ebenso kann der Spieler den Tieren schaden.
Der Spieler erhält Feedback, wenn er den Tieren Schaden zufügt oder sie tötet.

Ein Menü zum Start, bei Pause und beim Tod steht dem Spieler zur Verfügung.

...

Abgerundet wird der Prototypraum
von einer Auswahl an Gegnern:


 

Um einen tieferen Blick Einblick in die Entwicklung zu ermöglichen,
gewähren wir einen tieferen Einblick in die Entwicklungeine kleine Darstellung dessen am Beispiel
unseres pfeilschiessenden Hamsters.

...

Auf dieser Skizze haben wir den Charakter aufgebaut und seine Walkcyclen Walkcycles passend zum Grundentwurf ausgearbeitet.
Der Charakter hat 6 Walkcyclen Walkcycles, die wir alle auf ein „Atlas“ gespeichert haben, um „draw-calls“ von Unity zu vermindern
und somit eine höhere Performance zu gewährleisten.

...

In der vorgenerierten Funktion void Start(), welche beim Starten der Szene einmal ausgeführt wird, binden wir die Position des Spielers
an die Variable Player und weisen der Variable "animator" dem den Hamster - Animator zu, den wir vor dem Skript erstellt und konfiguriert haben.
Außerdem binden wir die public Variablen "health" und "attackCooldown" an private Variablen ,um feste Werte im Skript weiter zu verwenden.

Vielleicht mag man sich fragen, warum wir dann überhaupt public Variablen verwenden,
wenn die sowieso wieder in private verwandelt werden.
Der Grund dafür ist, dass man so in Unity schnell verschiedene Balancing - Veränderung durchführen kann.

 

 

Die void Update() - Funktion wird auch von Unity generiert und wird nach jedem Frame aufgerufen.
Daraufhin lassen wir unsere HP - Leiste Prozentual zu den Aktuellen zum aktuellen Leben füllen.
Sollte der Welt Wert auf "kleiner gleich" 0 fallen, zerstören wir unser Spielobjekt und lassen ein neues Objekt erstellen,
welche unsere Blutlache ist
Dieses neue Objekt ist eine Blutlache, die an der Stelle des eines Gegners spawnt, wenn eine Gegner er getötet wurde.
Alle Gameobjekte haben ein eigenes Verhalten, dementsprechend auch ein Skript.
Mit der nächsten If Abfragen - Abfrage prüfen wir, ob unser boolean "move" auf true gesetztegesetzt wurde, welche dann die Funktion Movement() aufruft,
zu welcher wir später noch später einmal zurückkommen.
In Zeile 71 reduzieren wir die attackCooldown um die System Zeit, also wenn im Spiel 200ms vergangen sind,
ist geht der attackCooldown Timer auch wirklich 200ms runter.
In der letzten If - Abfrage überprüfen wir, ob unser Hamster wieder angreifen darf
und er sich in einer Angriffs Animation befindet, also das ob die variable AttackDir nicht den Wert 0 hat.
Wenn dies erfüllt ist, rufen wir die Funktion shot() auf und die Funktion resetAttackCooldown(), welche später erläutert werden.

...

Auf dem Bild sehen wir die Funktion Movement(), die wir zur Erinnerung immer aufrufen, wenn der boolean "move" auf True gesetzt ist, also wenn sich der Gegner bewegt.
In den ersten beiden Zeilen (87 und 88) berechnen wir jemals jeweils den Unterschied zwischen dem Spieler und unseren Gegner für die X- und für die Y-Achse.
In den nächsten 4 Zeilen errechnen wir die Hypotenuse der zu den zuvor ausgerechneten zwei Strecken, um die direkte Entfernung des Gegners zu erhalten.

Es folgt ein Schaubild was , welche die Theorie dahinter nochmal verbildlicht.

...

Mit der errechneten Entfernung können wir gucken, ob sich unser Hamster in angriffsreichweite Angriffsreichweite befindet
oder er vor den dem Spieler wegrennen soll oder dem Gegner ihm entgegenrennen bzw. hinterherrennen soll, um in angriffsreichweite Angriffsreichweite zu kommen.


Die erste If - Abfrage überprüft, ob sich der Spieler in der Angriffszone befindet,
sollte das sein .
Sollte dies erfüllt sein, sorgt die Anweisung dafür das , dass er stehen bleibt und auch keine Bewegungsanimation mehr abspielt.
Die darauffolgende else Else if - Abfrage überprüft, ob der Spieler sich zu dicht am Gegner befindet,.
daraufhin Daraufhin sorgt die Anweisung, dafür das dass der Gegner entgegengesetzt zum vom Spieler wegläuft und keine Angriffsanimation mehr aktiv sein darf.
Falls keine der beiden vorherigen Szenarien zutrifft, rennt der Hamster auf den Spieler zu.

Dazu auch ein Schaubild was , das die Theorie dahinter nochmal verbildlicht.

 

 

Wir befinden unser uns noch immer in der Movement() Funktion.
Auf diesen diesem Bild geht es um das Animator verhalten was Verhalten des Animators, den wir relativ am Anfang konfiguriert haben.
Ziel hier ist es das , dass unser Hamster, passend zur Position, die Richtige Angriff richtige Angriffs- und Bewegungsanimation abspielt.

Mit der If - Abfrage (Zeile 117) überprüfen wir erstmal, ob der Abstand zum Spieler auf der X-Achse Größer größer ist als auf der Y-Achse.
Sollte , dass dies der Fall sein wissen wir das , dass der Spieler sich stärker mehr rechts oder links vom Hamster befindet, als über oder unter ihm.

Da wir jetzt wissen das , dass wir entweder die Bewegungs Animation Bewegungsanimation nach links oder nach rechts abspielen müssen,
müssen wir noch überprüfen, ob der Spieler sich weiter rechts oder weiter links befindet.
Zuerst übernehmen wir den Fall rechts.
Dafür prüfen wir in Zeile 119, ob der X-Wert vom Spieler größer als der X-Wert vom Hamster ist.
Trifft dieses Szenario ein, setzten wir die Variable AttackDir auf 0, um die Angriffsanimation aufjedenfall zu unterdrücken,
und setzten die Variable MovementDir auf 2, was nach unserer anfänglichen Konfiguration die der Bewegungsanimation nach rechts entspricht.

Da wir wissen das , dass der Spieler sich rechts von uns befindet, nutzen wir den Zustand aus
und gucken, ob wir uns in Angriffsreichweite befinden mit der if - Abfrage in Zeile 124.
Sollten wir uns in besagter Angriffsreichweite befinden, rufen wir die Funktion setMoveFalse() auf, woaruf worauf wir später nochmal zurückkommen,
kurz gesagt setzt sie unser boolean "move" auf falseFalse, setzten die Variable MovementDir auf 0 und die Variable AttackDir auf 2,
was nach unsere anfänglichen Konfiguration Angriff nach rechts entspricht.
Zusätzlich weißen weisen wir den dem String shotDirection die zeichenkette Zeichenkette „right“ zu und setzten den currentShotPoint auf 1. Letztendlich rufen wir die Funktion attackOffset() auf.

...

Falls sich der Spieler Links befindet wird die If - Abfrage in Zeile 135 ausgelöst,
welche dasselbe wie die If -Abfrage in Zeile 119 macht, nur sind alle Anweisung angepasst, um die Animation nach Links zu steuern.

...

Der Vollständigkeitshalber der letzte Teil der Movement() Funktion.
Sollte die If - Abfrage, in der wir testen, ob der Spieler sich mehr links oder rechts befindet als oben oder unten, fehlschlagen wird die else horizontale Abstand zum Spieler größer ist als der vertikale Abstand, fehlschlagen, wird die Else - Abfrage in Zeile 152 ausgelöst.
Dementsprechend testen die Nachfolgenden nachfolgenden If - Abfragen, ob der Spieler sich über oder unter unseren Hamster befindet
und führt dementsprechend dieselben Anweisungen aus, nur auf die richtige Richtung getrimmt.

...

Um das Thema abzuschließen, noch ein Schaubild was das ganze verbildlichen soll, um das Ganze noch einmal zu verbildlichen.

 

 

In Zeile 190 definieren wir die Funktion resetAttackCooldown(),
welche lediglich dafür sorgt das , dass bei jedem Aufruf die derzeitige attackCooldown wieder auf den defenierten definierten Wert von maxCooldown gesetzt wird.
Die nächste Funktion, die wir definieren, attackOffset() sorgt dafür, das auf attackCooldown 0.7f addiert wird.
Der Grund dafür das ist, dass der Hamster den Pfeil erst schießen soll, wenn bei der Animation der richtige Frame abgespielt wird,
daher müssen wir die künstliche Verzögerung einbauen.
Die Letzte Funktion auf den dem Bild (Zeile 200) shot() sorgt dafür das unser Hamster , dass, wenn die Funktion aufgerufen wird ,
unser Hamster ein GameObject erzeugt was der Pfeil vom Hamster ist und ihn mitteilen , welches sein Pfeil ist, und ihm mitteilt, wo er erzeugt wird und in welche Richtung der Pfeil er fliegen soll.
Aus diesen Grund setzten wir in der Movement() Funktion den currentShotPoint und die shotDirection.
Diese Information Teilen wir dem Skript mit, der mit den dem Pfeil vom Hamster verbunden ist und der regelt das Verhalten vom Pfeil.

...

Auf diesen Bild sehen wir die Funktion OnTriggerEnter2D(Collider2D collision) Funktion.
Diese macht letztendlich nix nichts anderes, als die Information von Unity zu bekommen,
was für eine Berührung bei mit der Hamster Hitbox, die wir in Unity definiert haben, stattgefunden hat.

Dafür überprüfen wir den Tag des Objektes, welches uns berührt haben hat und führen dementsprechend eine Anweisung aus.

Als Beispiel gehen wir davon aus das uns ein Maschien Gewehr Kugel, dass den Hamster eine Maschinengewehrkugel, mit den dem Tag „BulletMG“, getroffen hat.
Daraufhin wird von der health Variable der Wert 10 abgezogen. Die Kugel, die Kugel die uns getroffen hat, wird zerstört
und wir initialisieren das Objekt bloodSplattern an der derzeitigen Position des Hamsters.
Das bloodSplattern sind die Blutspritzer, die Blut einen Treffer anzeigen, welche auch wieder von einem eigenen Skript gesteuert wirdwerden.

 

 

Im letzten Teil des Skripts definieren wir die Funktion setMoveTrue()
und die Funktion setMoveFalse() welche jeweils den boolean "move" auf true oder false setzten.

Letztendlich haben wir dann mit unseren vorhandenen Gegnern, Weltobjekten
und unseren unserem Spieler den am Anfang besprochenen Prototyp Raum Prototypen unseres Raums entwickelt.

 

 

Ziel für den nächsten Milestone:
In diesem Milestone planen wir unseren nächsten Raum typRaumtyp, den Fallenraum, umzusetzen. Zudem soll unser bisheriger Raum mehr Vielfalt an Gegner Vielfalt bekommen.

 

 

Schlusswort:

Was wir auch niemanden vorenthalten wollen, ist die Wichtigkeit des stetigen Testens von dem, was man macht.
Als optimal hat sich erwiesen, wenn andere Leute die Sachen testen, die man selbst erstellt hat.
So konnten immer mehr Fehler gefunden werden, als der Ersteller selbst entdecken konnte.

Hier nur ein kleiner Ausschnitt unserer Bug Liste die wir hatten, als es nur ein einen Gegner gab und den Spieler.

...