Erstellen einer einfachen C # AI in Unity

Bild

Fast jedes Spiel erfordert künstliche Intelligenz (KI), die mit dem Benutzer interagiert, meist in Form einer dem Spieler feindlichen Kraft. In einigen Fällen sollte die KI dem Spieler helfen, in anderen sollte sie dagegen ankämpfen, aber alle vom Computer kontrollierten Charaktere haben einige Ähnlichkeiten. Abhängig von den Anforderungen des Projekts kann die KI einfache oder komplexe Verhaltensweisen verwenden. Solche Anforderungen können Diplomatie mit einem anderen Spieler oder ein einfaches Hin- und Herwandern auf der Plattform sein. Wie dem auch sei, es muss sichergestellt werden, dass die KI ihre Arbeit effizient erledigt.

In diesem Projekt werde ich eine sehr einfache künstliche Intelligenz demonstrieren. Angenommen, wir erstellen ein Spiel, in dem sich ein Spieler in die Nähe des feindlichen Hauptquartiers schleichen muss. Wenn ein Spieler von einer Überwachungskamera bemerkt wird, entstehen in der Nähe Feinde, die den Spieler für kurze Zeit verfolgen. Das setzen wir auf einfachster Ebene im Projekt um. Nach Abschluss des Projekts erhalten Sie ein Objekt eines kontrollierten Spielers, einen Kreis, der als Kamera eines Feindes verwendet wird, und ein Objekt eines Feindes, das den Spieler verfolgt, wenn das Objekt der Kamera über seine Anwesenheit informiert.

Vorbereitung


Zuerst müssen wir ein 3D-Projekt erstellen. Klicken Sie nach dem Starten von Unity oben im Fenster oben auf die Schaltfläche Neu (siehe Abbildung 1).


Abbildung 1: Erstellen eines neuen Projekts

Nennen Sie Ihr KI- Projekt und stellen Sie sicher, dass es sich um ein 3D-Projekt handelt. Nachdem Sie einen Ort auf dem Computer zum Speichern des Projekts ausgewählt haben, klicken Sie unten auf die Schaltfläche Projekt erstellen (siehe Abbildung 2).


Abbildung 2: Projekt-Setup-Bildschirm

Nach dem Erstellen des Projekts müssen wir zunächst die Ordner im Fenster " Assets" einrichten, um unsere Arbeit zu organisieren. Klicken Sie mit der rechten Maustaste auf das Fenster Assets und wählen Sie Erstellen → Ordner , um einen neuen Ordner zu erstellen. Nennen Sie diesen Ordner Materialien . Erstellen Sie dann einen zweiten Ordner und nennen Sie ihn Skripte . Abbildung 3 zeigt, wie es aussehen soll.


Abbildung 3: Erstellen eines neuen Ordners

Nach all dem sollte das Assets- Fenster wie in Abbildung 4 dargestellt aussehen.


Abbildung 4: Fenster " Assets" .

Erstellen Sie als Nächstes einen Boden, auf dem alle Objekte stehen. Wählen Sie im Hierarchiefenster Erstellen → 3D-Objekt → Ebene , um ein Ebenenobjekt zu erstellen, das als Boden verwendet wird.


Abbildung 5: Erstellen eines Ebenenobjekts

Benennen Sie dieses Bodenobjekt und ändern Sie seinen X-Skalierungswert auf 7 und den Z-Skalierungswert auf 3. Danach sollte das Inspektorfenster mit dem ausgewählten Bodenobjekt wie in Abbildung 6 dargestellt aussehen.


Abbildung 6: Festlegen der Eigenschaften des Floor- Objekts

Jetzt müssen wir ein neues Material für Floor erstellen, um es von den übrigen Objekten zu unterscheiden, die in der Szene platziert werden. Erstellen Sie im Ordner " Materialien " des Fensters " Assets" ein neues Material, indem Sie mit der rechten Maustaste auf das Fenster " Assets" klicken und " Erstellen" → "Material" wählen.


Abbildung 7: Neues Material erstellen

Wenn Sie fertig sind, benennen Sie das Material Boden .


Abbildung 8: Bodenmaterial .

Wählen Sie oben im Inspektorfenster mit ausgewähltem Boden einen Farbwähler aus.


Abbildung 9: Auswahl eines Farbwählers

Natürlich können Sie eine beliebige Farbe für den Boden auswählen, aber in diesem Beispiel habe ich Rotbraun gewählt, wie in Abbildung 10 dargestellt.


Abbildung 10: Farbwähler.

Wählen Sie das Floor- Objekt im Hierarchiefenster aus und wählen Sie in der Mesh Renderer- Komponente den kleinen Pfeil neben Materialien aus .


Abbildung 11: Vorbereitung auf einen Materialwechsel

Ziehen Sie Bodenmaterial aus dem Fenster " Assets" in das Feld " Element 0" der Mesh Renderer- Komponente im Inspektorfenster .


Abbildung 12: Definieren des Bodenmaterials als Material des Bodenobjekts .

Nachdem wir mit dem Bodenobjekt fertig sind, müssen wir um den Wandbereich herum erstellen, damit der Spieler nicht von der Kante fallen kann. Gehen Sie zurück zu Erstellen → 3D-Objekt → Ebene , um eine neue Ebene zu erstellen. Wir nennen diese Wandebene und stellen sie auf die gleichen Abmessungen wie Boden ein , dh X-Skalierung mit einem Wert von 7 und Z-Skalierung mit einem Wert von 3. Erstellen Sie dann drei weitere Wände, wählen Sie ein Objekt aus und drücken Sie dreimal Strg + D. Danach platzieren Sie die Wände herum Geschlecht gemäß den Angaben in der Tabelle.

Titel
Position X.
Position Y.
Position z
Drehung x
Drehung z
Wand
-35
21
0
0
-90
Wand (1)-1
11
-15
90
0
Wand (2)
-1
11
13.5
-90
0
Wand (3)
34
21
0
0
90

Tabelle 1: Positionen und Rotationen aller Wandobjekte.

Nachdem Sie dies alles abgeschlossen haben, müssen Sie die Position der Kamera so ändern, dass sie von oben auf den Boden schaut. Wählen Sie das Hauptkameraobjekt aus und setzen Sie die Y-Position auf 30, die Z-Position auf 0 und die X-Drehung auf 80.


Abbildung 13: Einrichten des Kameraobjekts

Die Szene ist vorbereitet, es ist also Zeit, den Charakter des Spielers zu erstellen. Klicken Sie im Hierarchiefenster auf Erstellen → 3D-Objekt → Kugel , um ein Kugelobjekt zu erstellen. Nennen Sie dieses Objekt Player und klicken Sie dann unten im Inspektorfenster auf die Schaltfläche Komponente hinzufügen.


Abbildung 14: Hinzufügen einer neuen Komponente

Finde jetzt den starren Körper . Wählen Sie anschließend die Rigidbody- Komponente aus der Liste aus und fügen Sie den Rigidbody zum Player- Objekt hinzu.


Abbildung 15: Hinzufügen einer Rigidbody- Komponente

Als nächstes müssen Sie dem Player ein Tag zuweisen, das uns später im Code nützlich sein wird. Klicken Sie auf das Dropdown-Menü Tag in der oberen linken Ecke des Inspektorfensters und wählen Sie das Player- Tag aus.


Abbildung 16: Definieren eines neuen Tags

Wir müssen die Position des Spielers so einstellen, dass er sich nicht unter dem Bodenobjekt befindet . Im Beispiel habe ich den Spieler in der oberen linken Ecke mit einer X-Position von 26, einer Y-Position von 1 und einer Z-Position von -9 platziert.


Abbildung 17: Spielerplatzierung

Damit unser zukünftiger Code ordnungsgemäß funktioniert, müssen wir ihn natürlich an das Objekt anhängen. Gehen Sie zurück zum Hierarchiefenster und wählen Sie dieses Mal Erstellen → 3D-Objekt → Würfel . Rufen Sie diesen Guard- Cube auf und fügen Sie die Rigidbody- Komponente und die NavMesh Agent- Komponente über die Schaltfläche Komponente hinzufügen im Inspektorfenster hinzu . Als nächstes platzieren Sie es irgendwo in der oberen linken Ecke der Szene. Danach sieht das Inspektorfenster des Guard- Objekts folgendermaßen aus:


Abbildung 18: Schutzobjekt im Inspektorfenster

Und dieses Objekt sollte so lokalisiert sein:


Abbildung 19: Platzierung des Guard- Objekts.

Schließlich benötigen wir ein Objekt, das als „Auge“ des Guard- Objekts verwendet wird und das den Guard benachrichtigt, dass der Spieler es berührt. Gehen Sie zum letzten Mal zum Hierarchiefenster und wählen Sie Erstellen → 3D-Objekt → Kugel , um ein weiteres Kugelobjekt zu erstellen. Nennen Sie dieses Objekt Looker . Dieses Mal müssen wir keine weiteren Komponenten hinzufügen. Wir werden jedoch die Größe des Objekts ändern. Ändern Sie nach Auswahl von Looker die folgenden Variablen der Transformationskomponente im Inspektorfenster .

  • Skaliere X bei 9.
  • Skala Y bei 0,5.
  • Skala Z bei 9.

Positionieren Sie den Looker danach so, dass er sich im mittleren oberen Teil des Bodens befindet (siehe Abbildung 20).


Abbildung 20: Position des Lookers.

Es ist der richtige Zeitpunkt, Looker ein einzigartiges Material zu geben, damit Sie sehen können, dass es sich lohnt, es zu vermeiden. Klicken Sie im Ordner " Materialien " des Fensters " Assets" mit der rechten Maustaste und erstellen Sie ein neues Material. Nennen Sie es Looker und geben Sie ihm eine leuchtend rote Farbe. Legen Sie danach dieses Material als Material des Looker- Objekts fest, um seine Farbe zu ändern. Danach sollte die Szene folgendermaßen aussehen:


Abbildung 21: Looker- Objekt mit neuem Material.

Wir müssen nur noch ein Navigationsnetz für die Wache erstellen, auf dem sie sich bewegen kann. Oben im Unity-Editor befindet sich ein Fenstermenü . Wählen Sie Fenster → Navigation , um das in Abbildung 22 gezeigte Navigationsfenster zu öffnen.


Abbildung 22: Navigationsfenster

Wählen Sie das Bodenobjekt in der Hierarchie aus und aktivieren Sie dann im Navigationsfenster das Kontrollkästchen Navigationsstatik .


Abbildung 23: Navigationsstatik

Wählen Sie als Nächstes oben im Fenster die Option Backen.


Abbildung 24: Wechseln Sie zum Menü Backen .

Das Menü Backen wird geöffnet, in dem Sie die Eigenschaften des Navigationsnetzes ändern können, das wir erstellen möchten. In unserem Beispiel muss nichts geändert werden. Klicken Sie einfach unten rechts auf die Schaltfläche Backen .


Abbildung 25: Erstellen eines neuen Navigationsnetzes

An dieser Stelle werden Sie von Unity aufgefordert, die Szene zu speichern. Speichern Sie es, woraufhin ein Navigationsnetz erstellt wird. Jetzt sieht die Szene folgendermaßen aus:


Abbildung 26: Die aktuelle Szene mit dem hinzugefügten Navigationsnetz.

Jetzt ist alles in Unity konfiguriert, sodass es Zeit ist, die Skripte zu erstellen, die für das Funktionieren des Projekts erforderlich sind. Klicken Sie im Fenster Assets mit der rechten Maustaste und wählen Sie Erstellen → C # -Skript . Nennen Sie dieses Skript Player . Wiederholen Sie diesen Vorgang noch zweimal und erstellen Sie Skripte mit den Namen Guard und Looker .


Abbildung 27: Erstellen eines neuen Skripts

Danach sieht der Ordner " Skripte " im Fenster " Assets " folgendermaßen aus:


Abbildung 28: Skriptordner

Zuerst schreiben wir den Player- Skriptcode. Doppelklicken Sie im Fenster " Assets" auf das Player- Skript, um Visual Studio zu öffnen und den Code zu erstellen.

Code


Das Player- Skript ist recht einfach. Der Benutzer kann lediglich das Ballobjekt bewegen. Unter der Klassendeklaration benötigen wir einen Link zu der Rigidbody- Komponente, die wir zuvor im Projekt erstellt haben.

private Rigidbody rb; 

Unmittelbar danach befehlen wir in der Startfunktion Unity, die aktuelle Rigidbody- Komponente des Player- Objekts auf rb zu setzen .

 rb = GetComponent<Rigidbody>(); 

Danach sieht das Player- Skript folgendermaßen aus:


Abbildung 29: Player- Skript im Moment.

Nachdem der rb- Wert zugewiesen wurde, müssen wir das Player- Objekt bewegen lassen, wenn wir die Pfeiltasten drücken. Um das Objekt zu bewegen, verwenden wir Physik und üben Kraft auf das Objekt aus, wenn der Benutzer die Pfeiltasten drückt. Fügen Sie dazu einfach den folgenden Code zur Update- Funktion hinzu:

 if (Input.GetKey(KeyCode.UpArrow)) rb.AddForce(Vector3.forward * 20); if (Input.GetKey(KeyCode.DownArrow)) rb.AddForce(Vector3.back * 20); if (Input.GetKey(KeyCode.LeftArrow)) rb.AddForce(Vector3.left * 20); if (Input.GetKey(KeyCode.RightArrow)) rb.AddForce(Vector3.right * 20); 

Damit haben wir das Player- Skript fertiggestellt. Das fertige Skript sieht folgendermaßen aus:


Abbildung 30: Das fertige Player- Skript.

Speichern Sie Ihre Arbeit und kehren Sie zu Unity zurück. Wählen Sie dieses Mal das Guard- Skript im Fenster " Assets" aus. Damit der Guard- Code funktioniert, müssen Sie das using-Konstrukt oben im Skript hinzufügen.

 using UnityEngine.AI; 

Deklarieren Sie als Nächstes die folgenden Variablen unmittelbar nach der Klassendeklaration.

 public GameObject player; private NavMeshAgent navmesh; 

Das Player- Objekt wird als Wert der Player- Variablen des Guard- Objekts verwendet. Es wird später nützlich sein, wenn wir dem Guard- Objekt befehlen, den Spieler zu jagen. Anschließend wird die Variable navmesh deklariert , um die NavMeshAgent- Komponente des Objekts zu empfangen. Wir werden es später verwenden, wenn der Wächter beginnt, den Spieler zu jagen, nachdem er erfahren hat, dass der Spieler das Looker- Objekt berührt. In der Startfunktion müssen wir den Wert der Variablen navmesh auf die Komponente NavMesh Agent des Objekts setzen:

 navmesh = GetComponent<NavMeshAgent>(); 

Dann fügen wir in der Update- Funktion eine einzelne Codezeile hinzu:

 navmesh.destination = player.transform.position; 

Diese Zeile legt das Ziel für das Guard- Objekt fest. In unserem Fall nimmt es die aktuelle Position des Player- Objekts ein und bewegt sich zu diesem Punkt. Nach der Operation verfolgt das Objekt den Spieler ständig. Die Frage ist, wie der Antwortprozess durchgeführt wird. Es wird nicht im Guard- Skript, sondern im Looker- Skript codiert. Bevor Sie mit dem Looker-Skript fortfahren, sehen Sie sich Abbildung 31 an, um Ihren Guard- Skriptcode zu überprüfen.


Abbildung 31: Das fertige Guard- Skript.

In Looker müssen wir erneut die folgenden Variablen deklarieren:

 public GameObject guard; private float reset = 5; private bool movingDown; 

Danach kommentieren wir die Startfunktion , die wir in diesem Skript nicht benötigen. Fahren wir mit der Update- Funktion fort und fügen den folgenden Code hinzu:

 if (movingDown == false) transform.position -= new Vector3(0, 0, 0.1f); else transform.position += new Vector3(0, 0, 0.1f); if (transform.position.z > 10) movingDown = false; else if (transform.position.z < -10) movingDown = true; reset -= Time.deltaTime; if (reset < 0) { guard.GetComponent<Guard>().enabled = false; GetComponent<SphereCollider>().enabled = true; } 

Hier finden die Hauptaktionen des Projekts statt. Analysieren wir also den Code. Erstens wird das Objekt, an das dieses Skript angehängt ist, abhängig vom Wert der booleschen Variablen moveDown nach oben oder unten verschoben. Sobald er einen bestimmten Punkt erreicht, ändert er die Richtung. Als nächstes senkt Looker den Rücksetzwert basierend auf der Echtzeit. Sobald der Timer kleiner als Null wird, nimmt er das Guard- Skript aus dem Guard- Objekt und deaktiviert es. Danach bewegt sich das Guard- Objekt bis zu diesem Moment an die letzte bekannte Position des Spielers und stoppt dann. Looker schaltet auch seinen Collider wieder ein, damit der gesamte Prozess von vorne beginnen kann. Jetzt sieht unser Skript so aus:


Abbildung 32: Looker- Skript

Apropos Collider: Es ist Zeit, einen Konfliktcode zu erstellen, der den Looker- Timer zurücksetzt und das Guard- Skript enthält. Erstellen Sie in der Update- Funktion den folgenden Code:

 private void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Player") { guard.GetComponent<Guard>().enabled = true; reset = 5; GetComponent<SphereCollider>().enabled = false; } } 

OnCollisionEnter Unity erkennt es automatisch als Kollisionscode und führt es daher aus, wenn eine Kollision mit einem anderen Objekt auftritt. In unserem Fall wird zunächst geprüft, ob das kollidierende Objekt ein Player- Tag hat. Wenn nicht, wird der Rest des Codes ignoriert. Andernfalls wird das Guard- Skript aktiviert, der Rücksetz- Timer auf 5 (d. H. Fünf Sekunden) gesetzt und der Collider deaktiviert, sodass sich der Player weiterhin durch das Objekt bewegen kann und nicht versehentlich im Looker- Objekt stecken bleibt. Die Funktion ist in Abbildung 33 dargestellt.


Abbildung 33: Kollisionscode für Looker

Das ist alles, was der Projektcode fertig ist! Sie können noch ein paar Dinge tun, bevor Sie das Projekt beenden. Speichern Sie die gesamte Arbeit und kehren Sie zu Unity zurück.

Projektabschluss


Um das Projekt abzuschließen, müssen wir nur Skripte an die entsprechenden Objekte anhängen und mehrere Variablen festlegen. Wechseln Sie zunächst vom Navigationsfenster zum Inspektorfenster :


Abbildung 34: Übergang zum Inspektorfenster

Beginnen wir danach mit dem Player- Objekt. Wählen Sie es im Hierarchiefenster aus, klicken Sie unten im Inspektorfenster auf die Schaltfläche Komponente hinzufügen und fügen Sie das Player- Skript hinzu. Damit ist das Player- Objekt abgeschlossen.


Abbildung 35: Player- Skriptkomponente

Wählen Sie als Nächstes das Guard- Objekt aus. Hängen Sie wie zuvor das Guard- Skript an das Objekt an. Dieses Mal müssen wir der Wache sagen, wer der Spieler ist. Ziehen Sie dazu das Player- Objekt aus der Hierarchie in das Player- Feld der Guard- Skriptkomponente (siehe Abbildung 36).


Abbildung 36: Das Player- Objekt zum Wert des Player- Felds machen.

Wir müssen auch das Guard- Skript deaktivieren. In unserem Projekt wird Guard den Spieler verfolgen, nachdem er sein Skript eingeschaltet hat. Dieses Guard- Skript sollte erst enthalten sein, nachdem der Player das Looker- Objekt berührt hat. Alles, was Sie tun müssen, ist das Kontrollkästchen neben dem Guard- Text (Skript) in der Komponente zu deaktivieren:


Abbildung 37: Deaktivieren des Guard- Skripts

Lassen Sie uns abschließend zum Looker- Objekt übergehen und das Looker- Skript daran anhängen. Dieses Mal benötigt das Looker- Objekt ein Guard- Objekt als Wert seiner Guard- Variablen. So wie wir das Player- Objekt der Player- Variablen des Guard- Skripts zugewiesen haben, werden wir dasselbe mit dem Guard- Objekt und dem Looker- Skript tun. Ziehen Sie den Guard aus der Hierarchie in das Guard- Feld des Looker- Skripts. Und das Projekt ist abgeschlossen! Klicken Sie oben im Unity-Editor auf die Schaltfläche Wiedergabe, um Ihr Projekt zu testen.


Abbildung 38: Testen eines Projekts

Versuchen Sie, das Player- Objekt in das Looker- Objekt zu verschieben (denken Sie daran, dass das Verschieben mit Pfeilen erfolgt!). Beachten Sie, dass das Guard- Objekt danach beginnt, den Spieler zu verfolgen. Er wird die Verfolgung für ungefähr 5 Sekunden fortsetzen, danach wird er aufgeben.


Abbildung 39: Ein vollständig abgeschlossenes Projekt in Aktion.

Fazit


Diese KI ist sehr einfach, kann aber leicht erweitert werden. Angenommen, wenn wir uns vorstellen, dass das Looker- Objekt eine Kamera ist und der Wächter durch sie schaut, um Sie zu finden, ist es logisch, dem Guard- Objekt ein eigenes Augenpaar zu geben. Der Spieler kann sich den Kameras nähern, muss jedoch die Augen des Wächters berücksichtigen. Sie können dieses Projekt auch mit dem Konzept kombinieren , den Pfad zu finden : Geben Sie dem Wächter den Pfad, dem er folgen wird, und schaffen Sie so eine interessantere Umgebung für den Spieler.

Eine solch einfache KI kann auf viele verschiedene Arten entwickelt werden. Möglicherweise möchten Sie nichts von alledem tun und sich dazu entschließen, etwas Eigenes zu tun. Ich rate Ihnen zu experimentieren, vielleicht haben Sie die Idee eines interessanten Projekts, das es wert ist, zum Ende gebracht zu werden.

Source: https://habr.com/ru/post/de419641/


All Articles