Tower Defense-Spiele werden immer beliebter, und das ist nicht verwunderlich - wenig kann mit dem Vergnügen verglichen werden, eigene Verteidigungslinien zu beobachten, die böse Feinde zerstören! In diesem zweiteiligen Tutorial erstellen wir ein Tower Defense-Spiel auf der
Unity- Engine!
Sie lernen, wie Sie Folgendes tun:
- Erschaffe Wellen von Feinden
- Lassen Sie sie Routenpunkten folgen
- Baue und verbessere Türme und lehre sie, wie man Feinde in kleine Pixel zerlegt
Am Ende bekommen wir den Rahmen des Spiels, der weiterentwickelt werden kann!
Hinweis : Sie benötigen grundlegende Unity-Kenntnisse (z. B. müssen Sie wissen, wie Assets und Komponenten hinzugefügt werden, welche Fertighäuser vorhanden sind) und die Grundlagen von C # . Um all dies zu lernen, empfehle ich Ihnen, die Tutorials zu Unity von Sean Duffy oder die Reihe Beginning C # with Unity von Brian Mockley durchzugehen.
Ich werde in Unity für OS X arbeiten, aber dieses Tutorial ist auch für Windows geeignet.
Durch die Fenster des Elfenbeinturms
In diesem Tutorial erstellen wir ein Tower Defense-Spiel, in dem Feinde (kleine Bugs) zu einem Cookie kriechen, der Ihnen und Ihren Schergen gehört (natürlich sind dies Monster!). Der Spieler kann Monster an strategischen Punkten platzieren und sie für Gold verbessern.
Der Spieler muss alle Bugs töten, bis sie zum Cookie gelangen. Jede neue Welle von Feinden wird immer schwieriger zu besiegen. Das Spiel endet, wenn Sie alle Wellen überleben (Sieg!) Oder wenn fünf Feinde zu den Keksen kriechen (Verlust!).
Hier ist ein Screenshot des fertigen Spiels:
Monster, vereinigt euch! Schützen Sie den Cookie!An die Arbeit gehen
Laden Sie dieses
Projekt leer herunter, entpacken Sie es und öffnen Sie das
TowerDefense-Part1-Starter- Projekt in Unity.
Der Projektentwurf enthält zahlreiche Grafiken und Sounds, vorgefertigte Animationen und mehrere nützliche Skripte. Die Skripte stehen nicht in direktem Zusammenhang mit Tower Defense-Spielen, daher werde ich hier nicht darauf eingehen. Wenn Sie jedoch mehr über das Erstellen von 2D-Animationen in Unity erfahren möchten, lesen Sie dieses
Unity 2D-Lernprogramm .
Das Projekt enthält auch Fertighäuser, die wir später hinzufügen werden, um Charaktere zu erstellen. Schließlich gibt es im Projekt eine Szene mit einem Hintergrund und einer benutzerdefinierten Benutzeroberfläche.
Öffnen Sie die
GameScene im Ordner "
Szenen " und stellen Sie den
Spielemodus auf ein Seitenverhältnis von
4: 3 ein, damit alle Beschriftungen korrekt zum Hintergrund passen. Im Spielemodus sehen Sie Folgendes:
Autorschaft:- Die Grafiken für das Projekt stammen aus dem kostenlosen Wiki Wenderlich Pack! Weitere grafische Arbeiten finden Sie auf ihrer Website gameartguppy .
- Großartige Musik von BenSound , die andere großartige Soundtracks enthält!
- Ich danke auch Michael Jesper für die sehr nützliche Kameraverwacklungsfunktion.
.
Der Ort ist mit einem Kreuz markiert: der Ort der Monster
Monster können nur auf Punkte gelegt werden, die mit einem
x markiert sind.
Um sie der Szene hinzuzufügen, ziehen Sie
Images \ Objects \ Openspot aus dem
Projektbrowser in das
Szenenfenster . Während die Position für uns nicht wichtig ist.
Nachdem Sie in der Hierarchie
Openspot ausgewählt haben, klicken
Sie im
Inspektor auf
Komponente hinzufügen und wählen Sie
Box Collider 2D . Im Szenenfenster zeigt Unity einen rechteckigen Collider mit einer grünen Linie an. Wir werden diesen Collider verwenden, um Mausklicks an dieser Stelle zu erkennen.
Fügen Sie die Komponente
Audio \ Audio Source auf
die gleiche Weise zu
Openspot hinzu .
Wählen Sie für den
AudioClip- Parameter der Audio Source-Komponente die Datei
tunnel_place aus , die sich im
Audio- Ordner befindet, und deaktivieren Sie
Play On Awake .
Wir müssen 11 weitere Punkte schaffen. Obwohl die Versuchung besteht, all diese Schritte zu wiederholen, hat Unity eine bessere Lösung:
Fertighaus !
Ziehen Sie
Openspot aus der
Hierarchie in den Ordner
Prefabs im
Projektbrowser . Sein Name wird in der Hierarchie blau, was bedeutet, dass er an das Fertighaus angehängt ist. Ungefähr so:
Nachdem wir das vorgefertigte Leerzeichen haben, können wir so viele Kopien erstellen, wie wir möchten. Ziehen Sie
Openspot einfach per Drag & Drop aus dem
Prefabs- Ordner im
Projektbrowser in das
Szenenfenster . Wiederholen Sie dies 11 Mal und 12 Openspot-Objekte werden in der Szene angezeigt.
Verwenden Sie nun den
Inspektor , um diese 12 Openspot-Objekte mit den folgenden Koordinaten festzulegen:
- (X: -5,2, Y: 3,5, Z: 0)
- (X: -2,2, Y: 3,5, Z: 0)
- (X: 0,8, Y: 3,5, Z: 0)
- (X: 3,8, Y: 3,5, Z: 0)
- (X: -3,8, Y: 0,4, Z: 0)
- (X: -0,8, Y: 0,4, Z: 0)
- (X: 2,2, Y: 0,4, Z: 0)
- (X: 5,2, Y: 0,4, Z: 0)
- (X: -5,2, Y: -3,0, Z: 0)
- (X: -2,2, Y: -3,0, Z: 0)
- (X: 0,8, Y: -3,0, Z: 0)
- (X: 3,8, Y: -3,0, Z: 0)
Wenn Sie dies tun, sieht die Szene folgendermaßen aus:
Wir platzieren Monster
Um die Platzierung zu vereinfachen, befindet sich im
Prefab- Ordner des Projekts ein
Monster- Fertighaus.
Monster Prefab GebrauchsfertigIm Moment besteht es aus einem leeren Spielobjekt mit drei verschiedenen Sprites und Schießanimationen als Kinder.
Jedes Sprite ist ein Monster mit unterschiedlichen Stärken. Das Fertighaus enthält auch die
Audio Source- Komponente, die gestartet wird, um Sound abzuspielen, wenn ein Monster einen Laser abfeuert.
Jetzt werden wir ein Skript erstellen, das
Monster auf
Openspot hostet .
Wählen Sie im
Projektbrowser das
Openspot- Objekt im Ordner
Prefabs aus . Klicken
Sie im
Inspektor auf
Komponente hinzufügen , wählen Sie
Neues Skript aus und benennen Sie das Skript
PlaceMonster . Wählen Sie
C Sharp als Sprache und klicken Sie auf
Erstellen und Hinzufügen . Da wir das Skript zum
Openspot- Prefab
hinzugefügt haben, haben alle Openspot-Objekte in der Szene jetzt dieses Skript. Großartig!
Doppelklicken Sie auf das Skript, um es in der IDE zu öffnen. Fügen Sie dann zwei Variablen hinzu:
public GameObject monsterPrefab; private GameObject monster;
Wir werden eine Instanz des in
monsterPrefab
gespeicherten
monsterPrefab
erstellen, um das Monster zu erstellen, und es in
monster
speichern, damit es während des Spiels manipuliert werden kann.
Ein Monster pro Punkt
Fügen Sie die folgende Methode hinzu, damit nur ein Monster auf einen Punkt gesetzt werden kann:
private bool CanPlaceMonster() { return monster == null; }
In
CanPlaceMonster()
wir überprüfen, ob die
monster
noch
null
. Wenn ja, dann gibt es kein Monster an der Stelle, und wir können es platzieren.
Füge nun den folgenden Code hinzu, um das Monster zu platzieren, wenn der Spieler auf dieses GameObject klickt:
Dieser Code findet das Monster, wenn Sie mit der Maus klicken oder den Bildschirm berühren. Wie arbeitet er?
- Unity ruft
OnMouseUp
automatisch OnMouseUp
wenn ein Spieler den physischen Collider GameObject berührt. - Beim Aufruf setzt diese Methode ein Monster, wenn
CanPlaceMonster()
true
zurückgibt. - Wir erstellen ein Monster mit der
Instantiate
Methode, die eine Instanz des angegebenen Fertighauses mit der angegebenen Position und Drehung erstellt. In diesem Fall kopieren wir monsterPrefab
, geben ihm die aktuelle GameObject-Position und keine Drehung, übertragen das Ergebnis auf GameObject
und speichern es in monster
- Am Ende rufen wir
PlayOneShot
auf, um den Soundeffekt PlayOneShot
, der an die AudioSource
Komponente des Objekts angehängt ist.
Jetzt kann unser
PlaceMonster
Skript ein neues Monster haben, aber wir müssen noch ein Fertighaus angeben.
Verwenden des richtigen Fertighauses
Speichern Sie die Datei und kehren Sie zu Unity zurück.
Um die Variable
monsterPrefab festzulegen , wählen
Sie zuerst das
Openspot- Objekt aus dem Ordner
Prefabs im Browser des Projekts aus.
Klicken Sie im
Inspektor auf den Kreis rechts neben dem Feld
Monster Prefab der
PlaceMonster (Script) -Komponente und wählen Sie im angezeigten Dialogfeld
Monster aus .
Das ist alles. Starte die Szene und erstelle Monster an verschiedenen Orten, indem du mit der Maus klickst oder den Bildschirm berührst.
Großartig! Jetzt können wir Monster erschaffen. Sie sehen jedoch wie ein seltsames Durcheinander aus, da alle Kindergeister des Monsters gezeichnet sind. Jetzt werden wir es beheben.
Erhöhe das Level der Monster
Die folgende Abbildung zeigt, dass Monster mit zunehmendem Level immer furchterregender aussehen.
Was für eine Süße! Aber wenn Sie versuchen, seine Kekse zu stehlen, wird dieses Monster zum Mörder.Das Skript wird als Grundlage für die Implementierung des Systems der Monsterlevel verwendet. Es verfolgt die Macht des Monsters in jedem Level und natürlich das aktuelle Level des Monsters.
Fügen Sie dieses Skript hinzu.
Wählen Sie das
Prefabs / Monster Prefab im
Projektbrowser . Fügen Sie ein neues
C # -Skript namens
MonsterData hinzu . Öffnen Sie das Skript in der IDE und fügen Sie den folgenden Code
über der
MonsterData
Klasse hinzu.
[System.Serializable] public class MonsterLevel { public int cost; public GameObject visualization; }
Also erstellen wir
MonsterLevel
. Es gruppiert den Preis (in Gold, den wir unten unterstützen werden) und eine visuelle Darstellung des Levels des Monsters.
Wir fügen zusätzlich zu
[System.Serializable]
damit Klasseninstanzen im Inspektor geändert werden können. Dadurch können wir schnell alle Werte der Level-Klasse ändern, auch wenn das Spiel läuft. Dies ist unglaublich nützlich, um das Spiel auszugleichen.
Monster Level einstellen
In unserem Fall speichern wir das angegebene
MonsterLevel
in
List<T>
.
Warum nicht einfach
MonsterLevel[]
? Wir benötigen den Index eines bestimmten
MonsterLevel
Objekts mehrmals. Obwohl es einfach ist, Code dafür zu schreiben, müssen wir dennoch
IndexOf()
, das die
Lists
Funktionalität implementiert. Es macht keinen Sinn, das Rad neu zu erfinden.
Das Fahrrad neu zu erfinden ist normalerweise eine schlechte Idee.Fügen Sie oben in
MonsterData.cs using
Konstrukts Folgendes hinzu:
using System.Collections.Generic;
Es gibt uns Zugriff auf verallgemeinerte Datenstrukturen, sodass wir die
List<T>
-Klasse im Skript verwenden können.
Hinweis : Verallgemeinerungen sind ein leistungsfähiges C # -Konzept. Mit ihnen können Sie typsichere Datenstrukturen angeben, ohne den Typ einhalten zu müssen. Dies ist nützlich für Containerklassen wie Listen und Mengen. Weitere Informationen zu generischen Strukturen finden Sie im Buch Einführung in C # Generics .
MonsterLevel
nun
MonsterData
die folgende Variable hinzu, um die
MonsterLevel
Liste zu
MonsterLevel
:
public List<MonsterLevel> levels;
Dank Verallgemeinerungen können wir garantieren, dass die
List
von
level
nur
MonsterLevel
Objekte enthält.
Speichern Sie die Datei und wechseln Sie zu Unity, um die einzelnen Ebenen zu konfigurieren.
Wählen Sie
Prefabs / Monster im
Projektbrowser . Der
Inspektor zeigt jetzt das Feld
Ebenen der
MonsterData (Script) -Komponente an. Stellen Sie die
Größe auf
3 ein .
Als nächstes legen Sie die
Kosten für jede Ebene fest:
- Element 0 : 200
- Element 1 : 110
- Element 2 : 120
Jetzt weisen wir die Werte der visuellen Anzeigefelder zu.
Erweitern Sie
Prefabs / Monster im Projektbrowser, um die
untergeordneten Elemente
anzuzeigen . Ziehen Sie das
untergeordnete Monster0 in das Feld
Visualisierungselement 0 .
Als nächstes setzen Sie
Element 1 auf
Monster1 und
Element 2 auf
Monster2 . Das GIF zeigt diesen Prozess:
Wenn Sie
Prefabs / Monster auswählen, sollte das Prefab folgendermaßen aussehen:
Aktuelle Stufe einstellen
Gehen Sie in der IDE zurück zu
MonsterData.cs und fügen Sie
MonsterData
eine weitere Variable hinzu.
private MonsterLevel currentLevel;
In der privaten Variablen
currentLevel
speichern wir das aktuelle Level des Monsters.
currentLevel
Sie nun
currentLevel
und machen Sie es für andere Skripte sichtbar. Fügen Sie
MonsterData
die folgenden Zeilen zusammen mit der Deklaration von Instanzvariablen hinzu:
Ziemlich großer Teil des C # -Codes, oder? Nehmen wir es in der Reihenfolge:
currentLevel
Sie die Eigenschaft der privaten Variablen currentLevel
. Durch Festlegen der Eigenschaft können wir sie wie jede andere Variable aufrufen: entweder als CurrentLevel
(innerhalb der Klasse) oder als monster.CurrentLevel
(außerhalb). Wir können jedes Verhalten in der Getter- oder Setter-Methode einer Eigenschaft definieren, und indem wir nur einen Getter, Setter oder beide erstellen, können wir die Eigenschaften der Eigenschaft steuern: schreibgeschützt, schreibgeschützt und schreiben / lesen.- Im Getter geben wir den Wert von
currentLevel
. - Im Setter weisen wir
currentLevel
neuen Wert zu. Dann erhalten wir den Index des aktuellen Niveaus. Schließlich durchlaufen wir alle Ebenen und aktivieren / deaktivieren die visuelle Anzeige abhängig von currentLevelIndex
. Dies ist großartig, da das Sprite automatisch aktualisiert wird, wenn sich currentLevel
ändert. Eigenschaften sind eine sehr bequeme Sache!
Fügen Sie die folgende
OnEnable
Implementierung hinzu:
void OnEnable() { CurrentLevel = levels[0]; }
Hier setzen wir
CurrentLevel
beim Platzieren. Dadurch wird sichergestellt, dass nur das gewünschte Sprite angezeigt wird.
Hinweis : Es ist wichtig, die Eigenschaft in OnEnable
und nicht in OnStart
zu initialisieren, da beim Erstellen vorgefertigter Instanzen die Ordnungsmethoden aufgerufen werden.
OnEnable
wird sofort aufgerufen, wenn das Fertighaus erstellt wird (wenn das Fertighaus im aktivierten Zustand gespeichert wurde), OnStart
erst aufgerufen, wenn das Objekt als Teil der Szene ausgeführt wird.
Wir müssen diese Daten überprüfen, bevor wir das Monster platzieren, also initialisieren wir sie auf OnEnable
.
Speichern Sie die Datei und kehren Sie zu Unity zurück. Führe das Projekt aus und platziere die Monster. Sie zeigen jetzt die richtigen Sprites der untersten Ebene an.
Monster Upgrade
Kehren Sie zur IDE zurück und fügen Sie
MonsterData
die folgende Methode hinzu:
public MonsterLevel GetNextLevel() { int currentLevelIndex = levels.IndexOf (currentLevel); int maxLevelIndex = levels.Count - 1; if (currentLevelIndex < maxLevelIndex) { return levels[currentLevelIndex+1]; } else { return null; } }
In
GetNextLevel
wir den
currentLevel
Index und den Index der höchsten Ebene. Wenn das Monster das maximale Level nicht erreicht hat, kehrt das nächste Level zurück. Andernfalls wird
null
zurückgegeben.
Mit dieser Methode kannst du herausfinden, ob ein Monster-Upgrade möglich ist.
Füge die folgende Methode hinzu, um das Level des Monsters zu erhöhen:
public void IncreaseLevel() { int currentLevelIndex = levels.IndexOf(currentLevel); if (currentLevelIndex < levels.Count - 1) { CurrentLevel = levels[currentLevelIndex + 1]; } }
Hier erhalten wir den Index der aktuellen Ebene und stellen dann sicher, dass dies nicht die maximale Ebene ist. Überprüfen Sie, ob diese unter den Ebenen liegt.
levels.Count - 1
. Wenn ja,
CurrentLevel
auf die nächste Stufe.
Überprüfen der Upgrade-Funktionalität
Speichern Sie die Datei und kehren
Sie in der IDE zu
PlaceMonster.cs zurück. Fügen Sie eine neue Methode hinzu:
private bool CanUpgradeMonster() { if (monster != null) { MonsterData monsterData = monster.GetComponent<MonsterData>(); MonsterLevel nextLevel = monsterData.GetNextLevel(); if (nextLevel != null) { return true; } } return false; }
Zuerst prüfen wir, ob es ein Monster gibt, das verbessert werden kann, indem wir die
monster
mit
null
. Wenn dies wahr ist, erhalten wir das aktuelle Monsterlevel aus seinen
MonsterData
.
Dann prüfen wir, ob die nächste Ebene verfügbar ist,
GetNextLevel()
ob
GetNextLevel()
nicht
null
GetNextLevel()
. Wenn eine Pegelerhöhung möglich ist, geben wir
true
. Andernfalls wird
false
.
Wir implementieren Verbesserungen für Gold
OnMouseUp
zum Aktivieren der Upgrade-Option den Zweig
else if
zu
OnMouseUp
:
if (CanPlaceMonster()) {
Wir prüfen die Möglichkeit eines Upgrades mit
CanUpgradeMonster()
. Wenn möglich, greifen wir mit
GetComponent()
auf die
MonsterData
Komponente zu und rufen
IncreaseLevel()
, wodurch sich das Level des Monsters erhöht. Schließlich starten wir die Monster
AudioSource .
Speichern Sie die Datei und kehren Sie zu Unity zurück. Führe das Spiel aus, platziere und verbessere eine
beliebige Anzahl von Monstern (aber vorerst).
Gold bezahlen - Game Manager
Wir können zwar sofort Monster bauen und verbessern, aber wird es im Spiel interessant sein?
Schauen wir uns das Thema Gold an. Das Problem beim Verfolgen ist, dass wir Informationen zwischen verschiedenen Spielobjekten übertragen müssen.
Die folgende Abbildung zeigt alle Objekte, die daran teilnehmen sollen.
Alle ausgewählten Spielobjekte müssen wissen, wie viel Gold ein Spieler hat.Um diese Daten zu speichern, verwenden wir ein gemeinsames Objekt, auf das andere Objekte zugreifen können.
Klicken Sie mit der rechten Maustaste auf die
Hierarchie und wählen
Sie Leer erstellen .
Benennen Sie das neue
GameManager- Objekt.
Fügen
Sie GameManager ein neues
C # -Skript mit dem Namen
GameManagerBehavior hinzu und öffnen Sie es in der IDE. Wir zeigen die Gesamtmenge an Spielergold auf dem Etikett an. Fügen Sie daher oben in der Datei die folgende Zeile hinzu:
using UnityEngine.UI;
Auf diese Weise können wir auf UI-Klassen wie
Text
zugreifen, die für Beschriftungen verwendet werden. Fügen Sie nun der Klasse die folgende Variable hinzu:
public Text goldLabel;
Es wird ein Link zur
Text
gespeichert, mit der die Goldmenge eines Spielers angezeigt wird.
GameManager
wir den
GameManager
über das Etikett
GameManager
, wie synchronisieren wir die in der Variablen gespeicherte Goldmenge und den auf dem Etikett angezeigten Wert? Wir werden eine Immobilie erstellen.
Fügen Sie
GameManagerBehavior
den folgenden Code
GameManagerBehavior
:
private int gold; public int Gold { get { return gold; } set { gold = value; goldLabel.GetComponent<Text>().text = "GOLD: " + gold; } }
Kommt er mir bekannt vor? Der Code ähnelt
CurrentLevel
, den wir in
Monster
. Zuerst erstellen wir eine private Variable
gold
, um die aktuelle
gold
zu halten. Dann setzen wir die
Gold
Eigenschaft (unerwartet, richtig?) Und implementieren den Getter und Setter.
Der Getter gibt einfach den Wert von
gold
. Der Setter ist interessanter. Zusätzlich zum Festlegen des Werts der Variablen wird auch das
text
für
goldLabel
, um den neuen Goldwert anzuzeigen.
Wie großzügig werden wir sein? Fügen Sie
Start()
die folgende Zeile hinzu, um dem Spieler
1000 Gold oder weniger zu geben, wenn Ihnen das Geld leid tut:
Gold = 1000;
Zuweisen eines Beschriftungsobjekts zu einem Skript
Speichern Sie die Datei und kehren Sie zu Unity zurück.
Wählen Sie in der
Hierarchie GameManager aus . Klicken Sie im
Inspektor auf den Kreis rechts neben dem
Goldetikett .
Wählen Sie im Dialogfeld
Text auswählen die Registerkarte
Szene und dann
GoldLabel .
Führen Sie die Szene aus und auf dem Etikett wird
Gold: 1000 angezeigt.
Überprüfen der "Brieftasche" des Players
Öffnen Sie das Skript
PlaceMonster.cs in der IDE und fügen Sie die folgende Instanzvariable hinzu:
private GameManagerBehavior gameManager;
Wir werden
gameManager
um auf die
GameManagerBehavior
Komponente des
GameManagerBehavior
Objekts
in der Szene
GameManagerBehavior
. Fügen Sie
Start()
Folgendes hinzu, um es anzugeben:
gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
Mit der Funktion
GameObject.Find()
wir ein GameObject namens GameManager, das das erste mit diesem Namen gefundene Spielobjekt zurückgibt. Dann holen wir uns die Komponente
GameManagerBehavior
und speichern sie für die Zukunft.
Hinweis : Sie können dies tun, indem Sie im Unity-Editor ein Feld GameManager
oder GameManager
eine statische Methode GameManager
, die eine Instanz des Singletons GameManager
, von dem wir GameManagerBehavior
.
In dem oben gezeigten Codeblock gibt es jedoch ein dunkles Pferd: die Find
Methode, die während der Anwendungsausführung langsamer arbeitet; aber es ist bequem und kann in Maßen verwendet werden.
Nimm mein Geld!
Wir haben Gold noch nicht subtrahiert, daher werden wir diese Zeile
zweimal zu
OnMouseUp()
hinzufügen und jeden der Kommentare ersetzen
// TODO:
:
gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost;
Speichern Sie die Datei und kehren Sie zu Unity zurück, aktualisieren Sie einige Monster und sehen Sie sich die Aktualisierung des Goldwerts an. Jetzt ziehen wir Gold ab, aber Spieler können Monster bauen, solange sie genug Platz haben. Sie leihen sich einfach Geld aus.
Unendlicher Kredit? Großartig! Aber wir können es nicht zulassen. Der Spieler muss in der Lage sein, Monster zu setzen, solange er genug Gold hat.Goldcheck für Monster
Wechseln Sie in der IDE zu
PlaceMonster.cs und ersetzen Sie den Inhalt von
CanPlaceMonster()
Folgendes:
int cost = monsterPrefab.GetComponent<MonsterData>().levels[0].cost; return monster == null && gameManager.Gold >= cost;
Wir
MonsterData
Monsterplatzierungspreis aus den
levels
in den
MonsterData
. Dann überprüfen wir, dass das
monster
nicht
null
ist und dass
gameManager.Gold
mehr als diesen Preis ist.
Die Aufgabe für Sie:
CanUpgradeMonster()
Sie
CanUpgradeMonster()
unabhängig
CanUpgradeMonster()
Überprüfung hinzu, ob der Spieler über genügend Gold verfügt.
Lösung im InnerenErsetzen Sie die Leitung:
return true;
dazu:
return gameManager.Gold >= nextLevel.cost;
Es wird geprüft, ob der Spieler mehr
Gold als den Upgrade-Preis hat.
Speichern Sie die Szene und führen Sie sie in Unity aus. Versuchen Sie nun, Monster unbegrenzt hinzuzufügen!
Jetzt können wir nur eine begrenzte Anzahl von Monstern bauen.Turmpolitik: Feinde, Wellen und Wegpunkte
Es ist Zeit, unseren Feinden den Weg zu ebnen. Feinde erscheinen am ersten Punkt der Route, gehen zum nächsten und wiederholen den Vorgang, bis sie den Cookie erreichen.
Sie können Feinde so bewegen:
- Stellen Sie die Straße ein, der die Feinde folgen sollen
- Bewegen Sie den Feind entlang der Straße
- Drehe den Feind so, dass er nach vorne schaut
Erstellen einer Straße aus Wegpunkten
Klicken Sie mit der rechten Maustaste auf die
Hierarchie und wählen
Sie "Leer erstellen", um ein neues leeres Spielobjekt zu erstellen. Nennen Sie es
Straße und positionieren Sie es bei
(0, 0, 0) .
Klicken Sie nun mit der rechten Maustaste auf
Straße in der
Hierarchie und erstellen Sie ein weiteres leeres Spielobjekt als Kind von Straße. Nennen Sie es
Wegpunkt0 und platzieren Sie es am Punkt
(-12, 2, 0) - von hier aus beginnen die Feinde ihre Bewegung.
Erstellen Sie auf ähnliche Weise fünf weitere Routenpunkte mit den folgenden Namen und Positionen:
- Wegpunkt 1: (X: 7, Y: 2, Z: 0)
- Wegpunkt 2: (X: 7, Y: -1, Z: 0)
- Wegpunkt 3: (X: -7,3, Y: -1, Z: 0)
- Wegpunkt 4: (X: -7,3, Y: -4,5, Z: 0)
- Wegpunkt 5: (X: 7, Y: -4,5, Z: 0)
Der Screenshot unten zeigt die Routenpunkte und den resultierenden Pfad.
Feinde machen
Erstellen Sie nun einige Feinde, damit sie sich entlang der Straße bewegen können. Im
Prefabs- Ordner befindet sich ein
Enemy- Fertighaus. Die Position ist
(-20, 0, 0) , sodass neue Instanzen außerhalb des Bildschirms erstellt werden.
Im Übrigen ist es fast genauso konfiguriert wie das Monster-Fertighaus, verfügt über
AudioSource
und ein
Sprite
Kind, und wir können dieses Sprite in Zukunft drehen, ohne die Gesundheitsleiste zu drehen.
Wir bewegen Feinde entlang der Straße
Fügen
Sie dem
Prefabs \ Enemy Prefab ein neues
C # -Skript mit dem Namen
MoveEnemy hinzu . Öffnen Sie das Skript in der IDE und fügen Sie die folgenden Variablen hinzu:
[HideInInspector] public GameObject[] waypoints; private int currentWaypoint = 0; private float lastWaypointSwitchTime; public float speed = 1.0f;
In
waypoints
wird eine Kopie der Routenpunkte im Array gespeichert, und die
[HideIn inspector ]
über den
waypoints
stellt sicher, dass wir dieses Feld im
Inspector nicht versehentlich ändern können, aber weiterhin über andere Skripts darauf zugreifen können.
currentWaypoint
verfolgt, woher die Route des Feindes zur aktuellen Zeit stammt, und
lastWaypointSwitchTime
speichert die Zeit, die der Feind durchlaufen hat. Außerdem speichern wir die
speed
Feindes.
Fügen Sie diese Zeile zu
Start()
:
lastWaypointSwitchTime = Time.time;
Also initialisieren wir
lastWaypointSwitchTime
mit dem Wert der aktuellen Zeit.
Update()
den folgenden Code hinzu, damit sich der Feind entlang der Route bewegen kann:
Lassen Sie uns den Code Schritt für Schritt analysieren:
- Aus dem Array von Routenpunkten erhalten wir die Start- und Endpositionen des aktuellen Routensegments.
- Wir berechnen die Zeit, die erforderlich ist, um die gesamte Strecke zurückzulegen, anhand der Formel Zeit = Entfernung / Geschwindigkeit und bestimmen dann die aktuelle Zeit auf der Route. Mit
Vector2.Lerp
interpolieren wir die aktuelle Position des Feindes zwischen dem exakten Start- und Endsegment. - Überprüfen Sie, ob der Feind die
endPosition
erreicht endPosition
. Wenn ja, verarbeiten wir zwei mögliche Szenarien:
- Der Feind hat den letzten Punkt der Route noch nicht erreicht. Erhöhen Sie daher den Wert von
currentWaypoint
und aktualisieren Sie lastWaypointSwitchTime
. Später werden wir einen Code hinzufügen, um den Feind so zu drehen, dass er in die Richtung seiner Bewegung schaut. - Der Feind hat den letzten Punkt der Route erreicht, dann zerstören wir ihn und starten den Soundeffekt. Später werden wir einen Code hinzufügen, der die
health
des Spielers verringert.
Speichern Sie die Datei und kehren Sie zu Unity zurück.
Wir informieren die Feinde über die Bewegungsrichtung
In ihrem aktuellen Zustand kennen die Feinde die Reihenfolge der Routenpunkte nicht.
Wählen Sie
Straße in der
Hierarchie aus und fügen Sie ein neues
C # -Skript mit dem Namen
SpawnEnemy hinzu . Öffnen Sie es in der IDE und fügen Sie die folgende Variable hinzu:
public GameObject[] waypoints;
Wir werden
waypoints
, um Verweise auf den Wegpunkt in der Szene in der gewünschten Reihenfolge zu speichern.
Speichern Sie die Datei und kehren Sie zu Unity zurück. Wählen Sie in der
Hierarchie Straße aus und setzen Sie die
Größe des Wegpunkt- Arrays auf
6 .
Ziehen Sie jedes der Road-Kinder in die Felder, indem Sie
Waypoint0 in
Element 0 ,
Waypoint1 in
Element 1 usw.
einfügen .
Jetzt haben wir ein Array, das die Routenpunkte in der richtigen Reihenfolge enthält - wohlgemerkt, die Feinde ziehen sich nie zurück, sie streben beharrlich nach einer süßen Belohnung.
Überprüfen Sie, wie alles funktioniert
Öffnen Sie
SpawnEnemy in der IDE und fügen Sie die folgende Variable hinzu:
public GameObject testEnemyPrefab;
In
testEnemyPrefab
wird ein Verweis auf das
Enemy- testEnemyPrefab
.
Fügen Sie
Start()
den folgenden Code hinzu, um beim Ausführen des Skripts einen Feind zu erstellen:
Instantiate(testEnemyPrefab).GetComponent<MoveEnemy>().waypoints = waypoints;
Daher erstellen wir eine neue Kopie des in testEnemy gespeicherten
testEnemy
und weisen ihm eine Route zu.
Speichern Sie die Datei und kehren Sie zu Unity zurück. Wählen Sie das
Road- Objekt in der
Hierarchie aus und wählen Sie das Prefab
Enemy für den Parameter
Test Enemy aus .
Starten Sie das Projekt und sehen Sie, wie sich der Feind auf der Straße bewegt (in GIF wird die Geschwindigkeit aus Gründen der Übersichtlichkeit um das 20-fache erhöht).Bemerkt, dass er nicht immer hinschaut, wohin er geht? Es ist lustig, aber wir versuchen ein professionelles Spiel zu machen. Daher werden wir im zweiten Teil des Tutorials den Feinden beibringen, nach vorne zu schauen.Wohin als nächstes?
Wir haben bereits viel getan und sind schnell dabei, unser eigenes Tower Defense-Spiel zu entwickeln.Spieler können eine begrenzte Anzahl von Monstern erschaffen, und der Feind rennt die Straße entlang und geht auf unseren Keks zu. Spieler haben Gold und können Monster verbessern.Laden Sie das fertige Ergebnis hier herunter .Im zweiten Teil werden wir die Entstehung riesiger Wellen von Feinden und deren Zerstörung betrachten. Bis dann!