Startseite

Plattformer-Tutorial — Teil 2: Ein kleines Spiel über Sprünge, Kisten und Wolken

Dies ist der zweite Teil unseres Unity-Plattformer-Tutorials. Im ersten Teil hast du gelernt, dich zu bewegen. In diesem hier baust du eine Welt, in der es sich zu bewegen lohnt.

Wir fügen keine Gegner mit Verhaltensbäumen hinzu. Wir bauen keine Menüs oder Übergänge. Was wir tun: Wir gestalten einen Raum mit Münzen, Wänden, Abgründen, einem leicht mürrischen Pilz… und etwas, das dich still begleitet – bis ganz zum Schluss.

Du wirst Dinge platzieren. Eine Wand reparieren, an der Ratten kleben bleiben. Auf einer Plattform fahren. Und wenn du schließlich den Ausgang erreichst – wirst du wissen, dass das nicht der wahre Grund war, warum dieses Level entstanden ist.

Also öffne Unity. Atme durch. Und beginne – nicht, weil du musst, sondern weil **hier etwas still darauf wartet**, platziert zu werden.

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.

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.

Tipp: Da wir PlayClipAtPoint verwenden, wird der Sound im Welt-Raum abgespielt. Wenn er leise klingt, liegt das daran, dass der Audio Listener auf der Kamera ist – das beheben wir später.

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:

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 CoinCounterText und nimm folgende Änderungen vor:

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 C#-Skript mit dem Namen DeadEndController. Füge folgenden Code ein:

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

public class DeadEndController : MonoBehaviour {
    void OnTriggerEnter2D(Collider2D other) {
        if (other.tag == "Player") {
            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.

Tipp: 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
{
    // Wie weit sich der Pilz von seinem Startpunkt entfernt (in Einheiten)
    public float distanceToRun = 2f;

    // Bewegungsgeschwindigkeit
    public float speed = 2f;

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

    // Startposition
    Vector3 startPos;

    // Referenz zu Rigidbody2D
    Rigidbody2D rb;

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

        // Distanzprüfung optimieren durch quadrierte Werte
        distanceToRun = distanceToRun * distanceToRun;
    }

    void FixedUpdate()
    {
        // Distanz vom Startpunkt berechnen
        Vector2 dist = transform.position - startPos;

        if (isLookingLeft)
        {
            // Wenn 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
        {
            // Wenn 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);
            }
        }
    }

    // Dreht die Blickrichtung des Pilzes (visuell und logisch)
    void TurnTheMushroom()
    {
        isLookingLeft = !isLookingLeft;
        transform.localScale = new Vector3(
            transform.localScale.x * -1,
            transform.localScale.y,
            transform.localScale.z
        );
    }

    // Wenn die Ratte mit dem Pilz kollidiert (nicht von oben)
    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.collider.gameObject.tag == "Player")
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    // Wenn die Ratte den Trigger oben berührt – 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 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 wall-Sprite und füge ihr einen Box Collider 2D hinzu.

Importiere das Exit-Sprite (oder verwende das rote Schild aus dem vorhandenen Asset-Sheet) und ziehe es in die Szene nahe der oberen Wand. Es sollte so hoch platziert sein, dass die Ratte es nicht einfach durch Springen erreichen kann – du wirst die Box brauchen.

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 C#-Skript mit dem Namen Parallax. Füge diesen Code ein:


using UnityEngine;

public class Parallax : MonoBehaviour
{
    // Referenz zum Spieler
    private GameObject player;

    // Position aus dem vorherigen Frame
    private Vector3 lastPosition;

    // Parallax-Scrollgeschwindigkeit
    public float speed = 60f;

    void Start()
    {
        // Spieler über Tag finden
        player = GameObject.FindWithTag("Player");
        if (player != null)
        {
            lastPosition = player.transform.position;
        }
    }

    void Update()
    {
        if (player == null) return;

        // Versatz berechnen und anwenden
        Vector3 offset = player.transform.position - lastPosition;
        transform.Translate(offset * speed * Time.deltaTime);

        // Aktuelle Position für nächsten Frame speichern
        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, bewegt sich nicht einmal von selbst. 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 C#-Skript mit dem Namen CloudFollower und hänge es an die Wolke. Verwende diesen Code:


using UnityEngine;

public class CloudFollower : MonoBehaviour
{
    public Vector3 offset = new Vector3(-2f, 3f, 0f);
    public float followSpeed = 1.5f;
    private Transform target;

    void Start()
    {
        // Spieler per Tag finden
        GameObject playerObj = GameObject.FindWithTag("Player");
        if (playerObj != null)
        {
            target = playerObj.transform;
        }
    }

    void Update()
    {
        if (target == null) return;

        // Sanft dem Spieler mit Offset folgen
        Vector3 desiredPos = target.position + offset;
        transform.position = Vector3.Lerp(transform.position, desiredPos, followSpeed * Time.deltaTime);
    }
}

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.