Startseite

Unity 2D Plattform-Tutorial – Teil 2: Springen, Kisten und mehr

Willkommen zu Teil 2 unseres Unity 2D Plattform-Tutorials. In Teil 1 hast du gelernt, wie man eine Spielfigur steuert. Jetzt baust du ein echtes Level – eines, durch das man gerne läuft.

Statt komplizierter Gegner oder Szenenwechsel konzentrieren wir uns auf die Spielwelt: Münzen zum Sammeln, Wände, Abgründe, ein leicht genervter Pilz… und etwas, das dich bis zum Ende begleitet.

Du lernst, wie man Objekte platziert, eine „klebrige Wand“ behebt, eine Plattform bewegt und einfache Logik für Gegner und Neustarts erstellt. Und wenn du den Ausgang erreichst – merkst du vielleicht, dass es gar nicht darum ging.

Öffne also Unity, atme tief durch und beginne – nicht weil du musst, sondern weil etwas leise darauf wartet, dass du es platzierst.

Schritt 1. Wandaufbau und der klebrige Wand-Glitch

Wir beginnen mit dem Hinzufügen einer vertikalen Wand zur Szene. Verwende den gleichen largeGround-Sprite wie für den Boden – dreh ihn einfach und stelle ihn senkrecht auf. Unity erstellt automatisch ein neues GameObject. Benenne es in Wall um.

Im Inspector der neuen Wand:

Drücke jetzt Play und probiere Folgendes: Lauf auf die Wand zu, springe daran hoch und halte die Bewegungstaste gedrückt. Die Ratte klammert sich an die Wand wie ein winziger Superheld. Das ist keine Magie – das ist Reibung.

Das passiert, weil Unitys Standard-Collider Reibung eingebaut haben. Um das zu beheben, weisen wir ein Physics Material 2D mit null Reibung zu.

Im Assets-Ordner:

Wähle jetzt das Rat-GameObject aus. Im Capsule Collider 2D-Component setze das Material auf noFriction.

Spiele die Szene erneut – die Ratte sollte nicht mehr an Wänden oder Plattformen hängenbleiben.

Vertikale Wand hinzugefügt und noFriction-Material der Ratte zugewiesen
Vertikale Wand hinzugefügt und noFriction-Material der Ratte zugewiesen.

Schritt 2. Münzen sammeln und einen Sound abspielen

Geben wir unserer Ratte etwas zum Einsammeln – Münzen!

Importiere das coin-Bild in dein Projekt: Bild hier herunterladen (wir verwenden die Münze aus diesem Sprite-Sheet). Ziehe sie dann in die Szene – Unity erstellt ein neues GameObject.

Wähle die Münze in der Hierarchy aus, dann im Inspector:

Erstelle ein neues Tag mit dem Namen Coin und weise es dem Münzobjekt zu.

Benenne die Münze in CoinPrefab um und ziehe sie dann in den Assets-Ordner, um ein Prefab zu erstellen.

Unity-Münzobjekt mit Collider und Coin-Tag
Das Münzobjekt ist eingerichtet: Circle Collider 2D hinzugefügt, Is Trigger aktiviert und der Tag Coin gesetzt.

Jetzt erstellen wir ein Skript zum Einsammeln der Münzen. Im Assets-Ordner:

Füge diesen Code in das Skript ein:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoinController : MonoBehaviour {

    // Sound, der beim Einsammeln einer Münze abgespielt wird
    public AudioClip CoinSound;

    // Münzzähler
    public int coin;

    void OnTriggerEnter2D (Collider2D other) {
        // Wenn das Objekt, das wir treffen, das Tag "Coin" hat
        if (other.tag == "Coin") {
            // Erhöhe den Münzzähler
            coin = coin + 1;

            // Spiele den Münz-Sound ab
            AudioSource.PlayClipAtPoint(CoinSound, transform.position);

            // Zerstöre die eingesammelte Münze
            Destroy(other.gameObject);
        }
    }
}

Füge das CoinController-Skript dem Rat-GameObject hinzu. Du kannst den Münzsound hier herunterladen: CoinSound.wav herunterladen. Importiere den CoinSound-Clip ins Projekt und weise ihn im Inspector dem Feld Coin Sound im Skript zu.

💡 Hinweis: Wir verwenden PlayClipAtPoint, daher wird der Ton im Welt-Raum abgespielt. Wenn er zu leise klingt, liegt das wahrscheinlich daran, dass der Audio Listener noch auf der Kamera sitzt. Du kannst das beheben, indem du entweder die Kamera näher an die Spielfigur bewegst oder den Audio Listener vom Kameraobjekt auf das Objekt Rat verschiebst.

Szene mit Münzobjekt und CoinController-Skript an der Ratte
Münze zur Szene hinzugefügt. CoinController-Skript der Ratte zugewiesen und Münz-Sound verbunden.

Schritt 3. Münzzähler mit TextMeshPro anzeigen

Zeigen wir an, wie viele Münzen die Ratte gesammelt hat – mit einem UI-Textfeld.

Gehe in der Hierarchy zu:

Wähle das Canvas-GameObject aus. Im Inspector:

Unity Canvas-Einstellungen für ein responsives UI-Layout
Canvas-Einstellungen: Scale With Screen Size und Expand für ein anpassbares UI.

Doppelklicke auf das Canvas in der Hierarchy, um die UI-Ansicht einzurahmen. Du siehst ein weißes Rechteck, das den sichtbaren Bereich des Bildschirms darstellt.

Wähle Text(TMP) und nimm folgende Änderungen vor:

TextMeshPro-Einstellungen für CoinCounterText in Unity
Einstellungen für CoinCounterText: Schriftgröße, Ausrichtung und automatische Anpassung.

Jetzt aktualisieren wir das CoinController-Skript, um diesen Text zu verbinden.

using UnityEngine;
using TMPro;

public class CoinController : MonoBehaviour
{
    // Sound beim Einsammeln von Münzen
    public AudioClip CoinSound;

    // Münzzähler
    public int coin;

    // Verknüpfung zum TextMeshPro-Zähler
    public TMP_Text CoinCounterText;

    void OnTriggerEnter2D(Collider2D other)
    {
        // Prüfen, ob das Objekt das Tag "Coin" hat
        if (other.tag == "Coin")
        {
            coin = coin + 1;

            // Abspielgeräusch
            AudioSource.PlayClipAtPoint(CoinSound, transform.position);

            // Text aktualisieren
            CoinCounterText.text = coin.ToString();

            // Münze aus Szene entfernen
            Destroy(other.gameObject);
        }
    }
}

Wähle die Rat in der Hierarchy. Im CoinController-Komponentenfeld ziehe das CoinCounterText-GameObject in das Feld Coin Counter Text.

Drücke nun Play – beim Einsammeln der Münzen wird die UI in Echtzeit aktualisiert.

TextMeshPro-UI-Element zeigt Münzzahl an
CoinCounterText mit TextMeshPro erstellt und mit dem Skript der Ratte verbunden.

Schritt 4. Eine Sackgasse erstellen und das Level neu starten

Lass uns eine kleine Herausforderung hinzufügen: ein Loch, in das der Spieler fallen kann.

Verschiebe eine der Plattformen, um eine Lücke im Boden zu schaffen – das wird zur Fallzone.

Klicke mit der rechten Maustaste in der Hierarchy und wähle: Create Empty. Benenne das neue Objekt in DeadEnd um.

Im Inspector, führe Folgendes aus:

Erstelle jetzt ein neues MonoBehaviour-Skript mit dem Namen DeadEndController. Füge folgenden Code ein:

using UnityEngine;
using UnityEngine.SceneManagement; // für Szenen-Neuladen

// Dieses Skript wird an ein "Dead End"-Objekt (z. B. Abgrund) gehängt
// Wenn der Spieler hinein fällt, wird die Szene neu geladen
public class DeadEndController : MonoBehaviour
{
    // Wird aufgerufen, wenn etwas den Trigger betritt
    void OnTriggerEnter2D(Collider2D other)
    {
        // Prüfen, ob das Objekt den Tag "Player" hat
        if (other.tag == "Player")
        {
            // Die aktuelle Szene neu laden
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }
}

Wähle das DeadEnd-Objekt und füge das DeadEndController-Skript hinzu. Erstelle dann ein Prefab, indem du DeadEnd aus der Hierarchy in den Assets-Ordner ziehst.

Wenn die Ratte in den Trigger-Bereich fällt, wird die Szene neu geladen – das ist eine einfache Möglichkeit, das Level ohne zusätzlichen Aufwand zurückzusetzen.

Szene mit DeadEnd-Trigger und zugehörigem Skript
DeadEnd-Trigger unter dem Loch platziert. Beim Betreten wird die Szene neu gestartet.

Schritt 5. Einen einfachen Gegner hinzufügen (der Pilz)

Zeit für ein bewegliches Hindernis: ein Pilz-Gegner, der hin und her läuft. Wenn die Ratte auf seinen Kopf springt – verschwindet er. Wenn sie ihn seitlich berührt – wird das Level zurückgesetzt.

Platziere ein Ground-Prefab und ein DeadEnd darunter. Ziehe dann den Pilz-Sprite aus den Assets in die Szene, auf die letzte Plattform. Benenne das neue Objekt in Enemy um.

Im Inspector für Enemy:

Erstelle nun ein neues Skript mit dem Namen MushroomController. Füge diesen Code ein:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class MushroomController : MonoBehaviour
{
    // Maximale Entfernung, die der Pilz von seiner Startposition entfernt laufen darf (in Unity-Einheiten)
    public float distanceToRun = 2f;

    // Bewegungsgeschwindigkeit
    public float speed = 2f;

    // Blickt der Pilz aktuell nach links?
    public bool isLookingLeft = true;

    // Startposition des Pilzes
    Vector3 startPos;

    // Referenz auf das Rigidbody2D-Komponente
    Rigidbody2D rb;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        startPos = transform.position;

        // Optimierung: Entfernung als Quadratwert speichern
        distanceToRun = distanceToRun * distanceToRun;
    }

    void FixedUpdate()
    {
        // Entfernung von der Startposition berechnen
        Vector2 dist = transform.position - startPos;

        if (isLookingLeft)
        {
            // Zu weit nach links gelaufen → umdrehen
            if (transform.position.x < startPos.x && dist.sqrMagnitude > distanceToRun)
            {
                TurnTheMushroom();
                rb.linearVelocity = new Vector2(speed, rb.linearVelocity.y);
            }
            else
            {
                rb.linearVelocity = new Vector2(-speed, rb.linearVelocity.y);
            }
        }
        else
        {
            // Zu weit nach rechts gelaufen → umdrehen
            if (transform.position.x > startPos.x && dist.sqrMagnitude > distanceToRun)
            {
                TurnTheMushroom();
                rb.linearVelocity = new Vector2(-speed, rb.linearVelocity.y);
            }
            else
            {
                rb.linearVelocity = new Vector2(speed, rb.linearVelocity.y);
            }
        }
    }

    // Pilz spiegeln (Richtung ändern + visuelle Drehung)
    void TurnTheMushroom()
    {
        isLookingLeft = !isLookingLeft;
        transform.localScale = new Vector3(
            transform.localScale.x * -1,
            transform.localScale.y,
            transform.localScale.z
        );
    }

    // Wenn der Spieler von der Seite kollidiert → Szene neu laden
    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.collider.gameObject.tag == "Player")
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    // Wenn der Spieler auf den Kopf springt (Trigger oben) → Pilz zerstören
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player")
        {
            Destroy(gameObject);
        }
    }
}

Füge das MushroomController-Skript dem Enemy-Objekt hinzu. Passe Speed und Distance To Run im Inspector an (z. B. beides auf 2).

Ziehe abschließend Enemy in den Assets-Ordner, um ein wiederverwendbares Prefab zu erstellen.

Pilz-Gegner mit Collidern, Skript und Prefab-Einstellungen
Gegner-Pilz mit zwei Collidern, Rigidbody2D und angehängtem Patrouillen-Skript.

Schritt 6. Eine bewegliche Plattform erstellen

Fügen wir eine vertikal bewegliche Plattform hinzu, auf der die Ratte fahren kann.

Ziehe das largeGround-Sprite in die Szene und benenne das neue Objekt in Platform um.

Im Inspector für Platform:

Jetzt geben wir der Plattform ein Skript, das sie zwischen zwei Punkten auf- und abbewegt.

Erstelle ein neues MonoBehaviour Skript mit dem Namen PlatformMoving und füge diesen Code ein:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlatformMoving : MonoBehaviour
{
    // Geschwindigkeit der Plattformbewegung
    public float speed;

    // Oberer Punkt, zu dem sich die Plattform bewegt
    public Transform endPoint;

    // Startpunkt (anfängliche Position)
    Vector3 startPoint;

    // Referenz zu Rigidbody2D
    Rigidbody2D rb;

    // Aktueller Geschwindigkeitswert
    float currentSpeed;

    void Start()
    {
        // Anfangsposition speichern
        startPoint = transform.position;

        // Referenz zu Rigidbody2D holen
        rb = GetComponent<Rigidbody2D>();

        // Anfangsrichtung setzen
        currentSpeed = speed;
    }

    void FixedUpdate()
    {
        // Wenn Plattform den Endpunkt erreicht hat, Richtung umkehren
        if (transform.position.y > endPoint.position.y)
            currentSpeed = -speed;

        // Wenn Plattform zum Start zurückkehrt, Richtung erneut umkehren
        if (transform.position.y < startPoint.y)
            currentSpeed = speed;

        // Geschwindigkeit auf Rigidbody anwenden
        rb.linearVelocity = new Vector3(0, currentSpeed, 0);
    }
}

Erstelle in der Hierarchy ein leeres GameObject und nenne es EndPoint. (Optional kannst du ein Icon zuweisen, um es sichtbar zu machen.) Platziere es über der Plattform mit dem Move-Tool.

Wähle erneut Platform aus. Füge das PlatformMoving-Skript hinzu. Setze Speed auf 1 und weise das Objekt EndPoint dem entsprechenden Feld zu.

Starte die Szene und beobachte, wie sich die Plattform vertikal zwischen zwei Positionen bewegt.

Füge rechts von der Plattform eine Wand hinzu und gib ihr einen Box Collider 2D. Platziere dann ein DeadEnd-Prefab unter der beweglichen Plattform und passe dessen Größe an.

Bewegliche Plattform mit Rigidbody, Endpunkt und Skript
Bewegliche Plattform mit Rigidbody2D, Box Collider und PlatformMoving-Skript konfiguriert.

Schritt 7. Eine physikalische Kiste hinzufügen

Fügen wir eine Kiste hinzu, die mit der Ratte und anderen Objekten durch echte Physik interagiert.

Ziehe das imageGround-Sprite in die Szene und benenne das neue Objekt in Box um.

Im Inspector für Box:

Du kannst die Kiste jetzt durch die Szene schieben — probiere aus, sie auf der beweglichen Plattform zu benutzen oder als Stufe zu verwenden!

Kiste aus imageGround mit Rigidbody und Collider
Eine einfache physikalische Kiste aus dem imageGround-Sprite, auf der Plattform platziert.

Schritt 8. Einen Ausgang erstellen

Fügen wir dem Level einen Ausgang hinzu. Er lädt noch keine neue Szene, aber er fungiert als Ziel-Trigger – wenn du ihn erreichst.

Füge zuerst ein weiteres Ground-Prefab an der Stelle hinzu, wo die bewegliche Plattform endet – also nahe dem oberen Ende ihres Pfades. Platziere dann am Ende des Levels eine Wand mit dem largeGround-Sprite und füge ihr einen Box Collider 2D hinzu.

Ziehe den Exit-Sprite aus dem Assets-Ordner in die Szene — er ist bereits im Projekt enthalten. Platziere ihn in der Nähe der oberen Wand, so hoch, dass die Ratte ihn nicht alleine erreichen kann. Um den Ausgang zu erreichen, braucht der Spieler eine Box als Hilfestufe.

Im Inspector für das Exit-Objekt:

Jetzt wird beim Berühren des Ausgangs durch die Ratte die Szene neu geladen – aber nur, wenn du es geschafft hast, hinaufzuklettern.

Exit-Objekt mit Collider und Controller-Skript
Der Ausgang knapp außerhalb der Reichweite platziert – du brauchst die Kiste, um dorthin zu gelangen.

Schritt 9 (Optional). Einen bewegten Hintergrund mit Parallax hinzufügen

Um ein Gefühl von Tiefe zu erzeugen, lassen wir den Hintergrund leicht mitbewegen, wenn sich der Spieler bewegt. Das nennt man Parallax-Effekt — er simuliert Tiefe, indem weiter entfernte Ebenen langsamer scrollen.

Du kannst das Hintergrundbild hier herunterladen: BackGround.png herunterladen

Importiere das Bild in dein Projekt und ziehe es in die Szene. Im Inspector:

Erstelle ein neues MonoBehaviour-Skript mit dem Namen Parallax. Füge diesen Code ein:


using UnityEngine;

public class Parallax : MonoBehaviour
{
    // Spieler, dem wir folgen möchten
    private GameObject player;

    // Position des Spielers im vorherigen Frame
    private Vector3 lastPosition;

    // Parallax-Geschwindigkeit (je kleiner, desto langsamer bewegt sich der Hintergrund)
    public float speed = 60f;

    void Start()
    {
        // Finde den Spieler über das Tag
        player = GameObject.FindWithTag("Player");

        // Startposition speichern
        if (player != null)
        {
            lastPosition = player.transform.position;
        }
    }

    void Update()
    {
        // Falls kein Spieler gefunden wurde, nichts tun
        if (player == null) return;

        // Berechne die Bewegung des Spielers seit dem letzten Frame
        Vector3 offset = player.transform.position - lastPosition;

        // Bewege den Hintergrund entsprechend, aber langsamer – für den Parallaxeffekt
        transform.Translate(offset * speed * Time.deltaTime);

        // Speichere die aktuelle Spielerposition für den nächsten Frame
        lastPosition = player.transform.position;
    }
}

Hänge das Skript an das Hintergrundobjekt. Setze den Speed-Wert — 60 ist ein guter Startpunkt, aber du kannst gern experimentieren.

Hintergrundobjekt mit Parallax-Skript und Setup
Ein Parallax-Hintergrund bewegt sich sanft mit der Bewegung des Spielers und erzeugt ein Gefühl von Tiefe.

Schritt 10. Die Wolke, die folgt (Der wichtigste Schritt)

Das ist der Schritt, auf den alles leise hingeführt hat. Nicht die Münzen, nicht der Pilz, nicht einmal der Ausgang. Das hier — ist der Grund.

In den Assets gibt es eine lächelnde Wolke. Sie greift nicht an, bringt keine Punkte. Und doch — ist sie das Einzige, das bei dir bleibt. Immer.

Ziehe das Wolken-Sprite in die Szene und benenne es Cloud. Setze seine Z-Position auf 0 und Order in Layer auf -50, damit es hinter der Ratte bleibt.

Platziere sie irgendwo über und hinter der Ratte — z. B. bei (x - 2, y + 3). Präzision ist nicht nötig. Nur Präsenz.

Erstelle ein neues MonoBehaviour-Skript mit dem Namen CloudFollower und hänge es an die Wolke. Verwende diesen Code:


using UnityEngine;

public class CloudFollower : MonoBehaviour
{
    // Versatz der Wolke relativ zum Spieler (nach links und oben)
    public Vector3 offset = new Vector3(-2f, 3f, 0f);

    // Geschwindigkeit, mit der die Wolke dem Spieler folgt
    public float followSpeed = 1.5f;

    // Referenz auf das Ziel (den Spieler)
    private Transform target;

    void Start()
    {
        // Suche das Objekt mit dem Tag "Player"
        GameObject playerObj = GameObject.FindWithTag("Player");
        if (playerObj != null)
        {
            target = playerObj.transform;
        }
    }

    void Update()
    {
        // Wenn kein Ziel gefunden — nichts tun
        if (target == null) return;

        // Zielposition: Spielerposition + Versatz
        Vector3 desiredPos = target.position + offset;

        // Bewege die Wolke sanft zur Zielposition
        transform.position = Vector3.Lerp(
            transform.position,           // aktuelle Position
            desiredPos,                   // Zielposition
            followSpeed * Time.deltaTime  // Interpolation über die Zeit
        );
    }
}

Die Wolke folgt der Ratte jetzt — nicht perfekt, nicht exakt, sondern mit sanfter Verzögerung. Sie hilft nicht. Sie spricht nicht. Sie bleibt einfach.

Wenn du langsamer wirst oder fällst — sie wartet. Wenn du neu startest — sie ist wieder da. Du bist in diesem Level nie allein. Nicht wirklich.

Wolke schwebt hinter und über der Ratte
Die Wolke. Die Begleiterin. Der Grund.

Schritt 11. Münzen, Pilze und alles, was danach kommt

Jetzt kannst du Münzen und Pilze hinzufügen. Eine Kiste unter die Plattform fallen lassen. Und — vielleicht — ein wenig länger in diesem Level bleiben, als geplant.

Alles wirkt einfach. Und genau das ist das Schöne daran. Versuch nicht sofort, das beste Spiel der Welt zu bauen. Versteh zuerst die Grundlagen: Bewegung, Kollisionen, Interaktionen.

Danach wirst du dein eigenes Spiel machen. Eines, das sich wirklich nach dir anfühlt.