Hinweis : Dieses Lernprogramm richtet sich an fortgeschrittene und erfahrene Benutzer und behandelt keine Themen wie das Hinzufügen von Komponenten, das Erstellen neuer GameObject-Skripts und die C # -Syntax. Wenn Sie Ihre Unity-Kenntnisse verbessern müssen, lesen Sie unsere Tutorials Erste Schritte mit Unity und Einführung in Unity Scripting .
Im 
ersten Teil des Tutorials haben wir gelernt, wie man einen Katzenhaken mit der Mechanik des Wickelns eines Seils um Hindernisse erstellt. Wir wollen jedoch mehr: Das Seil kann sich um Objekte auf der Ebene wickeln, löst sich jedoch nicht, wenn Sie zurückkehren.
An die Arbeit gehen
Öffnen Sie das fertige Projekt aus dem ersten Teil von Unity oder laden Sie den 
Entwurf für diesen Teil des Tutorials herunter und öffnen 
Sie dann 
2DGrapplingHook-Part2-Starter . Wie im ersten Teil werden wir Unity Version 2017.1 oder höher verwenden.
Öffnen Sie die Spielszene im Editor aus dem Projektordner " 
Szenen ".
Starten Sie die Spielszene und versuchen Sie, den Katzenhaken an den Steinen über dem Charakter zu befestigen. Schwingen Sie dann, damit sich das Seil um ein Paar Steinkanten wickelt.
Wenn Sie zurückkehren, werden Sie feststellen, dass sich die Punkte des Steins, durch die sich das Seil gedreht hat, nicht wieder lösen.
Denken Sie an den Punkt, an dem sich das Seil entfalten soll. Um die Aufgabe zu vereinfachen, ist es besser, den Fall zu verwenden, wenn sich das Seil um die Kanten wickelt.
Wenn die Schnecke, die an einem Stein über ihrem Kopf haftet, nach rechts schwingt, biegt sich das Seil nach der Schwelle, an der es den 180-Grad-Winkelpunkt mit der Rippe kreuzt, an der die Schnecke gerade befestigt ist. In der folgenden Abbildung wird dies durch einen hervorgehobenen grünen Punkt angezeigt.
Wenn die Schnecke in die andere Richtung zurückschwingt, sollte sich das Seil an derselben Stelle wieder aushaken (in der obigen Abbildung rot hervorgehoben):
Die Logik des Aufdrehens
Um den Moment zu berechnen, in dem Sie das Seil an den Stellen, um die es zuvor gewickelt wurde, aufdrehen müssen, benötigen wir Kenntnisse der Geometrie. Insbesondere werden wir einen Winkelvergleich verwenden, um zu bestimmen, wann sich das Seil von der Kante lösen soll.
Diese Aufgabe mag ein wenig einschüchternd wirken. Mathematik kann selbst bei den Mutigsten Entsetzen und Verzweiflung hervorrufen.
Glücklicherweise hat Unity einige großartige mathematische Hilfsfunktionen, die unser Leben ein bisschen einfacher machen können.
Öffnen Sie das 
RopeSystem- Skript in der IDE und erstellen Sie eine neue Methode namens 
HandleRopeUnwrap() .
 private void HandleRopeUnwrap() { } 
Gehen Sie zu 
Update() und fügen Sie ganz am Ende einen Aufruf unserer neuen Methode hinzu.
 HandleRopeUnwrap(); 
Während 
HandleRopeUnwrap() nichts tut, können wir jetzt die Logik verarbeiten, die mit dem gesamten Prozess des Ablösens von den Kanten verbunden ist.
Wie Sie sich aus dem ersten Teil des Tutorials erinnern, haben wir die 
ropePositions in einer Sammlung 
ropePositions , bei der es sich um eine 
List<Vector2> -Sammlung handelt. Jedes Mal, wenn sich ein Seil um eine Kante wickelt, behalten wir die Position dieses Wickelpunkts in dieser Sammlung bei.
Um den Prozess effizienter zu gestalten, führen wir in 
HandleRopeUnwrap() keine Logik aus, wenn die Anzahl der in der Auflistung gespeicherten Positionen gleich oder kleiner als 1 ist.
Mit anderen Worten, wenn der Butzen am Startpunkt eingehakt ist und sein Seil noch nicht um die Kanten gewickelt ist, beträgt die Anzahl der 
ropePositions 1, und wir folgen nicht der Aufdrehverarbeitungslogik.
Fügen Sie diese einfache 
return oben in 
HandleRopeUnwrap() , um wertvolle CPU-Zyklen zu speichern, da diese Methode mehrmals pro Sekunde von 
Update() aufgerufen wird.
 if (ropePositions.Count <= 1) { return; } 
Neue Variablen hinzufügen
In diesem neuen Test werden wir einige Dimensionen und Verweise auf die verschiedenen Winkel hinzufügen, die zur Implementierung der Basis der Aufdrehlogik erforderlich sind. Fügen Sie 
HandleRopeUnwrap() den folgenden Code 
HandleRopeUnwrap() :
 
Da es hier viele Variablen gibt, werde ich jede erklären und eine praktische Illustration hinzufügen, die hilft, ihren Zweck zu verstehen.
- anchorIndexist der Index in der- ropePositionsAuflistung an zwei Positionen ab dem Ende der Auflistung. Wir können es als einen Punkt in zwei Positionen auf dem Seil von der Position der Schnecke aus betrachten. In der folgenden Abbildung ist dies der erste Befestigungspunkt des Hakens an der Oberfläche. Wenn Sie die Sammlung "- ropePositionsneuen- ropePositionsfüllen,- ropePositionsdieser Punkt immer der- ropePositionsin einem Abstand von zwei Positionen von der Schnecke.
- hingeIndexist der Index der Sammlung, in dem der Punkt des aktuellen Scharniers- hingeIndexist. Mit anderen Worten, die Position, in der sich das Seil gerade um den Punkt wickelt, der dem Ende des Seils von der Schnecke am nächsten liegt. Es befindet sich immer in einem Abstand von einer Position von der Schnecke, weshalb- ropePositions.Count - 1verwenden.- ropePositions.Count - 1.
- anchorPositionberechnet, indem auf die- anchorIndexStelle in der- ropePositionsAuflistung- ropePositions, und ist der einfache Vector2-Wert dieser Position.
- hingePositionberechnet, indem auf die Stelle von- hingeIndexin der Sammlungeilsektionen- ropePositions, und ist der einfache Vector2-Wert dieser Position.
- hingeDirist ein Vektor, der von- anchorPositionzu- hingePosition. Es wird in der folgenden Variablen verwendet, um den Winkel zu erhalten.
- hingeAngle- Die nützliche- Vector2.Angle()wird hier verwendet, um den Winkel zwischen- anchorPositionund dem Scharnierpunkt zu berechnen.
- playerDirist ein Vektor, der von- anchorPositionzur aktuellen Position des Slugs (playerPosition) geleitet wird.
- Dann wird unter Verwendung des Winkels zwischen dem Ankerpunkt und dem Spieler (Slug) playerAngleberechnet.

Alle diese Variablen werden unter Verwendung von Positionen berechnet, die als Vector2-Werte in der 
ropePositions Sammlung gespeichert sind, und unter Verwendung dieser Positionen mit anderen Positionen oder der aktuellen Position des Spielers (Slug).
Die beiden wichtigen Variablen, die zum Vergleich verwendet werden, sind 
hingeAngle und 
hingeAngle .
Der in 
hingeAngle gespeicherte 
hingeAngle muss statisch bleiben, da er immer einen konstanten Winkel zwischen dem Punkt an den beiden „Falten des Seils“ von der Schnecke und der aktuellen „Falte des Seils“ aufweist, die der Schnecke am nächsten liegt und sich erst bewegt, wenn das Seil gelöst oder nach dem Falten ist Ein neuer Biegepunkt wird hinzugefügt.
Wenn die Schnecke 
playerAngle ändert sich 
playerAngle . Durch Vergleichen dieses Winkels mit 
hingeAngle und Überprüfen, ob sich der Butzen links oder rechts von dieser Ecke befindet, können wir bestimmen, ob der aktuelle 
hingeAngle , der dem Butzen am nächsten liegt, entfernt werden soll.
Im ersten Teil dieses Tutorials haben wir die 
wrapPointsLookup in einem Wörterbuch namens 
wrapPointsLookup . Jedes Mal, wenn wir den Biegepunkt speichern, haben wir ihn dem Wörterbuch mit der Position als Schlüssel und mit 0 als Wert hinzugefügt. Dieser Wert von 0 war jedoch ziemlich mysteriös, oder?
Wir werden diesen Wert verwenden, um die Position der Schnecke relativ zu ihrem Winkel zum Scharnierpunkt (dem aktuellen Falzpunkt, der der Schnecke am nächsten liegt) zu speichern.
Wenn Sie einen Wert von 
-1 zuweisen, ist der Winkel der 
hingeAngle ( 
hingeAngle ) kleiner als der Winkel des Scharniers ( 
hingeAngle ), und bei einem Wert von 
1 ist der Winkel von 
hingeAngle größer als der 
hingeAngle .
Aufgrund der Tatsache, dass wir die Werte im Wörterbuch 
hingeAngle , können wir jedes Mal, wenn wir 
hingeAngle mit 
hingeAngle vergleichen, nachvollziehen, ob die Schnecke gerade die Grenze überschritten hat, nach der sich das Seil lösen sollte.
Es kann anders erklärt werden: Wenn der Winkel der Schnecke gerade überprüft wurde und kleiner als der Scharnierwinkel ist, aber beim letzten Speichern im Wörterbuch der Biegepunkte mit einem Wert markiert wurde, der angibt, dass er sich auf der anderen Seite dieser Ecke befindet, sollte der Punkt entfernt werden !
Seil abkuppeln
Schauen Sie sich den Screenshot unten mit Notizen an. Unsere Schnecke klammerte sich an den Felsen, schwankte nach oben und wickelte auf dem Weg nach oben ein Seil um den Rand des Felsens.
Möglicherweise stellen Sie fest, dass an der obersten Schwenkposition, an der die Schnecke undurchsichtig ist, der aktuell nächstgelegene 
wrapPointsLookup (mit einem weißen Punkt markiert) im 
wrapPointsLookup Wörterbuch mit dem Wert 
1 gespeichert wird.
Auf dem Weg nach unten wird eine Überprüfung durchgeführt, wenn 
hingeAngle kleiner als 
hingeAngle (zwei gestrichelte grüne Linien), wie durch den blauen Pfeil angezeigt. Wenn der letzte (aktuelle) Wert des Biegepunkts 
1 war , sollte der Biegepunkt entfernt werden.
Lassen Sie uns diese Logik nun in Code implementieren. Bevor wir beginnen, erstellen wir ein Leerzeichen der Methode, mit der wir uns abwickeln. Aus diesem Grund führt das Erstellen der Logik nach dem Erstellen nicht zu einem Fehler.
Fügen Sie eine neue 
UnwrapRopePosition(anchorIndex, hingeIndex) Methode 
UnwrapRopePosition(anchorIndex, hingeIndex) indem Sie die folgenden Zeilen einfügen:
 private void UnwrapRopePosition(int anchorIndex, int hingeIndex) { } 
Nachdem Sie dies getan haben, 
HandleRopeUnwrap() zu 
HandleRopeUnwrap() . 
hingeAngle unter den neu hinzugefügten Variablen die folgende Logik hinzu, die zwei Fälle behandelt: 
playerAngle weniger als 
hingeAngle und 
hingeAngle mehr als 
hingeAngle :
 if (playerAngle < hingeAngle) {  
Dieser Code sollte der Erläuterung der oben beschriebenen Logik für den ersten Fall entsprechen (wenn 
hingeAngle < 
hingeAngle ), behandelt aber auch den zweiten Fall (wenn 
hingeAngle > 
hingeAngle ).
- Wenn der aktuelle hingeAngle, der dem Slug am nächsten liegt, an dem Punkt, an demhingeAngle<hingeAngle, den Wert 1hingeAngle, entfernen wir diesen Punkt und führen eine Rückgabe durch, damit der Rest der Methode nicht ausgeführt wird.
- Andernfalls wird -1 zugewiesen, wenn der hingeAnglenicht zuletzt mit dem Wert 1 markiert wurde,playerAnglekleiner alshingeAngleist .
- Wenn der aktuelle hingeAngle, der dem Butzen am nächsten liegt, -1 an dem Punkt ist, an demhingeAngle>hingeAngle, entfernen Sie den Punkt und kehren Sie zurück.
- Andernfalls ordnen wir die Einträge im Wörterbuch der Biegepunkte an der Scharnierposition 1 zu .
Dieser Code stellt sicher, dass das 
wrapPointsLookup Wörterbuch immer aktualisiert wird, und stellt sicher, dass der Wert des aktuellen 
wrapPointsLookup (der dem Butzen am nächsten liegt) mit dem aktuellen Butzenwinkel relativ zum 
wrapPointsLookup .
Vergessen Sie nicht, dass der Wert -1 ist, wenn der Schwenkwinkel kleiner als der Scharnierwinkel (relativ zum Referenzpunkt) ist, und 1, wenn der Schwenkwinkel größer als der Scharnierwinkel ist.
Jetzt 
UnwrapRopePosition() wir 
UnwrapRopePosition() im 
RopeSystem- Skript 
mit einem Code, der sich direkt 
mit dem 
Entkoppeln befasst , die Referenzposition verschiebt und dem 
Seilentfernungswert DistanceJoint2D einen neuen Abstandswert zuweist. Fügen Sie der zuvor erstellten Methoden-CD die folgenden Zeilen hinzu:
   
- Der Index des aktuellen Ankerpunkts (die zweite Position des Seils von der Schnecke) wird zur neuen Position des Scharniers, und die alte Position des Scharniers wird entfernt (die Position, die zuvor der Schnecke am nächsten war und die wir jetzt „aufdrehen“). Der Variablen newAnchorPositionin der Liste dernewAnchorPositionder WertanchorIndexzugewiesen. Es wird dann verwendet, um die aktualisierte Position des Ankerpunkts zu positionieren.
- Das Seilgelenk RigidBody2D (an dem das DistanceJoint2D-Seil befestigt ist) ändert seine Position in die neue Position des Ankerpunkts. Dies gewährleistet eine reibungslose kontinuierliche Bewegung des Butzens am Seil, wenn es mit DistanceJoint2D verbunden ist, und diese Verbindung sollte es ihm ermöglichen, weiter relativ zur neuen Position zu schwingen, die zur Referenz wurde - mit anderen Worten, relativ zum nächsten Punkt des Seils von seiner Position aus.
- Anschließend müssen Sie den Entfernungswert von distanceJoint2D aktualisieren, um eine starke Änderung der Entfernung von der Schnecke zum neuen Referenzpunkt zu berücksichtigen. Wenn dies noch nicht geschehen ist, wird eine schnelle Überprüfung des distanceSetFlags durchgeführt, und der Distanz wird der Wert der berechneten Distanz zwischen dem Butzen und der neuen Position des Ankerpunkts zugewiesen.
Speichern Sie das Skript und kehren Sie zum Editor zurück. Starten Sie das Spiel erneut und beobachten Sie, wie sich das Seil von den Kanten löst, wenn die Schnecke die Schwellenwerte jedes Biegepunkts überschreitet!
Obwohl die Logik fertig ist, fügen wir 
HandleRopeUnwrap() einen 
HandleRopeUnwrap() bevor wir 
HandleRopeUnwrap() mit 
hingeAngle ( 
if (playerAngle < hingeAngle) ).
 if (!wrapPointsLookup.ContainsKey(hingePosition)) { Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary."); return; } 
Dies sollte eigentlich nicht passieren, da wir den Katzenhaken neu definieren und trennen, wenn er zweimal um eine Kante gewickelt wird. In diesem Fall ist es jedoch nicht schwierig, diese Methode mit einer einfachen 
return und einer Fehlermeldung zu beenden in der Konsole.
Dank dessen können wir solche Grenzfälle außerdem bequemer behandeln. Darüber hinaus erhalten wir eine eigene Fehlermeldung für den Fall, dass etwas Unnötiges auftritt.
Wohin als nächstes?
Hier ist ein 
Link zum fertigen Projekt dieses zweiten und letzten Teils des Tutorials.
Herzlichen Glückwunsch zum Abschluss dieser Tutorial-Reihe! Wenn es darum ging, Winkel und Positionen zu vergleichen, wurde alles ziemlich kompliziert, aber wir haben dies überlebt und jetzt haben wir ein wunderbares Hakenkatzen- und Seilsystem, das sich auf Objekten im Spiel aufwickeln kann.
Wussten Sie, dass unser Unity-Entwicklungsteam ein Buch geschrieben hat? Wenn nicht, lesen Sie 
Unity Games By Tutorials . In diesem Spiel lernen Sie, wie Sie vier vorgefertigte Spiele von Grund auf neu erstellen:
- Zwei-Stock-Schütze
- Ego-Shooter
- Tower Defense-Spiel (mit VR-Unterstützung!)
- 2D-Plattformer
Nachdem Sie dieses Buch gelesen haben, lernen Sie, wie Sie Ihre eigenen Spiele für Windows, MacOS, iOS und andere Plattformen erstellen!
Dieses Buch richtet sich sowohl an Anfänger als auch an diejenigen, die ihre Unity-Fähigkeiten auf ein professionelles Niveau bringen möchten. Um das Buch zu beherrschen, müssen Sie Programmiererfahrung (in jeder Sprache) haben.