🏠 Startseite

Unity 2D Tutorial für Einsteiger: Grundlagen der Bewegung

In diesem einführenden Tutorial schauen wir uns an, wie Bewegung in Unity 2D grundsätzlich funktioniert. Nicht durch das Kopieren von Code, sondern durch Verständnis: wie Raum, Zeit und der Rhythmus der Frames beeinflussen, wie sich ein Objekt im Spiel bewegt.

Ein häufiger Anfängerfehler ist es, fertigen Bewegungscode zu kopieren, ohne zu verstehen, warum er funktioniert. Das Ergebnis ist oft ein Spiel, das sich seltsam verhält: Die Figur wird auf Diagonalen schneller, bewegt sich auf verschiedenen PCs unterschiedlich, fällt durch Objekte hindurch oder „ruckelt“ ohne ersichtlichen Grund. Solche Bugs lassen sich kaum beheben, wenn die Grundlagen fehlen.

Wir gehen Schritt für Schritt von einfachen Verschiebungen hin zu einer bewussten Entscheidung zwischen verschiedenen Bewegungsansätzen, damit du nicht nur verstehst, wie etwas funktioniert, sondern auch warum.

Dieses Tutorial hilft außerdem dabei, die Verbindung zwischen der internen Logik der Engine und dem, was du auf dem Bildschirm siehst, zu erkennen. Zahlen, Vektoren und Zeit hören auf, abstrakt zu sein — sie werden Teil eines gemeinsamen Raums, in dem das Objekt existiert und den du mehr fühlst als berechnest.

💡 Das ist keine Liste von Begriffen zum Auswendiglernen, sondern einfach eine Karte unseres heutigen Weges.

🛠 Was wir heute zähmen:

📍
Raum Koordinaten und Position in der 2D-Welt.
📐
Vektoren Richtung ist gar nicht so kompliziert.
🎞️
Frames Wie Unity Bewegung „zeichnet“.
⏱️
Rhythmus Warum Zeit im Spiel gemeinsam sein muss.
🏗️
Zwei Bewegungswege Geometrie (Transform) und Physik (Rigidbody).
🕹️
Input Wie die Engine die Absicht des Spielers wahrnimmt.

Koordinatenraum der 2D-Welt

Nachdem du ein 2D-Projekt in Unity erstellt und geöffnet hast, wirkt die Szene zunächst leer. Doch selbst diese „Leere“ ist in Unity bereits ein Raum. Jedes Spielobjekt, das du hinzufügst, besitzt immer eine Position, die durch Koordinaten definiert ist.

In 2D-Spielen interessieren uns vor allem zwei Achsen: X und Y. Die X-Achse steuert die Bewegung nach links und rechts, die Y-Achse die Bewegung nach oben und unten. Die Position eines Objekts ist einfach ein Punkt in diesem Raum.

💡 Wichtig ist, sich daran zu erinnern, dass Unity eine 3D-Engine ist – selbst wenn du ein 2D-Spiel entwickelst. Tatsächlich besitzt jedes Objekt auch eine Z-Koordinate. Diese Achse verläuft entlang der Blickrichtung der Kamera und bleibt in 2D meist bei 0. Manchmal ist jedoch genau der Z-Wert der Grund dafür, dass ein Objekt „verschwindet“ oder sich an einer anderen Stelle befindet als erwartet.

Unten siehst du ein typisches Koordinatengitter. Das ist keine abstrakte Mathematik – genau in diesem Raum lebt deine Unity-Szene. Wenn du ein Objekt im Scene-Fenster bewegst, änderst du in Wirklichkeit seine Koordinaten in diesem System.

Koordinatengitter mit X- und Y-Achsen im zweidimensionalen Raum
Koordinatengitter des 2D-Raums: X- und Y-Achsen.

Im Moment musst du noch nichts berechnen oder Formeln auswendig lernen. Es reicht, zu spüren, dass die Unity-Szene und dieses Gitter dieselbe Welt darstellen – nur auf unterschiedliche Weise visualisiert.

Positionsangabe und Beispiele

Wir haben bereits erwähnt, dass die Position eines Objekts im Koordinatensystem – und damit auch in der Unity-Szene – durch seine Position bestimmt wird. Eine Position wird als Zahlenpaar (x, y, z) angegeben, wobei x für die Bewegung nach links und rechts steht, y für oben und unten und z für näher an oder weiter weg von der Kamera.

In 2D-Spielen wird die Z-Koordinate meist nicht verwendet oder bleibt bei 0. Dennoch existiert sie weiterhin und kann in manchen Fällen Einfluss auf die Darstellung von Objekten haben.

Unten siehst du einige Beispiele für Positionen in diesem Raum. Der rote Kreis befindet sich bei (1, 1), der grüne bei (3, -2) und der blaue bei (-3.5, -2.5). Das sind einfach unterschiedliche Koordinaten in ein und derselben Welt.

Wichtig ist zunächst, Position als einen Ort im Raum zu verstehen – den Punkt, an dem sich das Objekt gerade befindet. Wir sprechen hier noch nicht über Bewegung oder Richtung, sondern nur darüber, wo ein Objekt liegt.

Koordinatengitter mit drei Beispielpositionen von Objekten
Koordinatengitter des 2D-Raums mit Beispielkoordinaten von Objekten.

💡 Die Position eines Objekts muss kein ganzzahliger Wert sein. Für eine präzise Platzierung verwendet Unity Gleitkommazahlen – also Werte mit Nachkommastellen wie -3.5 oder 0.25.

Was ist ein Vektor

Jetzt können wir einen wichtigen Begriff einführen, mit dem Unity ständig arbeitet — den Vektor. Noch ohne Formeln und ohne Komplexität. Im einfachsten Sinne ist ein Vektor ein gerichteter Streckenabschnitt.

Ein Vektor besitzt eine Richtung und eine Länge. Man kann ihn sich wie einen Pfeil vorstellen: Er beginnt an einem Punkt und zeigt auf einen anderen. Ein solcher Pfeil zeigt nicht nur, wo sich etwas befindet, sondern beschreibt die Beziehung zwischen zwei Punkten im Raum.

Betrachtet man die Position eines Objekts, kann man einen Vektor als eine Strecke auffassen, die im Ursprung (0, 0) beginnt und an dem Punkt endet, an dem sich das Objekt befindet. Genau so „sieht“ Unity eine Position im Raum — nicht als einzelne Zahlen, sondern als Richtung und Entfernung vom Ursprung.

In der Abbildung unten werden Objektpositionen nicht nur als Punkte, sondern auch als Pfeile dargestellt, die vom Koordinatenursprung ausgehen. Diese Pfeile sind die Vektoren, die die Position jedes Objekts im 2D-Raum beschreiben.

Koordinatengitter mit Objektpositionen, dargestellt als Vektorpfeile
Objektpositionen im 2D-Raum, dargestellt als Vektoren vom Ursprung aus.

💡 Dieselben Punkte auf dem Koordinatengitter würden in Unity so beschrieben:


// Roter Punkt (1, 1)
redCircle.transform.position = new Vector2(1f, 1f);

// Grüner Punkt (3, -2)
greenCircle.transform.position = new Vector2(3f, -2f);

// Blauer Punkt (-3.5, -2.5)
blueCircle.transform.position = new Vector2(-3.5f, -2.5f);

Das sind einfach unterschiedliche Positionen im selben Raum, formuliert in der „Sprache“ von Unity.

Wichtig ist, sich eine einfache Idee zu merken: Ein Vektor ist eine Art, Position und Richtung im Raum zu beschreiben.

Bezugspunkt: globaler und lokaler Raum

Bis zu diesem Punkt haben wir stillschweigend eine wichtige Sache benutzt — einen Bezugspunkt. Auf dem Koordinatengitter ist das der Punkt (0, 0), von dem aus alle Positionen und Richtungen gemessen werden.

Einen solchen Raum nennt man global. In ihm existieren alle Objekte in derselben gemeinsamen Welt und verwenden dasselbe Koordinatensystem.

In Spielen ist es jedoch oft sinnvoll, ein Objekt nicht aus der Sicht der gesamten Welt zu betrachten, sondern relativ zu einem anderen Objekt oder sogar relativ zu sich selbst. In diesem Fall entsteht ein lokaler Raum — mit einem eigenen Bezugspunkt.

Stell dir ein einfaches Beispiel vor: Ein Auto fährt vor dir von links nach rechts vorbei. Für dich bewegt es sich nach rechts, für den Fahrer im Auto fährt es jedoch geradeaus. Das zeigt, dass die Achsenrichtungen im globalen und im lokalen Koordinatensystem nicht identisch sein müssen.

Ein weiteres Beispiel ist die Objekt-Hierarchie. Ist ein Objekt ein Kindobjekt, wird seine lokale Position nicht vom Weltzentrum aus gemessen, sondern von der Position des Elternobjekts. Aus Sicht der Welt kann sich das Objekt an einem Ort befinden, aus Sicht des Elternobjekts jedoch an einem anderen.

Stell dir vor, auf einem Tisch steht eine Tasse, und du möchtest sie vom Mittelpunkt des Tisches in eine Ecke verschieben. Du musst dafür nicht die Position der Tasse relativ zur gesamten Küche berechnen — du bewegst sie einfach relativ zur Tischoberfläche.

Globale und lokale Koordinatensysteme im 2D-Raum
Globale und lokale Bezugssysteme der Koordinaten.

In dieser Abbildung sieht man, dass die Positionskoordinaten des grünen Kindobjekts vom Bezugspunkt abhängen. Relativ zum Weltursprung beträgt seine Position (2, 3), relativ zum Elternobjekt jedoch (-1, -2). Die tatsächliche Position des Objekts auf dem Bildschirm ändert sich dabei nicht — nur das Koordinatensystem, in dem wir es beschreiben.

Das Wichtigste: Eine Position wird immer von einem Bezugspunkt aus gemessen. Welcher Punkt das ist, hängt davon ab, in welchem Raum wir das Objekt betrachten.

Richtung und Verschiebung: wie ein Vektor einen Punkt bewegt

Ein Vektor besitzt zwei zentrale Eigenschaften: Richtung und Länge. Stellt man sich einen Vektor als Pfeil vor, zeigt die Richtung, wohin der Pfeil „blickt“, und die Länge, wie weit er verschiebt.

Genau deshalb eignen sich Vektoren so gut als Verschiebung. Wir nehmen die aktuelle Position eines Objekts (als Bezugspunkt) und addieren einen Verschiebungsvektor dazu. Das Ergebnis ist eine neue Position.

💡 Das lässt sich sehr einfach merken: Position + Verschiebung = neue Position. Noch nicht Bewegung über die Zeit — nur das Verschieben eines Punktes im Raum.

Möchten wir ein Objekt zum Beispiel nach rechts verschieben, addieren wir einen Vektor mit positivem X-Wert. Wollen wir es nach links verschieben, verwenden wir einen Vektor mit negativem X-Wert. Dasselbe gilt für Y: positives Y bewegt nach oben, negatives Y nach unten.


// aktuelle Objektposition (Punkt). Beispiel: (1, -1)
Vector2 p = transform.position;

// Verschiebung um 2 nach rechts → (1, -1) + (2, 0)
p = p + new Vector2(2f, 0f);

// Verschiebung um 1 nach links und 3 nach oben → (3, -1) + (-1, 3)
p = p + new Vector2(-1f, 3f);

// neue Position anwenden. Endposition: (2, 2)
transform.position = p;
Verschiebung der Objektposition mithilfe eines Vektors vom Startpunkt zum Endpunkt
Positionsverschiebung als Vektor: Der Pfeil zeigt Richtung und Länge der Verschiebung vom Startpunkt zum Endpunkt.

Eine weitere nützliche Idee: Verschiebungen lassen sich addieren. Wenn du erst eine Verschiebung und dann eine zweite hinzufügst, ist das dasselbe, als würdest du ihre Summe einmal addieren. Wenn der Spieler zum Beispiel gleichzeitig „rechts“ und „hoch“ drückt, fasst Unity beide Verschiebungen zu einem diagonalen Vektor zusammen.

Horizontale und vertikale Richtungen werden so häufig verwendet, dass Unity dafür bereits feste Bezeichnungen bereitstellt. Das ist nichts Neues — nur praktische Namen für bekannte Vektoren.


// Standardrichtungen in Unity 2D
Vector2.right  // (1, 0)
Vector2.left   // (-1, 0)
Vector2.up     // (0, 1)
Vector2.down   // (0, -1)

Diese Vektoren hängen nicht von der Position eines Objekts ab. Sie zeigen immer eine Richtung an und haben die Länge 1. Im Grunde sind es vorgefertigte Pfeile, die man immer wieder bequem verwenden kann.

Neben globalen Richtungen besitzt jedes Objekt auch seine eigenen lokalen Richtungen. Diese hängen davon ab, wie das Objekt im Raum gedreht und ausgerichtet ist.


// lokale Richtungen eines Objekts
transform.right // nach rechts relativ zum Objekt
transform.left  // nach links relativ zum Objekt
transform.up    // nach oben relativ zum Objekt
transform.down  // nach unten relativ zum Objekt
Lokale Richtungen eines Objekts in Unity: transform.right und transform.up bei Rotation
Lokale Richtungen eines Objekts: Die Achsen transform.right und transform.up drehen sich gemeinsam mit dem Objekt.

Im Gegensatz zu Vector2.right oder Vector2.up können sich diese Richtungen ändern. Wird das Objekt gedreht, drehen sich auch seine lokalen Achsen mit. Wichtig: Eine Richtung kann global für die gesamte Welt sein oder relativ — abhängig vom jeweiligen Objekt.

Das Ziel im Blick: Richtung durch Subtraktion

Bis hierhin haben wir über einfache und intuitive Richtungen gesprochen — nach oben, unten, links und rechts. In Spielen braucht man jedoch oft etwas anderes: eine Richtung nicht „allgemein“, sondern zu einem konkreten Ziel.

Dafür verwendet man die Subtraktion von Vektoren. Wir nehmen die Position des Ziels und ziehen davon die aktuelle Position des Objekts ab. Das Ergebnis ist ein Richtungsvektor — ein Pfeil, der direkt vom Objekt auf das Ziel zeigt.


// Position des Objekts und Position des Ziels
Vector2 current = transform.position;
Vector2 target = targetPosition;

// Richtungsvektor zum Ziel
Vector2 direction = target - current;

// Länge des Vektors (Entfernung zum Ziel)
float distance = direction.magnitude;

// Quadrat der Vektorlänge (quadratische Entfernung)
float distanceSqr = direction.sqrMagnitude;
Vektorsubtraktion: Richtung und Entfernung von der aktuellen Position zum Ziel
Durch das Subtrahieren von Positionen entsteht ein Richtungsvektor zum Ziel. Seine Länge entspricht der Entfernung zwischen dem aktuellen Punkt und dem Ziel.

💡 magnitude liefert die tatsächliche Entfernung zum Ziel, erfordert jedoch die Berechnung einer Quadratwurzel, was relativ teuer ist. In Situationen mit vielen solchen Abfragen verwendet man daher oft die quadratische Entfernung und vergleicht sie mit dem Quadrat eines Schwellenwerts. sqrMagnitude ist schneller und wird häufig eingesetzt, wenn lediglich Entfernungen miteinander verglichen werden sollen.

Ein solcher Vektor ist besonders wichtig in Spielen. Er enthält sofort zwei Informationen: die Richtung zum Ziel und die Entfernung dorthin, ausgedrückt durch die Länge des Vektors.

Für den Moment reicht es, die Grundidee zu verstehen: Das Subtrahieren von Positionen ergibt einen Vektor, der die Frage beantwortet: „In welche Richtung und wie weit?“.

Frames: wie Bewegung entsteht

Bewegung existiert in einem Spiel nicht von selbst. Sie entsteht als Ergebnis einer aufeinanderfolgenden Abfolge von Zuständen, die Bild für Bild auf dem Bildschirm dargestellt werden.

Die Unity-Engine arbeitet in einem Zyklus. In jedem Durchlauf wird zuerst Code ausgeführt und ein neuer Zustand der Szene berechnet: Positionen der Objekte, ihre Rotationen und die Werte von Variablen. Anschließend wird dieser Zustand als einzelnes Frame auf dem Bildschirm angezeigt. Danach beginnt der Zyklus von vorn.


// wird einmal pro Frame aufgerufen
void Update()
{
    // aktuelle Objektposition
    Vector2 p = transform.position;

    // kleine Verschiebung nach rechts
    p = p + new Vector2(1f, 0f);

    // neue Position anwenden
    transform.position = p;
}

Dieser Code wird in jedem Frame ausgeführt. Jedes Mal ändert sich die Position des Objekts ein kleines Stück, und Unity rendert den aktualisierten Zustand der Szene.

Würde man die Position nur einmal ändern, würde das Objekt einfach an einer neuen Stelle erscheinen. Wenn diese kleinen Änderungen jedoch von Frame zu Frame erfolgen, beginnt das Auge, sie als kontinuierliche Bewegung wahrzunehmen.

Bewegung ist damit keine eigenständige Entität, sondern das Ergebnis einer fortlaufenden Veränderung der Objektposition zwischen Frames relativ zum Beobachter (der Kamera).

Abfolge von Objektpositionen über mehrere Frames hinweg
Dasselbe Objekt in mehreren aufeinanderfolgenden Frames. Eine kleine Positionsänderung zwischen den Frames wird als Bewegung wahrgenommen.

FPS und Zeit: warum Bewegung Frames berücksichtigen muss

Wir haben bereits gesehen, dass Bewegung als eine Abfolge von Frames entsteht. Doch hier stellt sich eine wichtige Frage: Was passiert, wenn die Anzahl der Frames pro Sekunde auf verschiedenen Computern unterschiedlich ist?

Stell dir zwei Computer vor. Einer rendert 50 Frames pro Sekunde, der andere 100. Auf dem leistungsstärkeren System wirkt das Bild flüssiger — aber wenn wir ein Objekt in jedem Frame um dieselbe Strecke verschieben, entsteht ein Problem.

Auf dem Computer mit 100 FPS wird der Code pro Sekunde doppelt so oft ausgeführt wie auf dem mit 50 FPS. Dadurch legt das Objekt auf dem schnelleren Rechner in derselben Zeit die doppelte Strecke zurück.

Um das zu vermeiden, muss Bewegung nicht an die Anzahl der Frames, sondern an die reale Zeit gekoppelt werden. In Unity geschieht das über den Wert Time.deltaTime.

Time.deltaTime gibt an, wie viel Zeit seit dem vorherigen Frame vergangen ist. Bei hoher FPS ist dieser Wert kleiner, bei niedriger FPS größer. Damit lässt sich die Größe der Verschiebung an die Aktualisierungsrate der Frames anpassen.


// wird einmal pro Frame aufgerufen
void Update()
{
    // aktuelle Objektposition
    Vector2 p = transform.position;

    // zeitbasierte Verschiebung
    p = p + new Vector2(1f, 0f) * Time.deltaTime;

    // neue Position anwenden
    transform.position = p;
}

Jetzt hängt die Verschiebung nicht mehr von der Anzahl der Frames ab, sondern davon, wie viel Zeit zwischen ihnen vergangen ist. Bei hoher FPS sind die Schritte kleiner, bei niedriger FPS größer — doch innerhalb einer Sekunde legt das Objekt stets dieselbe Strecke zurück.

Das Ergebnis: Auf schnellen Computern wirkt die Bewegung flüssiger, auf langsameren eventuell etwas ruckeliger, aber die pro Sekunde zurückgelegte Strecke bleibt auf allen Systemen gleich.

Zwei Bewegungsansätze in Unity

Bis hierhin haben wir über Bewegungsprinzipien im Allgemeinen gesprochen: Frames, Positionen, Verschiebungen und Zeit. Jetzt lassen sich diese Ideen direkt mit der Art und Weise verknüpfen, wie Bewegung in Unity umgesetzt wird.

In den meisten Fällen wird in Unity einer von zwei Ansätzen verwendet: positionale Geometrie und physikalische Simulation. Es gibt hier kein „gut“ oder „schlecht“ — sondern nur das, was für eine konkrete Aufgabe geeignet ist.

Bei positionaler Bewegung arbeiten wir direkt mit der Position eines Objekts und verändern seine Koordinaten im Raum. Diesen Ansatz haben wir bereits genutzt, indem wir die globale Position über transform.position geändert haben, sowie lokale Verschiebungen über transform.Translate.

Die größten Vorteile der positionalen Bewegung sind Einfachheit, volle Kontrolle und Vorhersehbarkeit. Wir wissen genau, wo sich das Objekt im nächsten Moment befinden wird.

Dieser Ansatz hat jedoch auch eine Einschränkung. Wenn wir die Position direkt verändern, ignorieren wir die physikalische Simulation. Besitzt ein Objekt einen Collider und ein Rigidbody, kann das direkte Setzen der Position zu unnatürlichem Verhalten oder zu verpassten Kollisionen führen.

In Situationen, in denen Physik und Interaktion mit der Umgebung wichtig sind, wird Bewegung in der Regel über ein Rigidbody realisiert. Dieser Ansatz lässt Objekte natürlicher reagieren, reduziert jedoch den direkten Einfluss des Codes.

Statt das Objekt direkt zu verschieben, beeinflussen wir seinen Zustand: Geschwindigkeit, Impuls oder andere physikalische Parameter.

Vergleich von Bewegung über Transform und Rigidbody bei einer Kollision mit einem Hindernis
Oben — positionale Bewegung über Transform: Das Objekt ignoriert die Form des Hindernisses. Unten — Bewegung über Rigidbody: Das Objekt interagiert mit der Geometrie der Szene.

Im Folgenden betrachten wir beide Ansätze getrennt und klären, in welchen Situationen welcher von ihnen am sinnvollsten ist.

Kriterium Transform (positional) Rigidbody (Physik)
Bedeutung Direkte Positionsänderung Bewegung als physikalischer Körper
Kontrolle Vollständig und vorhersehbar Teilweise an die Physik abgegeben
Kollisionen Können ignoriert werden Werden korrekt verarbeitet
Trägheit und Masse Nicht vorhanden Standardmäßig vorhanden
Typische Einsatzbereiche UI, Logik, einfache Objekte Charaktere, Actionspiele, Platformer

Nimmt ein Objekt nicht an der physikalischen Simulation teil und besitzt keinen physikalischen Körper, wird Bewegung in der Regel direkt über die Position umgesetzt.

Beispiel: direkte Positionsänderung


// Bewegung nach rechts durch Positionsänderung
void Update()
{
    transform.position += Vector3.right * 2f * Time.deltaTime;
}

Beispiel: lokale Verschiebung mit Translate


// Bewegung nach rechts im lokalen Raum des Objekts
void Update()
{
    transform.Translate(Vector3.right * 2f * Time.deltaTime);
}

Die Methode Translate ist praktisch, da sie das Objekt standardmäßig in seinem lokalen Raum bewegt — relativ zu seiner eigenen Ausrichtung und nicht zum Weltursprung.

Soll ein Objekt korrekt mit der Umgebung interagieren, Kollisionen haben sowie Masse und Trägheit besitzen, benötigt es einen physikalischen Körper: Collider und Rigidbody.

Beispiel: Bewegung über Kraft

Wichtig ist zu verstehen, dass Vektoren beim Wechsel zur physikalischen Bewegung nicht verschwinden. Sie werden weiterhin verwendet, um Richtung, Geschwindigkeit und Kraft zu definieren — nur verändern sie nun nicht mehr direkt die Position des Objekts, sondern beschreiben, wie sich der physikalische Körper bewegen soll.

Anstatt „das Objekt an eine Position zu setzen“, teilen wir der Physik mit, in welche Richtung und mit welcher Intensität auf den Körper eingewirkt werden soll. Die Position wird zum Ergebnis dieser Berechnung und nicht zu einem Wert, den wir selbst überschreiben.


// Krafteinwirkung auf einen physikalischen Körper
void FixedUpdate()
{
    rb.AddForce(Vector2.right * 10f);
}

In manchen Fällen ist selbst bei der Nutzung von Physik eine genauere Kontrolle nötig. Dann kann man direkt mit dem Zustand des Körpers arbeiten, zum Beispiel mit seiner Geschwindigkeit.

Beispiel: direkte Steuerung der Geschwindigkeit


// direktes Setzen der Geschwindigkeit (Unity 6+)
void FixedUpdate()
{
    rb.linearVelocity = new Vector2(2f, 0f);
    // in älteren Unity-Versionen wird rb.velocity verwendet
}

💡 Beachte: Die Physik in Unity läuft in einem eigenen Takt, der an die reale Zeit und nicht an die Framerate gebunden ist. Deshalb wird Bewegung über Rigidbody im FixedUpdate umgesetzt, und eine zusätzliche Skalierung mit Time.deltaTime ist in der Regel nicht notwendig.

Beide Ansätze haben ihre Stärken. Wichtig ist nicht, den „richtigen“ Weg zu wählen, sondern zu verstehen, welcher Ansatz zur aktuellen Aufgabe passt.

Jeder dieser Ansätze wird in separaten Tutorials auf der Website noch detaillierter behandelt.

Logik der Bewegungssteuerung

Bis zu diesem Punkt haben wir Bewegung als Ergebnis von Änderungen an Position, Zeit und physikalischen Eigenschaften betrachtet. Jetzt bleibt noch, das Ganze mit der Frage zu verbinden, wer die Bewegung steuert und wie diese Steuerung erfolgt.

Grundsätzlich gibt es auch hier zwei zentrale Ansätze: externe Steuerung und interne Steuerung.

Interne Steuerung bedeutet Bewegung, die durch Algorithmen, Animationen oder Spiellogik vorgegeben ist. Solche Beispiele haben wir bereits gesehen, wenn sich ein Objekt selbstständig bewegt, ohne Einfluss des Spielers. Dieser Ansatz hängt stark vom Spieldesign ab und besitzt keine einzige „richtige“ Lösung.

Externe Steuerung ist die Steuerung durch den Spieler. Die Eingabequelle kann dabei eine Tastatur, ein Gamepad, ein Touchscreen oder ein anderer Controller sein. Die Aufgabe des Spiels besteht darin, diese Eingabe zu erfassen, zu verarbeiten und in geeigneter Form zu nutzen.

Beispiel: Steuerung über Transform



using UnityEngine;
using UnityEngine.InputSystem;

void Update()
{
    float x = 0f;
    float y = 0f;

    if (Keyboard.current != null)
    {
        if (Keyboard.current.leftArrowKey.isPressed)
            x -= 1f;
        if (Keyboard.current.rightArrowKey.isPressed)
            x += 1f;

        if (Keyboard.current.downArrowKey.isPressed)
            y -= 1f;
        if (Keyboard.current.upArrowKey.isPressed)
            y += 1f;
    }
    // Bewegungssteuerung über die Position
    Vector2 direction = new Vector2(x, y);
    transform.Translate(direction * 2f * Time.deltaTime);
}

In diesem Fall verschieben wir das Objekt direkt und verwenden die Spielereingabe als Bewegungsrichtung. Dieser Ansatz ist einfach und eignet sich gut für Objekte, die nicht an der physikalischen Simulation teilnehmen.

Beispiel: Steuerung über Rigidbody



using UnityEngine;
using UnityEngine.InputSystem;

void FixedUpdate()
{
    float x = 0f;
    float y = 0f;

    if (Keyboard.current != null)
    {
        if (Keyboard.current.leftArrowKey.isPressed)
            x -= 1f;
        if (Keyboard.current.rightArrowKey.isPressed)
            x += 1f;

        if (Keyboard.current.downArrowKey.isPressed)
            y -= 1f;
        if (Keyboard.current.upArrowKey.isPressed)
            y += 1f;
    }

    Vector2 direction = new Vector2(x, y);
    // Bewegungssteuerung über einen physikalischen Körper
    rb.linearVelocity = direction * 2f;
}

Hier wird die Spielereingabe genutzt, um den Zustand des physikalischen Körpers zu steuern. Das Objekt reagiert auf Kollisionen, Trägheit und andere physikalische Eigenschaften der Szene.

Das Wichtigste aus diesem Abschnitt: Steuerung ist nicht Bewegung an sich. Sie ist lediglich eine Datenquelle, die anschließend in Richtung, Geschwindigkeit oder andere Bewegungsparameter übersetzt wird.

Zusammenhang zwischen Spielereingabe, Richtungsvektor und Objektbewegung
Die Spielereingabe wird in einen Richtungsvektor umgewandelt. Dieser Vektor wird als Verschiebung genutzt und in jedem Frame auf das Objekt angewendet.

Verschiedene Eingabe- und Steuerungsmethoden werden in separaten Tutorials noch ausführlicher behandelt.

Fazit

In diesem Tutorial haben wir keinen „richtigen Code“ gelernt. Stattdessen haben wir Schritt für Schritt untersucht, woraus Bewegung in einem Spiel überhaupt besteht: Raum, Positionen, Vektoren, Frames, Zeit und die Arten, wie wir auf ein Objekt einwirken.

Du hast gesehen, dass Bewegung weder Magie noch eine fertige Funktion ist, sondern eine Abfolge einfacher Entscheidungen. Wenn wir die Position ändern, ändern wir den Zustand. Wenn wir Zustände frameweise darstellen, entsteht Bewegung. Wenn wir Zeit und Kontext berücksichtigen, bleibt sie auf unterschiedlichen Systemen gleich.

Unity schreibt keinen einzigen Weg vor. Man kann ein Objekt direkt bewegen, man kann die Bewegung der Physik überlassen, oder man steuert es über den Spieler oder Algorithmen. Entscheidend ist nicht, den „besten“ Ansatz zu wählen, sondern zu verstehen, warum man sich für einen bestimmten entscheidet.

Wenn der Code nach diesem Tutorial nicht mehr wie eine Ansammlung von Zeilen wirkt, sondern wie eine Beschreibung dessen, was in der Welt passiert, dann ist das Ziel erreicht.

Als Nächstes werden wir einzelne Themen weiter vertiefen: Physik, Input, Kameras und Game Feel. Das Fundament dafür ist jetzt gelegt.