Eines der Schlüsselelemente jedes 2D-Plattformspiels ist die Hauptfigur. Die Art und Weise, wie sie sich bewegt und gesteuert wird, prägt maßgeblich die Atmosphäre des Spiels – egal, ob es sich um ein gemütliches Old-School-Spiel oder einen dynamischen Slasher handelt. Daher ist die Erstellung eines Charakter-Controllers ein wichtiger früher Schritt bei der Entwicklung eines Plattformspiels. In diesem Artikel werden wir den Prozess der Erstellung eines Charakters von Grund auf gründlich untersuchen und ihm beibringen, sich unter Einhaltung der Gesetze der Physik im Level zu bewegen. Auch wenn Sie bereits Erfahrung mit der Erstellung von Charakter-Controllern haben, werden Sie an den Neuerungen in Unity 2023 interessiert sein. Zu meiner Überraschung wurde für die Komponente eine lang erwartete Methode hinzugefügt, die das Schreiben eines Charakter-Controllers erheblich vereinfacht, indem sie die Verwendung von im Kinematic-Modus effektiver ermöglicht. Bisher musste all diese Funktionalität manuell implementiert werden. Rigidbody2D Slide Rigidbody2D Wenn Sie den Artikel nicht nur lesen, sondern auch in der Praxis ausprobieren möchten, empfehle ich Ihnen, eine Level-Vorlage aus dem GitHub-Repository herunterzuladen, in der die erforderlichen Assets und ein fertiges Level zum Testen Ihres Charakters bereits enthalten sind. Treasure Hunters Den Grundstein für unseren Charakter legen Für unser Plattformspiel haben wir die Regel festgelegt, dass das Spiel nur vertikale und horizontale Flächen haben soll und die Schwerkraft streng nach unten gerichtet sein soll. Dies vereinfacht die Erstellung des Plattformspiels in der Anfangsphase erheblich, insbesondere wenn Sie sich nicht mit Vektormathematik befassen möchten. In Zukunft werde ich in meinem Projekt Treasure Hunters, in dem ich die Erstellung von Mechaniken für ein 2D-Plattformspiel auf Unity erforsche, möglicherweise von diesen Regeln abweichen. Aber das wird das Thema eines anderen Artikels sein. Da wir uns entschieden haben, die Bewegung auf horizontalen Flächen durchzuführen, wird die Basis unseres Charakters rechteckig sein. Die Verwendung von geneigten Flächen würde die Entwicklung eines kapselförmigen Kolliders und zusätzlicher Mechaniken wie Gleiten erfordern. Erstellen Sie zunächst ein leeres Objekt in der Szene und nennen Sie es Captain – das wird unsere Hauptfigur. Fügen Sie dem Objekt die Komponenten und hinzu. Stellen Sie den -Typ auf Kinematisch ein, damit wir die Bewegung der Figur steuern und gleichzeitig die integrierten Physikfunktionen von Unity nutzen können. Sperren Sie außerdem die Drehung der Figur entlang der Z-Achse, indem Sie die Option „Rotation Z einfrieren“ aktivieren. Rigidbody2D BoxCollider2D Rigidbody2D Ihr Setup sollte wie in der Abbildung unten aussehen. Jetzt verleihen wir unserem Kapitän ein Aussehen. Suchen Sie die Textur unter Assets/Textures/Treasure Hunters/Captain Clown Nose/Sprites/Captain Clown Nose/Captain Clown Nose with Sword/09-Idle Sword/Idle Sword 01.png und setzen Sie den Wert für Pixel pro Einheit auf 32. Wir werden diesen Wert in diesem Kurs häufig verwenden, da unsere Texturen mit dieser Auflösung erstellt werden. Stellen Sie den Sprite-Modus auf Einzeln und der Einfachheit halber den Drehpunkt auf Unten. Vergessen Sie nicht, die Änderungen durch Klicken auf die Schaltfläche Übernehmen anzuwenden. Stellen Sie sicher, dass alle Einstellungen korrekt vorgenommen wurden. In diesem Artikel werden wir nicht auf die Charakteranimation eingehen, daher verwenden wir vorerst nur ein Sprite. Erstellen Sie im Captain-Objekt ein verschachteltes Objekt namens Appearance und fügen Sie ihm eine Sprite-Renderer-Komponente hinzu, wobei Sie das zuvor konfigurierte Sprite angeben. Als ich das Bild des Kapitäns vergrößerte, bemerkte ich, dass es aufgrund falscher Sprite-Einstellungen ziemlich verschwommen war. Um dies zu beheben, wählen Sie die Textur Idle Sword 01 im Projektfenster aus und stellen Sie den Filtermodus auf Punkt (kein Filter). Jetzt sieht das Bild viel besser aus. Einrichtung des Character Collider Im Moment stimmen die Position des Colliders und das Bild unseres Kapitäns nicht überein und der Collider erweist sich für unsere Anforderungen als zu groß. Lassen Sie uns dies beheben und auch den Drehpunkt des Charakters unten richtig positionieren. Wir werden diese Regel auf alle Objekte im Spiel anwenden, um ihre Platzierung auf derselben Ebene unabhängig von der Größe zu erleichtern. Um diesen Vorgang einfacher zu handhaben, verwenden Sie die Umschaltfunktion für die Werkzeuggriffposition mit festgelegtem Drehpunkt, wie unten gezeigt. Der nächste Schritt besteht darin, den Collider unseres Helden so einzustellen, dass sein Drehpunkt genau in der Mitte unten liegt. Die Größe des Colliders sollte genau den Abmessungen des Charakters entsprechen. Passen Sie die Parameter Offset und Size des Colliders sowie die Position des verschachtelten Appearance-Objekts an, um die erforderliche Präzision zu erreichen. Achten Sie besonders auf den Parameter Offset.X des Colliders: Sein Wert muss strikt 0 sein. Dadurch wird die symmetrische Platzierung des Colliders relativ zur Mitte des Objekts sichergestellt, was für nachfolgende Charakterrotationen nach links und rechts äußerst wichtig ist, bei denen der Wert von Transform.Scale.X auf -1 und 1 geändert wird. Der Collider sollte an Ort und Stelle bleiben und die visuelle Rotation sollte natürlich aussehen. Einführung in das physische Verhalten von Charakteren In erster Linie ist es wichtig, den Charakteren – ob dem Haupthelden, NPCs oder Feinden – beizubringen, mit der physischen Welt zu interagieren. Charaktere sollten beispielsweise in der Lage sein, auf einer ebenen Fläche zu laufen, davon zu springen und der Schwerkraft zu unterliegen, die sie wieder auf den Boden zieht. Unity verfügt über eine integrierte Physik-Engine, die die Bewegung von Körpern steuert, Kollisionen behandelt und die Auswirkungen externer Kräfte auf Objekte hinzufügt. Dies alles wird mithilfe der Komponente implementiert. Für Charaktere ist es jedoch nützlich, ein flexibleres Tool zu haben, das mit der physischen Welt interagiert und Entwicklern gleichzeitig mehr Kontrolle über das Verhalten des Objekts gibt. Rigidbody2D Wie ich bereits erwähnt habe, mussten Entwickler in früheren Versionen von Unity die gesamte Logik selbst implementieren. In Unity 2023 wurde der Komponente jedoch eine neue Methode hinzugefügt, die eine flexible Steuerung des physischen Objekts ermöglicht und gleichzeitig alle erforderlichen Informationen über die ausgeführte Bewegung bereitstellt. Rigidbody2D Slide Beginnen wir mit der Erstellung einer Klasse, die die grundlegende Logik für die Bewegung von Charakteren in der physischen Welt enthält. Diese Klasse verwendet im Modus, den wir unserem Charakter bereits hinzugefügt haben. Als Erstes fügen wir also einen Verweis auf diese Komponente hinzu. CharacterBody Rigidbody2D Kinematic public class CharacterBody : MonoBehaviour { [SerializeField] private Rigidbody2D _rigidbody; } Manchmal ist es für die Dynamik der Charakterbewegung erforderlich, dass die Schwerkraft stärker als üblich wirkt. Um dies zu erreichen, fügen wir einen Schwerkrafteinflussfaktor mit einem Anfangswert von 1 hinzu, und dieser Faktor kann nicht kleiner als 0 sein. [Min(0)] [field: SerializeField] public float GravityFactor { get; private set; } = 1f; Außerdem müssen wir definieren, welche Objekte als unpassierbare Flächen betrachtet werden. Dazu erstellen wir ein Feld, in dem wir die erforderlichen Ebenen angeben können. [SerializeField] private LayerMask _solidLayers; Wir werden die Geschwindigkeit des Charakters begrenzen, um zu verhindern, dass er zu hohe Geschwindigkeiten entwickelt, beispielsweise aufgrund äußerer Einflüsse, einschließlich der Schwerkraft. Wir setzen den Anfangswert auf 30 und beschränken die Möglichkeit, im Inspektor einen Wert kleiner als 0 festzulegen. [Min(0)] [SerializeField] private float _maxSpeed = 30; Beim Bewegen entlang einer Oberfläche möchten wir, dass die Figur immer an dieser haften bleibt, wenn der Abstand zwischen ihnen gering genug ist. [Min(0)] [SerializeField] private float _surfaceAnchor = 0.01f; Obwohl wir entschieden haben, dass die Oberflächen in unserem Spiel nur horizontal oder vertikal sein sollen, werden wir für alle Fälle den maximalen Neigungswinkel der Oberfläche angeben, auf dem die Figur stabil stehen kann, mit einem Anfangswert von 45º. [Range(0, 90)] [SerializeField] private float _maxSlop = 45f; Über den Inspektor möchte ich auch die aktuelle Geschwindigkeit der Figur und ihren Zustand sehen, daher füge ich zwei Felder mit dem Attribut hinzu. SerializeField [SerializeField] private Vector2 _velocity; [field: SerializeField] public CharacterState State { get; private set; } Ja, hier habe ich eine neue, noch nicht definierte Entität eingeführt. Wir werden dies weiter besprechen. CharacterState Charakterzustände Um die Entwicklung unseres Plattformspiels zu vereinfachen, definieren wir nur zwei Hauptcharakterzustände. Der erste Zustand ist , ein Zustand, in dem die Spielfigur sicher auf der Oberfläche steht. In diesem Zustand kann sich die Spielfigur frei auf der Oberfläche bewegen und von ihr springen. „Geerdet“ Der zweite ist , ein Zustand des freien Falls, bei dem sich die Spielfigur in der Luft befindet. Das Verhalten der Spielfigur in diesem Zustand kann je nach den Besonderheiten des Plattformspiels variieren. In einem allgemeinen, der Realität nahekommenden Fall bewegt sich die Spielfigur unter dem Einfluss des anfänglichen Impulses und kann ihr Verhalten nicht beeinflussen. Bei Plattformspielen wird die Physik jedoch häufig zugunsten der Bequemlichkeit und der Spieldynamik vereinfacht: Beispielsweise können wir in vielen Spielen sogar im freien Fall die horizontale Bewegung der Spielfigur steuern. In unserem Fall ist dies ebenfalls möglich, ebenso wie die beliebte Mechanik des Doppelsprungs, die einen zusätzlichen Sprung in die Luft ermöglicht. Airborne Lassen Sie uns die Zustände unseres Charakters im Code darstellen: /// <summary> /// Describes the state of <see cref="CharacterBody"/>. /// </summary> public enum CharacterState { /// <summary> /// The character stays steady on the ground and can move freely along it. /// </summary> Grounded, /// <summary> /// The character is in a state of free fall. /// </summary> Airborne } Es ist erwähnenswert, dass es noch viele weitere Zustände geben kann. Wenn das Spiel beispielsweise geneigte Flächen enthält, kann sich die Figur in einem Gleitzustand befinden, in dem sie sich nicht frei nach rechts oder links bewegen kann, sondern den Hang hinunterrutschen kann. In einem solchen Zustand kann die Figur auch springen und sich vom Hang abstoßen, aber nur in Hangrichtung. Ein anderer möglicher Fall ist das Gleiten entlang einer vertikalen Wand, bei dem der Einfluss der Schwerkraft abgeschwächt ist und die Figur sich horizontal abstoßen kann. Begrenzung der Bewegungsgeschwindigkeit Wir haben bereits ein privates Feld definiert, aber wir müssen in der Lage sein, diesen Wert von außen abzurufen und festzulegen, während wir die Höchstgeschwindigkeit des Charakters begrenzen. Dies erfordert einen Vergleich des angegebenen Geschwindigkeitsvektors mit der maximal zulässigen Geschwindigkeit. _velocity Dies kann durch die Berechnung der Länge des Geschwindigkeitsvektors oder, mathematisch ausgedrückt, seiner Größe erfolgen. Die Struktur enthält bereits eine , die uns dies ermöglicht. Wenn also die Größe des übergebenen Vektors die maximal zulässige Geschwindigkeit überschreitet, sollten wir die Richtung des Vektors beibehalten, aber seine Größe begrenzen. Dazu multiplizieren wir mit dem normalisierten Geschwindigkeitsvektor (ein normalisierter Vektor ist ein Vektor mit derselben Richtung, aber einer Größe von 1). Vector2 magnitude _maxSpeed So sieht es im Code aus: public Vector2 Velocity { get => _velocity; set => _velocity = value.magnitude > _maxSpeed ? value.normalized * _maxSpeed : value; } Schauen wir uns nun genauer an, wie der Betrag eines Vektors berechnet wird. Er wird durch die Formel definiert: Die Berechnung der Quadratwurzel ist eine ressourcenintensive Operation. Obwohl die Geschwindigkeit in den meisten Fällen das Maximum nicht überschreitet, müssen wir diesen Vergleich dennoch mindestens einmal pro Zyklus durchführen. Wir können diese Operation jedoch erheblich vereinfachen, wenn wir das Quadrat des Vektorbetrags mit dem Quadrat der maximalen Geschwindigkeit vergleichen. Dazu führen wir ein zusätzliches Feld ein, um das Quadrat der Maximalgeschwindigkeit zu speichern, und berechnen es einmal in der Methode: Awake private float _sqrMaxSpeed; private void Awake() { _sqrMaxSpeed = _maxSpeed * _maxSpeed; } Die Geschwindigkeitseinstellung kann nun noch optimaler vorgenommen werden: public Vector2 Velocity { get => _velocity; set => _velocity = value.sqrMagnitude > _sqrMaxSpeed ? value.normalized * _maxSpeed : value; } Dadurch vermeiden wir unnötige Berechnungen und verbessern die Leistung bei der Verarbeitung der Bewegungsgeschwindigkeit des Charakters. Methode der Starrkörperbewegung Wie ich bereits erwähnt habe, hat Unity eine neue Methode hinzugefügt, die die Entwicklung unseres erheblich vereinfacht. Bevor diese Methode jedoch verwendet werden kann, müssen die Regeln definiert werden, nach denen sich das Objekt im Raum bewegt. Dieses Verhalten wird durch die Struktur festgelegt. Slide() CharacterBody Rigidbody2D.SlideMovement Lassen Sie uns ein neues Feld einführen und seine Werte festlegen. _slideMovement private Rigidbody2D.SlideMovement _slideMovement; private void Awake() { _sqrMaxSpeed = _maxSpeed * _maxSpeed; _slideMovement = CreateSlideMovement(); } private Rigidbody2D.SlideMovement CreateSlideMovement() { return new Rigidbody2D.SlideMovement { maxIterations = 3, surfaceSlideAngle = 90, gravitySlipAngle = 90, surfaceUp = Vector2.up, surfaceAnchor = Vector2.down * _surfaceAnchor, gravity = Vector2.zero, layerMask = _solidLayers, useLayerMask = true, }; } Es ist wichtig zu erklären, dass bestimmt, wie oft ein Objekt infolge einer Kollision die Richtung ändern kann. Zum Beispiel, wenn sich die Figur neben einer Wand in der Luft befindet und der Spieler versucht, sie nach rechts zu bewegen, während die Schwerkraft darauf einwirkt. Daher wird für jeden Aufruf der Methode ein nach rechts und unten gerichteter Geschwindigkeitsvektor festgelegt. Beim Auftreffen auf die Wand wird der Bewegungsvektor neu berechnet und das Objekt bewegt sich weiter nach unten. maxIterations Slide() Wenn in einer solchen Situation der Wert auf 1 gesetzt wäre, würde das Objekt gegen die Wand stoßen, anhalten und dort praktisch stecken bleiben. maxIterations Die Werte für und wurden zuvor definiert. Ausführlichere Informationen zu den anderen Feldern finden Sie . maxIterations layerMask in der offiziellen Strukturdokumentation Zum Schluss das Bewegen der Figur Jetzt ist alles bereit, um Captain in Bewegung zu setzen. Wir werden dies in tun – einem Callback in Unity, der für die Handhabung physikalischer Vorgänge entwickelt wurde. In den letzten Jahren hat das Unity-Team die Handhabung 2D-Physik erheblich verbessert. Derzeit kann die Verarbeitung im Callback oder sogar durch eigenständiges Aufrufen der erforderlichen Methode erfolgen. FixedUpdate Update In diesem Beispiel verwenden wir jedoch die traditionelle und bewährte Methode . Bevor wir fortfahren, sollten wir noch ein paar Worte zum Wert von verlieren. FixedUpdate Time.fixedDeltaTime Um die Vorhersagbarkeit der Spielphysik zu gewährleisten, wird die Simulation in Iterationen in festen Zeitintervallen durchgeführt. Dies garantiert, dass Änderungen der FPS oder Verzögerungen das Objektverhalten nicht beeinflussen. Zu Beginn jedes Zyklus berücksichtigen wir die Wirkung der Schwerkraft auf das Objekt. Da die Schwerkraft durch den Vektor der freien Fallbeschleunigung gegeben ist, können wir die Geschwindigkeitsänderung des Objekts über die Zeit mit der folgenden Formel berechnen: Δv Δt wobei die konstante Beschleunigung des Objekts ist. In unserem Fall ist es die Erdbeschleunigung unter Berücksichtigung des von uns eingeführten Koeffizienten — . Daher kann wie folgt berechnet werden: a Physics2D.gravity * GravityFactor Δv Time.fixedDeltaTime * GravityFactor * Physics2D.gravity Das Endergebnis, bei dem wir die Geschwindigkeit ändern, sieht folgendermaßen aus: Velocity += Time.fixedDeltaTime * GravityFactor * Physics2D.gravity; Jetzt können wir die Starrkörperbewegung des Charakters ausführen: var slideResults = _rigidbody.Slide( _velocity, Time.fixedDeltaTime, _slideMovement); Die Variable ist ein Wert der Struktur und speichert die Ergebnisse der Bewegung. Die wichtigsten Felder dieses Ergebnisses sind für uns , das Ergebnis der Kollision mit der Oberfläche während der Bewegung, und — das Ergebnis eines Abwärtswurfs, der dabei hilft festzustellen, ob der Charakter auf einer stabilen Oberfläche steht. slideResults SlideResults slideHit surfaceHit Umgang mit Kollisionen Bei Kollisionen mit Oberflächen ist es wichtig, die Geschwindigkeit der Figur in Richtung der Oberfläche zu begrenzen. Ein einfaches Beispiel: Wenn die Figur still auf dem Boden steht, sollte sie unter dem Einfluss der Schwerkraft nicht weiter an Geschwindigkeit gewinnen. Am Ende jedes Zyklus sollte ihre Geschwindigkeit Null betragen. Ähnlich sollte die Figur, wenn sie sich nach oben bewegt und an die Decke stößt, ihre gesamte vertikale Geschwindigkeit verlieren und anfangen, sich nach unten zu bewegen. Die Ergebnisse von Kollisionen, und , werden durch Werte der Struktur dargestellt, die die Normale der Kollisionsoberfläche enthält. slideHit surfaceHit RaycastHit2D Die Geschwindigkeitsbegrenzung kann berechnet werden, indem die Projektion des ursprünglichen Geschwindigkeitsvektors auf die Kollisionsnormale vom Geschwindigkeitsvektor selbst abgezogen wird. Dies geschieht mithilfe des . Schreiben wir eine Methode, die diese Operation durchführt: Skalarprodukts private static Vector2 ClipVector(Vector2 vector, Vector2 hitNormal) { return vector - Vector2.Dot(vector, hitNormal) * hitNormal; } Integrieren wir diese Methode nun in unser . Hier werden wir für die Geschwindigkeit nur begrenzen, wenn sie nach unten gerichtet ist, da der Cast, der bestimmt, ob sich das Objekt auf der Oberfläche befindet, immer ausgeführt wird, um den Kontakt mit dem Boden zu überprüfen. FixedUpdate surfaceHit private void FixedUpdate() { Velocity += Time.fixedDeltaTime * GravityFactor * Physics2D.gravity; var slideResults = _rigidbody.Slide( _velocity, Time.fixedDeltaTime, _slideMovement); if (slideResults.slideHit) { _velocity = ClipVector(_velocity, slideResults.slideHit.normal); } if (_velocity.y <= 0 && slideResults.surfaceHit) { var surfaceHit = slideResults.surfaceHit; _velocity = ClipVector(_velocity, surfaceHit.normal); } } Diese Implementierung ermöglicht es, die Bewegung des Charakters richtig zu steuern, eine unerwünschte Beschleunigung bei Kollisionen mit verschiedenen Oberflächen zu vermeiden und die Bewegung der Charaktere im Spiel vorhersehbar und reibungslos zu gestalten. Den Zustand des Charakters bestimmen Am Ende jedes Zyklus muss festgestellt werden, ob sich die Figur auf einer festen Oberfläche befindet (geerdeter Zustand) oder im freien Fall (oder, wie wir es definiert haben, im kontrollierten Fall – in der Luft befindlicher Zustand) ist. Damit davon ausgegangen werden kann, dass sich der Charakter im Zustand „geerdet“ befindet, muss seine vertikale Geschwindigkeit zunächst null oder negativ sein, was wir durch den Wert von bestimmen. _velocity.y Ein weiteres wichtiges Kriterium ist das Vorhandensein einer Oberfläche unter den Füßen des Charakters, die wir anhand der Ergebnisse der Rigidbody-Bewegung ermitteln, und zwar durch das Vorhandensein von . surfaceHit Der dritte Faktor ist der Neigungswinkel der Oberfläche, den wir anhand der Normalen dieser Oberfläche analysieren, also dem Wert von . Dieser Winkel muss mit verglichen werden — dem maximal möglichen Winkel der Oberfläche, auf dem die Figur stabil stehen kann. surfaceHit.normal _maxSlop Bei einer vollständig vertikalen Oberfläche ist die Normale streng horizontal, d. h. ihr Vektorwert ist (1, 0) oder (-1, 0). Bei einer horizontalen Oberfläche ist der Wert der Normalen (0, 1). Je kleiner der Neigungswinkel, desto größer ist der Wert von . Für den Winkel kann dieser Wert wie folgt berechnet werden: y alpha Da unser Winkel in Grad angegeben ist und die Funktion $\cos$ Bogenmaß erfordert, lässt sich die Formel wie folgt umwandeln: Lassen Sie uns dazu ein neues Feld einführen und es in der Methode berechnen. Awake private float _minGroundVertical; private void Awake() { _minGroundVertical = Mathf.Cos(_maxSlop * Mathf.PI / 180f); //... } Aktualisieren wir nun unseren Code in und überprüfen alle oben genannten Bedingungen. FixedUpdate if (_velocity.y <= 0 && slideResults.surfaceHit) { var surfaceHit = slideResults.surfaceHit; Velocity = ClipVector(_velocity, surfaceHit.normal); State = surfaceHit.normal.y >= _minGroundVertical ? CharacterState.Grounded : CharacterState.Airborne; } else { State = CharacterState.Airborne; } Mithilfe dieser Logik können wir genau bestimmen, wann sich die Figur auf dem Boden befindet, und richtig auf Änderungen ihres Zustands reagieren. CharacterBody zum Captain hinzufügen Nachdem unsere CharacterBody-Komponente nun fertig ist, besteht der letzte Schritt darin, sie unserem Captain hinzuzufügen. Wählen Sie in der Szene das Captain-Objekt aus und fügen Sie ihm die Komponente hinzu. CharacterBody Vergessen Sie nicht, den Rigidbody wie in der Abbildung oben gezeigt zu konfigurieren. Stellen Sie den Schwerkraftfaktor auf 3 ein und wählen Sie die Standardoption für die feste Ebene. Jetzt können Sie das Spiel starten und mit der Einstellung verschiedener Geschwindigkeitswerte experimentieren, um zu beobachten, wie sich unsere Figur in der Szene bewegt. Zusammenfassung für jetzt Natürlich müssen wir noch Charaktersteuerungen hinzufügen. Da dieser Artikel jedoch bereits recht lang geworden ist, werde ich die Steuerung des Charakters mithilfe des neuen Eingabesystems im nächsten Artikel ausführlich beschreiben: „Erstellen eines 2D-Charakter-Controllers in Unity: Teil 2.“ Sie können das vollständige Projekt, das in diesem Artikel beschrieben wird, hier herunterladen: und alles in der Praxis überprüfen, falls Sie auf Schwierigkeiten stoßen. Die Entwicklung eines Charakter-Controllers ist ein wichtiger Aspekt bei der Erstellung eines 2D-Plattformspiels, da sie die weitere Entwicklung des Spiels bestimmt. Sie beeinflusst, wie einfach dem Verhalten des Haupthelden oder der Feinde neue Funktionen hinzugefügt werden können. Daher ist es sehr wichtig, die Grundlagen zu verstehen, um Ihr eigenes Spiel unabhängig entwickeln zu können. Treasure Hunters