Dies ist der zweite Teil des Tutorials
„Erstellen eines Tower Defense-Spiels in Unity“ . Wir entwickeln in Unity ein Tower Defense-Genre-Spiel und am Ende des
ersten Teils haben wir gelernt, wie man Monster platziert und verbessert. Wir haben auch einen Feind, der Cookies angreift.
Der Feind weiß jedoch noch nicht, wo er suchen soll! Außerdem sieht ein Angriff allein seltsam aus. In diesem Teil des Tutorials werden wir Wellen von Feinden und Armmonstern hinzufügen, damit diese einen wertvollen Keks verteidigen können.
An die Arbeit gehen
Öffnen Sie das Projekt in Unity, das wir im letzten Teil gestoppt haben. Wenn Sie gerade zu uns gekommen sind, laden Sie den
Projektentwurf herunter und öffnen Sie
TowerDefense-Part2-Starter .
Öffne
GameScene aus dem Ordner "
Szenen ".
Wende Feinde ab
Am Ende des vorherigen Tutorials lernte der Feind, sich auf der Straße zu bewegen, aber es scheint, dass er keine Ahnung hat, wo er suchen soll.
Öffnen Sie das Skript
MoveEnemy.cs in der IDE und fügen Sie die folgende Methode hinzu, um die Situation zu beheben.
private void RotateIntoMoveDirection() {
RotateIntoMoveDirection
dreht den Feind so, dass er immer
RotateIntoMoveDirection
vorne
RotateIntoMoveDirection
. Er macht es wie folgt:
- Berechnet die aktuelle Richtung des Fehlers, indem die Position des aktuellen Wegpunkts von der Position des nächsten Punkts abgezogen wird.
- Verwendet
Mathf.Atan2
, um den Winkel im Bogenmaß zu bestimmen, in den Mathf.Atan2
gerichtet ist (der Nullpunkt befindet sich rechts). Multipliziert das Ergebnis mit 180 / Mathf.PI
und konvertiert den Winkel in Grad. - Schließlich erhält es das Sprite- Kind und dreht die Achse um Winkelwinkel. Beachten Sie, dass wir das Kind und nicht das Elternteil drehen, damit der Energiestreifen, den wir später hinzufügen, horizontal bleibt.
Ersetzen Sie in
Update()
den Kommentar
// TODO:
nächsten Aufruf von
RotateIntoMoveDirection
:
RotateIntoMoveDirection();
Speichern Sie die Datei und kehren Sie zu Unity zurück. Führen Sie die Szene aus; Jetzt weiß der Feind, wohin er sich bewegt.
Jetzt weiß der Fehler, wohin es geht.
Der einzige Feind sieht nicht sehr beeindruckend aus. Wir brauchen Horden! Und wie in jedem Tower Defense-Spiel laufen Horden in Wellen!
Spieler informieren
Bevor wir anfangen, die Horden zu bewegen, müssen wir den Spieler vor dem bevorstehenden Kampf warnen. Außerdem lohnt es sich, die aktuelle Wellenzahl oben auf dem Bildschirm anzuzeigen.
Wave- Informationen werden von mehreren GameObjects benötigt, daher werden sie der
GameManagerBehavior- Komponente des
GameManager hinzugefügt .
Öffnen Sie die
GameManagerBehavior.cs in der IDE und fügen Sie die folgenden zwei Variablen hinzu:
public Text waveLabel; public GameObject[] nextWaveLabels;
waveLabel
speichert einen Link zum Wellenzahl-Ausgabeetikett in der oberen rechten Ecke des Bildschirms.
nextWaveLabels
speichert zwei GameObjects, die eine Kombination von Animationen erstellen, die wir zu Beginn einer neuen Welle zeigen werden:
Speichern Sie die Datei und kehren Sie zu Unity zurück. Wählen Sie
GameManager in der
Hierarchie . Klicken Sie auf den Kreis rechts neben der
Wellenbeschriftung und wählen
Sie im Dialogfeld
Text auswählen
auf der Registerkarte
Szene die
Option Wellenbeschriftung aus.
Stellen Sie nun die
Größe für die
Beschriftungen der nächsten Welle auf
2 ein . Setzen Sie nun
Element 0 auf
NextWaveBottomLabel , und für
Element 1 ist NextWaveTopLabel dasselbe wie bei Wave Label.
So sollte das Verhalten von Game Managern jetzt aussehenWenn der Spieler verliert, sollte er keine Nachricht über die nächste Welle sehen. Um diese Situation zu bewältigen, kehren Sie zu
GameManagerBehavior.cs zurück und fügen Sie eine weitere Variable hinzu:
public bool gameOver = false;
In
gameOver
speichern wir den Wert, ob der Spieler verloren hat.
Hier verwenden wir wieder die Eigenschaft, um die Elemente des Spiels mit der aktuellen Welle zu synchronisieren. Fügen Sie
GameManagerBehavior
den folgenden Code
GameManagerBehavior
:
private int wave; public int Wave { get { return wave; } set { wave = value; if (!gameOver) { for (int i = 0; i < nextWaveLabels.Length; i++) { nextWaveLabels[i].GetComponent<Animator>().SetTrigger("nextWave"); } } waveLabel.text = "WAVE: " + (wave + 1); } }
Das Erstellen einer privaten Variablen, einer Eigenschaft und eines Getters sollte Ihnen bereits vertraut sein. Aber mit dem Setter ist wieder alles etwas interessanter.
Wir weisen
wave
neuen
value
.
Dann prüfen wir, ob das Spiel beendet ist. Wenn nicht, durchlaufen Sie alle
nextWaveLabels- Labels - diese Labels haben eine
Animator- Komponente. Um die
Animator- Animation zu aktivieren,
definieren wir einen
nextWave- Trigger.
Schließlich setzen wir den
text
von
waveLabel
auf
wave + 1
. Warum
+1
? Normale Leute zählen nicht von vorne (ja, das ist seltsam).
In
Start()
den Wert dieser Eigenschaft:
Wave = 0;
Wir beginnen die Zählung mit der Nummer
0 Wave
.
Speichern Sie die Datei und führen Sie die Szene in Unity aus. Das Wave-Label zeigt 1 korrekt an.
Für einen Spieler beginnt alles mit Welle 1.Wellen: Erschaffe Haufen von Feinden
Es mag offensichtlich erscheinen, aber um mit einer Horde anzugreifen, müssen mehr Feinde geschaffen werden - obwohl wir nicht wissen, wie das geht. Außerdem sollten wir die nächste Welle erst erzeugen, wenn die aktuelle zerstört ist.
Das heißt, das Spiel sollte in der Lage sein, die Anwesenheit von Feinden in der Szene zu erkennen, und
Tags sind eine gute Möglichkeit, Spielobjekte hier zu identifizieren.
Feindliche Markierung
Wählen Sie im Projektbrowser das
Enemy- Fertighaus aus. Klicken Sie oben im
Inspektor auf die Dropdown-Liste
Tag und wählen
Sie Tag hinzufügen .
Erstellen Sie ein
Tag namens
Enemy .
Wählen Sie den vorgefertigten
Feind . Legen Sie im
Inspektor das Enemy- Tag dafür fest.
Wellen von Feinden definieren
Jetzt müssen wir die Welle der Feinde einstellen. Öffnen Sie
SpawnEnemy.cs in der IDE und fügen Sie vor
SpawnEnemy
die folgende Klassenimplementierung
SpawnEnemy
:
[System.Serializable] public class Wave { public GameObject enemyPrefab; public float spawnInterval = 2; public int maxEnemies = 20; }
Wave enthält
enemyPrefab
- die Basis zum Erstellen von Instanzen aller Feinde in dieser Welle,
spawnInterval
- Zeit zwischen Feinden in der Welle in Sekunden und
maxEnemies
- die Anzahl der in dieser Welle erstellten Feinde.
Die Klasse ist
serialisierbar ,
dh wir können ihre Werte im Inspektor ändern.
Fügen Sie der
SpawnEnemy
Klasse die folgenden Variablen
SpawnEnemy
:
public Wave[] waves; public int timeBetweenWaves = 5; private GameManagerBehavior gameManager; private float lastSpawnTime; private int enemiesSpawned = 0;
Hier legen wir die Variablen für das Laichen von Feinden fest, was sehr ähnlich ist, wie wir Feinde zwischen Punkten auf der Route bewegt haben.
Wir setzen die Wellen einzelner Feinde in
waves
und verfolgen die Anzahl der erstellten Feinde und die Zeit, zu der sie in den
enemiesSpawned
und
lastSpawnTime
.
Nach all diesen Kills brauchen die Spieler Zeit zum Atmen, also setzen Sie
timeBetweenWaves
auf 5 Sekunden.
Ersetzen Sie den Inhalt von
Start()
folgenden Code.
lastSpawnTime = Time.time; gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
Hier weisen wir
lastSpawnTime
Wert der aktuellen Zeit zu,
lastSpawnTime
Zeit, zu der das Skript nach dem Laden der Szene gestartet wurde. Dann bekommen wir das bereits bekannte
GameManagerBehavior
.
Fügen Sie
Update()
den folgenden Code hinzu:
Lassen Sie es uns Schritt für Schritt analysieren:
- Wir erhalten den Index der aktuellen Welle und prüfen, ob es die letzte ist.
- Wenn ja, berechnen wir die Zeit, die nach dem vorherigen Spawn des Feindes vergangen ist, und prüfen, ob es Zeit ist, einen Feind zu erschaffen. Hier berücksichtigen wir zwei Fälle. Wenn dies der erste Feind in der Welle ist, prüfen wir, ob
timeInterval
als timeBetweenWaves
. Andernfalls prüfen wir, ob timeInterval
als spawnInterval
Wellen ist. In jedem Fall überprüfen wir, ob wir nicht alle Feinde in dieser Welle erschaffen haben. - Wenn nötig,
enemyPrefab
den Feind und erstelle eine Instanz von enemyPrefab
. Erhöhen Sie auch den Wert von enemiesSpawned
. - Überprüfen Sie die Anzahl der Feinde auf dem Bildschirm. Wenn sie nicht da sind und dies der letzte Feind in der Welle war, dann erschaffen wir die nächste Welle. Ebenfalls am Ende der Welle geben wir dem Spieler 10 Prozent des gesamten verbleibenden Goldes.
- Nach dem Sieg über die letzte Welle wird hier eine Animation des Sieges im Spiel abgespielt.
Spawn-Intervalle einstellen
Speichern Sie die Datei und kehren Sie zu Unity zurück. Wählen Sie das Straßenobjekt in der
Hierarchie aus . Setzen Sie im
Inspektor die
Größe des
Waves- Objekts auf
4 .
Wählen Sie zunächst ein
Enemy- Objekt für alle vier Elemente als
Enemy Prefab aus . Konfigurieren Sie die Felder
Spawn Interval und
Max Enemies wie folgt:
- Element 0 : Spawn-Intervall: 2,5 , Max. Gegner: 5
- Element 1 : Spawn-Intervall: 2 , Max. Gegner: 10
- Element 2 : Spawn-Intervall: 2 , Max. Gegner: 15
- Element 3 : Spawn-Intervall: 1 , Max. Gegner: 5
Das fertige Schema sollte folgendermaßen aussehen:
Natürlich können Sie mit diesen Werten experimentieren, um die Komplexität zu erhöhen oder zu verringern.
Starte das Spiel. Ja! Käfer haben die Reise zu Ihrem Keks begonnen!
Zusätzliche Aufgabe: Füge verschiedene Arten von Feinden hinzu
Kein Turmverteidigungsspiel kann als vollständig mit nur einem Feindtyp betrachtet werden. Glücklicherweise gibt es auch
Enemy2 im
Prefabs- Ordner.
Wählen Sie im
Inspektor Prefabs \ Enemy2 aus und fügen Sie das
MoveEnemy- Skript hinzu. Stellen Sie die
Geschwindigkeit auf
3 und
das Enemy- Tag ein . Jetzt können Sie diesen schnellen Feind verwenden, damit sich der Spieler nicht entspannt!
Player Life Update
Obwohl Horden von Feinden den Cookie angreifen, erleidet der Spieler keinen Schaden. Aber bald werden wir es beheben. Der Spieler muss leiden, wenn er dem Feind erlaubt, sich anzuschleichen.
Öffnen Sie die
GameManagerBehavior.cs in der IDE und fügen Sie die folgenden zwei Variablen hinzu:
public Text healthLabel; public GameObject[] healthIndicator;
Wir verwenden
healthLabel
um auf den Lebenswert des Spielers zuzugreifen, und
healthIndicator
um auf die fünf kleinen grünen Monster zuzugreifen, die Kekse kauen - sie symbolisieren einfach die Gesundheit des Spielers. Es ist lustiger als ein Standard-Gesundheitsindikator.
Gesundheitsmanagement
GameManagerBehavior
nun eine Eigenschaft hinzu, die die Gesundheit des Spielers in
GameManagerBehavior
:
private int health; public int Health { get { return health; } set {
So verwalten wir die Gesundheit des Spielers. Und wieder befindet sich der Hauptteil des Codes im Setter:
- Wenn wir die Gesundheit des Spielers verringern, verwenden wir die
CameraShake
Komponente, um einen schönen Schütteleffekt zu erzielen. Dieses Skript ist im herunterladbaren Projekt enthalten und wird hier nicht berücksichtigt. - Wir aktualisieren die private Variable und das Health-Label in der oberen linken Ecke des Bildschirms.
- Wenn der Gesundheitszustand auf 0 gesunken ist und das Ende des Spiels noch nicht erreicht ist,
gameOver
auf true
und starten Sie die gameOver
Animation. - Wir entfernen eines der Monster aus den Keksen. Wenn wir sie nur ausschalten, kann dieser Teil einfacher geschrieben werden, aber hier unterstützen wir die Wiedereingliederung, falls die Gesundheit hinzugefügt wird.
Wir initialisieren
Health
in
Start()
:
Health = 5;
Wir setzen
Health
auf
5
wenn die Szene abgespielt wird.
Nachdem wir dies alles getan haben, können wir jetzt den Zustand des Players aktualisieren, wenn der Fehler im Cookie auftritt. Speichern Sie die Datei und
wechseln Sie zur IDE zum Skript
MoveEnemy.cs .
Gesundheitsveränderung
Um Ihre Gesundheit zu ändern, suchen Sie den Kommentar in
Update()
mit den Worten
// TODO:
und durch diesen Code ersetzen:
GameManagerBehavior gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>(); gameManager.Health -= 1;
Also bekommen wir das
GameManagerBehavior
und subtrahieren die Einheit von ihrer
Health
.
Speichern Sie die Datei und kehren Sie zu Unity zurück.
Wählen Sie einen
GameManager in der
Hierarchie aus und wählen Sie
HealthLabel als
Health Label aus .
Erweitern Sie das
Cookie- Objekt in der
Hierarchie und ziehen Sie die fünf
untergeordneten HealthIndicators in das
Health Indicator- Array des
GameManager. Die Health-Indikatoren sind kleine grüne Monster, die Cookies essen.
Führen Sie die Szene aus und warten Sie, bis die Fehler den Cookie erreichen. Tu nichts, bis du verlierst.
Monster Rache
Monster an Ort und Stelle? Ja Angreifen Feinde? Ja, und sie sehen bedrohlich aus! Es ist Zeit, diese Tiere zu beantworten!
Dazu benötigen wir Folgendes:
- Spur der Gesundheit, damit der Spieler weiß, welche Feinde stark und welche schwach sind
- Feinde in Reichweite eines Monsters erkennen
- Eine Entscheidung treffen - auf welchen Feind geschossen werden soll
- Ein paar Muscheln
Feindliche Gesundheitsleiste
Um das Gesundheitsband zu implementieren, verwenden wir zwei Bilder - eines für den dunklen Hintergrund und das zweite (der grüne Balken ist etwas kleiner) skalieren wir entsprechend der Gesundheit des Feindes.
Ziehen Sie vom
Projektbrowser in die Szene
Prefabs \ Enemy .
Ziehen Sie dann in der
Hierarchie Images \ Objects \ HealthBarBackground auf
Enemy , um es als
untergeordnetes Element hinzuzufügen.
Setzen Sie im
Inspektor die
Position des HealthBarBackground auf
(0, 1, -4) .
Wählen Sie dann im
Projektbrowser Images \ Objects \ HealthBar aus und stellen Sie sicher, dass der
Pivot links ist .
Fügen Sie es dann als
untergeordnetes Element des
Feindes in die
Hierarchie ein und setzen Sie seinen
Positionswert (-0,63, 1, -5) . Setzen Sie für
X Scale den Wert auf
125 .
Fügen Sie
dem HealthBar -Spielobjekt ein neues
C # -Skript mit dem Namen HealthBar hinzu . Später werden wir es so ändern, dass es die Länge des Gesundheitsbalkens ändert.
Stellen Sie nach Auswahl eines
feindlichen Objekts in der
Hierarchie sicher, dass seine Position
(20, 0, 0) ist .
Klicken
Sie oben im
Inspektor auf Übernehmen, um alle Änderungen als Teil des Fertighauses zu speichern. Löschen Sie abschließend das
Enemy- Objekt in der
Hierarchie .
Wiederholen Sie nun alle diese Schritte, um eine
Integritätsleiste für
Prefabs \ Enemy2 hinzuzufügen .
Ändern Sie die Länge der Gesundheitsleiste
Öffnen Sie die IDE
HealthBar.cs und fügen Sie die folgenden Variablen hinzu:
public float maxHealth = 100; public float currentHealth = 100; private float originalScale;
In
maxHealth
die maximale Gesundheit des Feindes gespeichert und in
currentHealth
die verbleibende Gesundheit. Schließlich ist in
originalScale
die anfängliche Größe der Integritätsleiste.
Speichern Sie das
originalScale
Objekt in
Start()
:
originalScale = gameObject.transform.localScale.x;
Wir speichern den
x
Wert der
localScale
Eigenschaft.
Legen Sie die Skalierung der Integritätsleiste fest, indem Sie
Update()
den folgenden Code hinzufügen:
Vector3 tmpScale = gameObject.transform.localScale; tmpScale.x = currentHealth / maxHealth * originalScale; gameObject.transform.localScale = tmpScale;
Wir können
localScale
in eine temporäre Variable kopieren, da wir ihren
x- Wert nicht separat ändern können. Dann berechnen wir die neue
x- Skala basierend auf dem aktuellen
localScale
des Käfers und weisen den Wert
localScale
erneut einer temporären Variablen zu.
Speichern Sie die Datei und starten Sie das Spiel in Unity. Über Feinden sehen Sie Gesundheitsstreifen.
Erweitern Sie während des Spiels eines der
Enemy (Clone) -Objekte in der
Hierarchie und wählen Sie die
untergeordnete HealthBar aus . Ändern Sie den
aktuellen Gesundheitswert und sehen Sie, wie sich der Gesundheitsbalken ändert.
Erkennung von Feinden in Reichweite
Jetzt müssen unsere Monster herausfinden, auf welche Feinde sie zielen sollen. Aber bevor Sie diese Gelegenheit nutzen, müssen Sie Monster und Feind vorbereiten.
Wählen Sie Project Browser
Prefabs \ Monster und fügen Sie im
Inspector die
Circle Collider 2D- Komponente hinzu.
Setze den
Radius- Parameter des Colliders auf
2,5 - dies zeigt den Angriffsradius der Monster an.
Aktivieren Sie das Kontrollkästchen
Ist Auslöser , damit Objekte diesen Bereich passieren, anstatt mit ihm zu kollidieren.
Stellen Sie schließlich oben im
Inspektor die
Ebene des Monsters so ein, dass
Raycast ignoriert wird . Klicken Sie im Dialogfeld auf
Ja, untergeordnete
Elemente ändern . Wenn Raycast ignorieren nicht ausgewählt ist, reagiert der Collider auf Mausklickereignisse. Dies wird ein Problem sein, da Monster Ereignisse blockieren, die für Openspot-Objekte unter ihnen bestimmt sind.
Um sicherzustellen, dass der Feind im Triggerbereich erkannt wird, müssen wir einen Collider und einen starren Körper hinzufügen, da Unity nur dann Triggerereignisse sendet, wenn ein starrer Körper an einem der Collider befestigt ist.
Wählen Sie im
Projektbrowser Prefabs \ Enemy aus . Fügen Sie die
Rigidbody 2D- Komponente hinzu und wählen Sie
Kinematik für
Körpertyp . Dies bedeutet, dass der Körper nicht von der Physik beeinflusst wird.
Fügen Sie
Circle Collider 2D mit einem
Radius von
1 hinzu . Wiederholen Sie diese Schritte für
Prefabs \ Enemy 2 .
Die Auslöser sind so konfiguriert, dass Monster verstehen, dass sich Feinde innerhalb ihres Aktionsradius befinden.
Wir müssen noch eines vorbereiten: ein Skript, das Monstern sagt, wenn der Feind zerstört wird, damit sie keine Ausnahme auslösen, während sie weiter schießen.
Erstellen Sie ein neues
C # -Skript mit dem Namen
EnemyDestructionDelegate und fügen Sie es den
Prefabs Enemy und
Enemy2 hinzu .
Öffnen Sie
EnemyDestructionDelegate.cs in der IDE und fügen Sie die folgende Delegierungsdeklaration hinzu:
public delegate void EnemyDelegate (GameObject enemy); public EnemyDelegate enemyDelegate;
Hier erstellen wir einen
delegate
, dh einen Container für eine Funktion, die als Variable übergeben werden kann.
Hinweis : Delegaten werden verwendet, wenn ein Spielobjekt andere Spielobjekte aktiv über Änderungen informieren muss. Weitere Informationen zu Delegierten finden Sie in der Unity-Dokumentation .
Fügen Sie die folgende Methode hinzu:
void OnDestroy() { if (enemyDelegate != null) { enemyDelegate(gameObject); } }
Wenn ein Spielobjekt zerstört wird, ruft Unity diese Methode automatisch auf und überprüft den Delegaten auf
null
. In unserem Fall rufen wir es mit
gameObject
als Parameter auf. Auf diese Weise können alle als Delegierte registrierten Befragten wissen, dass der Feind zerstört wurde.
Speichern Sie die Datei und kehren Sie zu Unity zurück.
Wir geben Monstern eine Lizenz zum Töten
Und jetzt können Monster Feinde im Radius ihrer Aktion erkennen. Fügen Sie dem
Monster- Fertighaus ein neues
C # -Skript hinzu und nennen Sie es
ShootEnemies .
Öffnen Sie
ShootEnemies.cs in der IDE und fügen Sie
using
Konstrukts Folgendes hinzu
using
um auf
Generics
zuzugreifen.
using System.Collections.Generic;
Fügen Sie eine Variable hinzu, um alle Feinde in Reichweite zu verfolgen:
public List<GameObject> enemiesInRange;
In
enemiesInRange
speichern wir alle Feinde in Reichweite.
Initialisieren Sie das Feld in
Start()
.
enemiesInRange = new List<GameObject>();
Ganz am Anfang befinden sich keine Feinde im Aktionsradius, daher erstellen wir eine leere Liste.
enemiesInRange
die Liste der
enemiesInRange
! Fügen Sie dem Skript den folgenden Code hinzu:
- In
OnEnemyDestroy
entfernen wir den Feind aus feindlicher enemiesInRange
. Wenn ein Feind auf einen Abzug um ein Monster tritt, wird OnTriggerEnter2D
. - Dann fügen wir den Feind zur
enemiesInRange
Liste hinzu und fügen das EnemyDestructionDelegate
Ereignis OnEnemyDestroy
. Wir garantieren also, dass bei Zerstörung des Feindes OnEnemyDestroy
aufgerufen wird. Wir wollen nicht, dass Monster Munition für tote Feinde ausgeben, oder? - In
OnTriggerExit2D
entfernen wir den Feind von der Liste und OnTriggerExit2D
die Registrierung des Delegaten auf. Jetzt wissen wir, welche Feinde sich in Reichweite befinden.
Speichern Sie die Datei und starten Sie das Spiel in Unity. Um sicherzustellen, dass alles funktioniert, positioniere das Monster, wähle es aus und folge den Änderungen in der
enemiesInRange
Rangliste im
enemiesInRange
.
Zielauswahl
Monster wissen jetzt, welcher Feind sich in Reichweite befindet. Aber was werden sie tun, wenn sich mehrere Feinde im Radius befinden?
Natürlich werden sie denjenigen angreifen, der der Leber am nächsten liegt!
Öffne das IDE-Skript
MoveEnemy.cs und füge eine neue Methode hinzu, mit der dieses Monster berechnet wird:
public float DistanceToGoal() { float distance = 0; distance += Vector2.Distance( gameObject.transform.position, waypoints [currentWaypoint + 1].transform.position); for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++) { Vector3 startPosition = waypoints [i].transform.position; Vector3 endPosition = waypoints [i + 1].transform.position; distance += Vector2.Distance(startPosition, endPosition); } return distance; }
Der Code berechnet die Weglänge, die der Feind noch nicht zurückgelegt hat. Dazu wird
Distance
, die als Abstand zwischen zwei Instanzen von
Vector3
.
Wir werden diese Methode später verwenden, um herauszufinden, welches Ziel angegriffen werden soll. Obwohl unsere Monster nicht bewaffnet und hilflos sind, werden wir es zuerst tun.
Speichern Sie die Datei und kehren Sie zu Unity zurück, um mit dem Einrichten Ihrer Shells zu beginnen.
Geben wir den Monstern Muscheln. Viele Muscheln!
Ziehen Sie aus dem Projektbrowser in die
Szene Images / Objects / Bullet1 . Setzen Sie die Position auf
z auf
-2 - die Positionen auf x und y sind nicht wichtig, da wir sie jedes Mal setzen, wenn wir während der Programmausführung eine neue Instanz des Projektils erstellen.
Fügen Sie ein neues
C # -Skript mit dem Namen
BulletBehavior hinzu und fügen Sie dann in der IDE die folgenden Variablen hinzu:
public float speed = 10; public int damage; public GameObject target; public Vector3 startPosition; public Vector3 targetPosition; private float distance; private float startTime; private GameManagerBehavior gameManager;
speed
bestimmt die Geschwindigkeit der Projektile; Die
damage
aus dem Namen.
target
,
startPosition
und
targetPosition
bestimmen die Richtung des Projektils.
distance
und
startTime
verfolgen die aktuelle Position des Projektils.
gameManager
belohnt den Spieler, wenn er den Feind tötet.
Weisen Sie die Werte dieser Variablen in
Start()
:
startTime = Time.time; distance = Vector2.Distance (startPosition, targetPosition); GameObject gm = GameObject.Find("GameManager"); gameManager = gm.GetComponent<GameManagerBehavior>();
startTime
Wir stellen den Wert der aktuellen Zeit ein und berechnen den Abstand zwischen Start- und Zielposition. Auch bekommen wir wie immer GameManagerBehavior
.Fügen Sie den Update()
folgenden Code hinzu, um die Bewegung des Projektils zu steuern :
- Wir berechnen die neue Position des Projektils unter Verwendung der
Vector3.Lerp
Interpolation zwischen der Start- und Endposition. - Wenn das Projektil erreicht
targetPosition
, prüfen wir, ob es noch vorhanden ist target
. - Wir erhalten die Komponente des
HealthBar
Ziels und reduzieren seine Gesundheit um die Größe des damage
Projektils. - Wenn die Gesundheit des Feindes auf Null reduziert wird, zerstören wir sie, reproduzieren den Soundeffekt und belohnen den Spieler für seine Genauigkeit.
Speichern Sie die Datei und kehren Sie zu Unity zurück.Wir machen große Muscheln
Wäre es nicht großartig, wenn das Monster mehr Granaten auf hohem Niveau abschießen würde? Glücklicherweise ist dies einfach zu implementieren.Ziehen Sie das Bullet1 -Spielobjekt aus der Hierarchie auf die Registerkarte Projekt , um ein Projektil-Fertighaus zu erstellen. Entfernen Sie das Originalobjekt aus der Szene - wir werden es nicht mehr benötigen.Duplizieren Sie das Bullet1- Fertighaus zweimal . Nennen Sie die Kopien von Bullet2 und Bullet3 .Wählen Sie Bullet2 . Setzen Sie im Inspektor das Sprite- Feld der Sprite- Renderer- Komponente auf Images / Objects / Bullet2. Also werden wir Bullet2 etwas mehr als Bullet1 machen.Wiederholen Sie den Vorgang, um das Sprite des Bullet3- Fertighauses in Images / Objects / Bullet3 zu ändern .Weiter im Bullet Behaviour werden wir die Höhe des durch Granaten verursachten Schadens anpassen.Wählen Sie das vorgefertigte Bullet1 auf der Registerkarte Projekt aus . Der Inspektor Sie sehen Einschuss Verhalten (Script) , die zugeordnet werden können Damage Wert 10 für Bullet1 , 15 für Bullet2 und 20 für Bullet3 - oder andere Werte, die Sie mögen.Hinweis : Ich habe die Werte so geändert, dass bei höheren Werten der Schadenspreis höher wird. Dies verhindert, dass der Spieler durch das Upgrade Monster an den besten Punkten aktualisieren kann.
Fertige Muscheln - Größe nimmt mit dem Level zuÄndern der Muschelstufe
Weisen Sie verschiedenen Monsterstufen unterschiedliche Granaten zu, damit stärkere Monster Feinde schneller zerstören.Öffnen Sie MonsterData.cs in der IDE und fügen Sie die MonsterLevel
folgenden Variablen hinzu: public GameObject bullet; public float fireRate;
Also haben wir das Fertighaus des Projektils und die Häufigkeit des Feuers für jede Stufe von Monstern festgelegt. Speichern Sie die Datei und kehren Sie zu Unity zurück, um das Monster-Setup abzuschließen.Wählen Sie das Monster- Fertighaus im Projektbrowser aus . Der Inspektor erweitert Level in der Komponente Monster Daten (Script) . Stellen Sie die Feuerrate jedes Gegenstands auf 1 ein . Setzen Sie dann den Bullet- Parameter von Element 0, 1 und 2 auf Bullet1 , Bullet2 und Bullet3 .Monsterlevel sollten wie folgt eingestellt werden:Granaten töten Feinde? Ja!
Lass uns das Feuer eröffnen!Offenes Feuer
Öffnen Sie ShootEnemies.cs in der IDE und fügen Sie die folgenden Variablen hinzu: private float lastShotTime; private MonsterData monsterData;
Wie der Name schon sagt, verfolgen diese Variablen die Zeit des letzten Monsterschusses sowie die Struktur MonsterData
, die Informationen über die Art der Monsterschalen, die Häufigkeit des Feuers usw. enthält.Legen Sie die Werte dieser Felder fest in Start()
: lastShotTime = Time.time; monsterData = gameObject.GetComponentInChildren<MonsterData>();
Hier weisen wir den lastShotTime
Wert der aktuellen Zeit zu und erhalten Zugriff auf die Komponente MonsterData
dieses Objekts.Fügen Sie die folgende Methode hinzu, um die Aufnahme zu implementieren: void Shoot(Collider2D target) { GameObject bulletPrefab = monsterData.CurrentLevel.bullet;
- Wir erhalten die Start- und Zielpositionen der Kugel. Stellen Sie die Position z gleich z ein
bulletPrefab
. Zuvor haben wir die Fertighausposition des Projektils in z so eingestellt, dass das Projektil unter dem schießenden Monster, aber über den Feinden erscheint. - Wir erstellen eine Instanz einer neuen Shell mit der
bulletPrefab
entsprechenden MonsterLevel
. Zuweisen startPosition
und targetPosition
Projektil. - Wir machen das Spiel interessanter: Wenn das Monster schießt, starten Sie die Animation des Schießens und spielen Sie den Klang des Lasers.
Alles zusammenfügen
Es ist Zeit, alles zusammenzusetzen. Definiere das Ziel und lass das Monster es betrachten.Das Skript ShootEnemies.cs fügen Sie den Update()
folgenden Code: GameObject target = null;
Betrachten Sie diesen Code Schritt für Schritt.- Bestimmen Sie den Zweck des Monsters. Wir beginnen mit der maximal möglichen Entfernung in
minimalEnemyDistance
. Wir gehen in einem Zyklus aller Feinde in Reichweite umher und machen den Feind zu einem neuen Ziel, wenn seine Entfernung zum Cookie geringer ist als die derzeit kleinste. - Wir rufen an,
Shoot
wenn die verstrichene Zeit größer als die Schussfrequenz des Monsters ist, und stellen den lastShotTime
Wert der aktuellen Zeit ein. - Wir berechnen den Drehwinkel zwischen dem Monster und seinem Ziel. Wir drehen das Monster in diesen Winkel. Jetzt wird er immer auf das Ziel schauen.
Speichern Sie die Datei und starten Sie das Spiel in Unity. Monster werden verzweifelt anfangen, Cookies zu schützen. Wir sind endlich fertig!Wohin als nächstes gehen
Das fertige Projekt kann hier heruntergeladen werden .Wir haben in diesem Tutorial großartige Arbeit geleistet und jetzt haben wir ein großartiges Spiel.Hier einige Ideen für die Weiterentwicklung des Projekts:- Weitere Arten von Feinden und Monstern
- Verschiedene Wege der Feinde
- Verschiedene Spielstufen
Jeder dieser Aspekte erfordert nur minimale Änderungen und kann das Spiel unterhaltsamer machen. Wenn Sie ein neues Spiel basierend auf diesem Tutorial erstellen, werde ich es gerne spielen. Bitte teilen Sie einen Link dazu.Interessante Gedanken zur Erstellung eines Tower Defense-Hit-Spiels finden Sie in diesem Interview .