Mein Start mit Unity & C# – Ein Ludo-ähnliches Brettspiel von null auf eins

Ich habe mein erstes Unity-Projekt in C# gestartet: ein Ludo-ähnliches Brettspiel mit KI-Gegnern. Vom Set-up über Prefabs, Pfaddefinition und Würfel-/Zuglogik bis zu einer einfachen KI – inklusive Bugs und Fixes. Es war anstrengend, aber lehrreich, und ich bin motiviert für das nächste Projekt.

Motivation

Ich wollte endlich mit der Game-Entwicklung starten – hands-on statt Tutorials zu bringen. Ein kleines, aber vollständiges Brettspiel mit grundlegender KI. Fokus auf sauberen Code, nachvollziehbare Architektur und das Lösen echter Probleme.

Tech-Stack

  • Engine: Unity
  • Sprache: C#
  • IDE: Jetbrains Rider (persönliche Präferenz gegenüber Visual Studio)
  • 3D-Modellierung: Blender

Erste Schritte: C#-Basics und Projekt-Setup

Ich bin mit den Grundlagen gestartet: Variablen, String, int & Co. Danach: Unity installiert, Rider angebunden und das Projekt sauber strukturiert (Scenes, Scripts, Materials, Models).

Spielfeld & Assets

  • In Unity eine Plane angelegt und ein Referenzbild als temporäres Board-Layout genutzt
  • In Blender eine einfache Spielfigur modelliert und exportiert
  • In Unity vier Prefabs (Farben) angelegt und Spawnpunkte im Code definiert

Beispiel: Spawn-Position pro Farbe

using UnityEngine;

public class Spawns : MonoBehaviour
{
    public Vector3[] startPositionsGreen = new Vector3[4];
    public Vector3[] startPositionsRed   = new Vector3[4];
    public Vector3[] startPositionsBlue  = new Vector3[4];
    public Vector3[] startPositionsYellow= new Vector3[4];
}

Pfaddefinition: FieldPath.cs

Für die Spiellogik habe ich den Laufpath als festes Array modelliert. Einmal viel Arbeit, danach wiederverwendbar.

public class FieldPath : MonoBehaviour
{
    // 40 Felder als Beispiel – an Boardlayout anpassen
    public Vector3[] path = new Vector3[40];
}

Würfel & Zuglogik

Dice (Würfel)

Ein einfacher Würfel, der Werte 1-6 liefert und Events triggert.

using UnityEngine;
using System;

public class Dice : MonoBehaviour
{
    public event Action<int> OnRolled;

    public int Roll()
    {
        int value = UnityEngine.Random.Range(1, 7);
        OnRolled?.Invoke(value);
        return value;
    }
}

Turn-/Move-Flow (vereinfacht)

  • Spieler würfelt
  • Bei 6: Prüfen, ob eine eigene Figur im Haus ist und das Startfeld frei ist -> dann Figur aufs Brett setzen. Vor anderen Züge prüfen, ob im Home-Bereich platzt geschaffen werden muss.
  • Normale Züge: Figur entlang FieldPath bewegen
  • Begegnungen: Landet eine Figur auf ein Feld mit fremder Figure -> diese zurück ins Haus
  • Endbedingung: Sind alle 4 eigenen Figuren im Haus (Zielbereich), ist das Spiel für diesen Spieler beendet.

KI: Anspruchsvoll, aber machbar

Die KI war am schwierigsten. Probleme u.a. bei Spielerzuordnung, Zugreihenfolge und Zugberechtigung. Mehrfaches Recatoring bis es „stabil genug“ lief. Geplat ist, die Heuristiken zu verbessern (z.B. Risiko-/Nutzen-Abwägung, Priorisierung von Schlägen, Einzug ins Haus).

Beispiel: sehr einfache KI-Heuristik

public class SimpleAi : MonoBehaviour
{
    public MoveGenerator moveGenerator; // liefert mögliche Moves

    public Move ChooseMove(BoardState state, int roll)
    {
        var moves = moveGenerator.GetLegalMoves(state, roll);
        if (moves.Count == 0) return Move.None;

        // 1) Kann ich jemanden schlagen? – höchste Priorität
        var hit = moves.Find(m => m.WillCapture);
        if (hit != null) return hit;

        // 2) Kann ich ins Haus einziehen?
        var home = moves.Find(m => m.WillEnterHome);
        if (home != null) return home;

        // 3) Sonst: längster Fortschritt
        moves.Sort((a,b) => b.Advance.CompareTo(a.Advance));
        return moves[0];
    }
}

Regeln & Sonderfälle (implementiert/geplant)

  • 6 gewürfelt: nächste Figur darf herausgesetzt werden, sofern Startfeld frei und im Home-Bereich Platz ist
  • Rauswerfen: Auf besetztes Feld ziehen -> gegnerische Figur zurück ins Haus
  • Haus/Ende: Spieler & KI können das Haus betreten; sind alle 4 Figuren drin -> Spiel für diesen Spieler beendet, sonst KI weiterspielen.

Hürden & Bugs (und wie ich sie angegangen bin)

  1. Bewegung ungenau
    • Fix: Alle Koordinaten einzeln überprüft und angepasst
  2. KI würfelt vorzeitig (startet, sobald der Spieler eine 6 würfelt; Rot wird herausgesetzt)
    • Fix: Update/Turn-Manager so angepasst, dass der Spieler erst nach bis zu drei Würfeln an die KI übergibt; Würfellogik neu aufgesetzt
  3. Falsche Wurfanzahl (zu oft / nur 2x statt 3x)
    • Fix: Zähler und Zustandsautomat (State Machine) eingeführt
  4. Einzug ins Haus blockiert
    • Status: Ursache noch offen; wird priorisiert untersucht

Architektur-Notizen

  • State Machine für Phasen: Idle -> Rolling -> Choosing -> Moving -> Resolving -> NextTurn
  • Datenstrukturen: BoardState, PieceState, PlayerState zum klaren Trennung von Anzeigen & Logik
  • Events (C# event/action) für lose Kopplung zwischen UI, Würfel, Turn-Manager und KI

Eigene Assets & Urheberrecht

Das Board-Design wird auf eigene Grafiken umgestellt, um rechtlich sauber zu bleiben. Platzhalter wurden nur als Referenz verwendet.

Was ich gelernt habe

  • Debuggings zuerst strukturieren: kleine Repro-Szene, Logos, Giszmos, Breakpoints
  • Klare Zustände verhindern Logik-Chaos (insb. Mehrfachwürfe & Zugübergabe)
  • KI iterativ entwickeln: von deterministisch zu heuristisch
  • Einmalige Daten (Pfad) lohnen den upfront-Aufwand

Einstieg & Einrichtung

1) Einstieg in C# – die Basis, die alles trägt

Bevor ich Unity geöffnet habe, habe ich mir ein solides Fundament in C# erarbeitet. Ich habe mit Variablen, Datentypen (int, float, bool, string), Operatoren, if/else (for/while), Arrays/Listen und Methoden begonnen. Danach kamen Klassen, Objekte und Vererbung. Besonders wichtig für Unity: Verstehen, wie Referenz- vs. Werttype funktionieren (z.B. Vector3 ist ein struct -> Werttyp) und wie Ereignisse/Delegates für Architektur entkoppeln können.

Unity-spezifisch lernte ich die Lebenszyklen von MonoBehaviour (u.a. Awake, Start, Update, OnEnable / OnDisable) sowie Couroutines (StartCoroutine) für zeitbasierte Abläufe. Das half später enorm bei Würfel-Animationen und Zugsequenzen.

2) Unity einrichten & Rider als IDE

Ich nutze Jetbrains Rider, weil ich mich damit am produktivsten fühle. Ich habe von Anfang an Struktur geschaffen: Ordner für Scenes, Scripts, Prefabs, Materials, Models, Art, ScriptableObjects. Zusätzlich eine .gitignore und Versionskontrolle eingerichtet – so lassen sich Experimente rückgängig machen.

Tipp: Assembly Definitions für größere Projekte nutzen; hier genügte einen Haupt-Assembly. Außerdem habe ich die Play Mode Options auf „Enter Play Mode ohne Domains/Scene Reload“ geprüft (für schnellere Iterationen), aber nur, wenn der Code darauf ausgelegt ist.


Entdecke mehr von DaonWare

Melde dich für ein Abonnement an, um die neuesten Beiträge per E-Mail zu erhalten.

Kommentar verfassen

Nach oben scrollen