
Einige wichtige Hinweise zum Ablauf dieses Kurses.
Legen wir zunächst über das Unity Hub ein neues Projekt mit dem Template "2D" an.
Hier kannst Du Begleitmaterial zum Kurs herunterladen.
In diesem Abschnitt legen wir die Projektstruktur an, erzeugen Objekte, um Karten überhaupt darzustellen und fügen ein einfaches Script hinzu, so dass der Spieler eine verdeckte Karte per Klick umdrehen kann.
Wir legen separate Projekt-Ordner an, um eigene und fremde Inhalt zu trennen.
Da wir zunächst ausschließlich mit 2D-Elementen arbeiten, fügen wir ein erstes Bild in Form eines UI-Image-Objekts hinzu. In diesem Zusammenhang werden die Komponenten des UI-Systems sowie das Grundprinzip des Layoutmechanismus besprochen.
Wir legen eine Karte auf den Tisch und konfigurieren das UI-System so, dass sie unabhängig von der Bildschirmauflösung immer sichtbar bleibt.
Wir schreiben ein einfaches Script, das zunächst nur eine Meldung ausgibt und verbinden dieses mit einer Schaltflächenkomponente. Anhand dieses Beispiels lernst Du den Ablauf kennen, um eigene Programmlogik aufzurufen, wenn der Spieler auf eine Karte klickt.
Der Code wird nun so verändert, dass durch austauschen des Kartenbilds beim Klicken ein simples Umdrehen realisiert wird.
Schöner sieht es aus, wenn sich die Karte mit einer sichtbaren Animation umdreht. Dazu kommt eine Zeitleiste zum Einsatz, auf der sich Eigenschaften wie die Skalierung der Karte animieren lassen.
Damit der Kartenwert zum richtigen Zeitpunkt der Animation sichtbar wird, muss das Script aufgeteilt und an ein Zeitleistenereignis gebunden werden.
Eine Herausforderung des Programmierens liegt darin, mögliche Problemsituationen vorab zu erkennen und im Code zu berücksichtigen. In dieser Lektion sehen wir uns an, wie wir Probleme identifizieren und lösen. Unser Script darf nur im PlayMode und nur nach dem ersten Klick ausgeführt werden.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt bauen wir das System aus, so dass eine beliebige Anzahl von Karten unterstützt wird.
Wir konvertieren unseren Spielkartenprototyp in ein wiederverwendbares Bibliotheksobjekt, ein sogenanntes Prefab, und sehen uns die allgemeine Funktionsweise dieses Mechanismus an. Zudem führen wir eine Datenklasse ein, die die grafische Darstellung von den inhaltlichen Kartendaten trennt und erzeugen einen Kartenstapel als Liste dieser Daten. Wir bauen das Ziehen einer Karte vom Stapel ein und erweitern dies um eine Zufallskomponente, so dass wir einen gemischten Kartenstapel bekommen. Schließlich verbinden wir den Datenstapel wieder mit der grafischen Darstellung und erzeugen Spielkarten per Script auf dem Spieltisch. Dieser Abschnitt bespricht außerdem Ursache und Behebung der typischen Fehler Index out of Range und Null Reference Exception.
Unitys Prefab-Mechanismus ermöglicht es, den Grundaufbau der Spielkarte zu speichern und später einfach zu vervielfältigen. Dieses Video erklärt zudem die Grundlagen der Prefabs.
Um verschiedene Karten definieren zu können, fügen wir der Szene ein Kartenstapel-Objekt hinzu und verbinden es mit dem Klick-Ereignis.
Durch Erweiterung des Programmcodes realisieren wir das Ziehen einer Karte aus dem Kartenstapel.
Der Fehler Index out of Range tritt immer dann auf, wenn versucht wird auf ein Element außerhalb der verfügbaren Elemente einer Liste zuzugreifen.
Während sich die erste Position über einen festen Index ansprechen lässt, müssen wir beim Ziehen vom Ende des Stapels dessen dynamische Länge berücksichtigen.
Um eine zufällige Karte aus dem Stapel zu ziehen, setzen wir den Zufallsgenerator Random ein und sehen uns dessen Eigenschaften an.
Durch Verbindung des Scripts mit der Bildkomponente des bestehenden Prototyp-Objekts in der Szene, wird die gezogene Karte nun für den Spieler sichtbar. Ein typischer Leichtsinnsfehler führt hier oft zu Null-Reference-Fehlern. Ist der Stapel leer, blenden wir ihn zudem im Spiel aus.
Unsere vorherige Arbeit bewirkt, dass man auf die Karte klicken und sie so umdrehen kann. Außerdem ist das Kartenobjekt von Anfang an zu sehen, wir möchten aber, dass sie erst beim Ziehen sichtbar ist. Diese beiden Probleme beheben wir mit der Aktivierungs-Eigenschaft von Objekten und Komponenten.
Die bisherige Visualisierung der gezogenen Karte kann immer nur eine Karte zeigen. Da wir für die meisten Spielprinzipien aber mehrere Karten legen müssen, verbinden wir nun das Prefab mit dem Stapel um beliebige Karten auf der Spielfläche zu zeigen.
Mit Hilfe einer Layout-Gruppe ordnen wir die vom Stapel gezogenen Karten nebeneinander auf dem Spielbrett an.
Als Gedächtsnisstütze wiederholt dieses Video die bisher kennengelernten Elemente und zeigt, wie das Umdrehen der Karte bei dynamischer Instantiierung des Prefabs deaktiviert wird.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt setzen wir eine einfache Tarot-Legung um. Der Spieler zieht hierbei 4 Karten und dreht sie per Klick um.
Hierfür erweitern wir unser Projekt um eine zusätzliche Szene und Teilen den Code in gemeinsame und spielspezifische Elemente auf. Wir implementieren die Beschränkung der Züge und erweitern das Spielbrett um Hilfetexte. Schließlich programmieren wir einen alternativen Layoutmechanismus, der es ermöglicht, die Karten in einer bestimmten Formation abzulegen, wie es bei der Kartendeutung des Tarot oft erwünscht ist. Wichtige Teile dieses Abschnitts beschäftigen sich mit dem Aufräumen des Codes, der Zentralisierung von gemeinsam genutzten Teilen und dem erstellen von einzelnen Modulen für unterschiedliche Spielregeln.
Für unser Tarot-Spiel legen wir eine zweite Szene an und definieren einen neuen Kartenstapel mit 22 Tarot-Motiven.
Ein typisches Merkmal der Tarot-Legung ist, dass die Anzahl der zu ziehenden Karten vorgegeben wird. In diesem Video realisieren wir eine entsprechende Einschränkung im Code.
Da wir die Debug-Ausgaben nur im Editor sehen, fügen wir nun eine Textkomponente hinzu, die dem Spieler die verbleibenden Spielzüge zeigt.
Aufgrund der Entwicklung unseres Projekts bis hier, werden zwei Zeiger auf das Kartenbild vorgehalten. Außerdem greift der Kartenstapel auf interne Elemente des Kartendarstellers zu, was durch Kapselung der Render-Vorgänge verbessert werden kann.
Der Parameter kannAngeklicktWerden beim Zuweisen der Kartendaten funktioniert noch nicht ganz korrekt. Wir ergänzen den Code, so dass die Karte auch tatsächlich umdrehbar wird, wenn der Parameter false ist.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Um eine übersichtlichere Code-Struktur zu erreichen und Gemeinsamkeiten wie die Kartendarstellung zwischen verschiedenen Spielprinzipien zu teilen, trennen wir allgemeinen und spielspezifischen Code voneinander.
Einige Elemente, wie das Ziehen einer zufälligen Karte, befindet sich derzeit noch mehrfach im Spielprinzip. Diese immer gleichen Abläufe zentralisieren wir nun im Kartenstapelscript, so dass identischer Code nur einmal vorkommt und Stapelaktivitäten auch tatsächlich vom Stapel durchgeführt werden.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Die Formation "Kleines Kreuz" ist ein beispielhaftes Legebild des Tarot bei dem die Lage der Karte auf dem Spielbrett die Interpretation der Karte beeinflusst. Daher erweitern wir unser Tarot-Spielprinzip um die Verwendung von Platzhaltern zur präzisen Ablage auf dem Spielbrett.
Die Einführung des Platzhalter-Stapels hat zu einer doppelten Datenhaltung des Zugzählers geführt, die wir in dieser Lektion auflösen. Um den bereits geschriebenen Code bei dieser Änderung möglichst wenig zu beeinflussen, konvertieren wir die bisherige Variable in ein Getter-Property.
In diesem Abschnitt realisieren wir ein Spielmenü, das sich per Schalter ein- und ausblenden lässt. Wir fügen ein Script für die Menüpunkte hinzu, so dass diese zwischen den Szenen, also den unterschiedlichen Spielbrettern wechseln. Da das Menü in allen Szenen vorkommen soll, zentralisieren wir es in einem gemeinsam genutzten Prefab. Für nicht alle Teile müssen wir eigenen Code schreiben, wie wir am Beispiel der Schalter zum Ein- und Ausblenden des Menüs sehen werden.
Zunächst legen wir eine Verdunklungsfläche mit Schaltern für die Menüpunkte an und verwenden dann den SceneManager, um zwischen den Szenen zu wechseln. Dafür müssen die Szenenassets außerdem dem Build hinzugefügt werden.
Menüschalter werden nun hinzugefügt, um das Menü-Overlay ein- und auszublenden. Dabei sehen wir uns an, wie sich manche Eigenschaften auch ohne Script direkt mit dem Schaltenflächenereignis verknüpfen lassen.
Um das selbe Menü in allen Szenen zu verwenden, erzeugen wir ein Prefab und instantiieren dies entsprechend in den Szenen.
Hier findest du Übungsmaterial zur eigenständigen Bearbeitung.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt setzen wir das Spielprinzip 'Paare finden' um. Darin wird jede Karte zweimal verdeckt auf dem Spieltisch ausgelegt. Der Spieler dreht per Klick zwei Karten um. Haben beide den selben Wert, verschwinden sie vom Tisch. Andernfalls verbleiben sie wieder verdeckt im Spiel. Das Spiel ist gewonnen, wenn alle Paare gefunden wurden.
Das neue Spielbrett sowie die Grundlogik des Aufdeckens der Karten leiten wir von den vorherigen Projektressourcen ab, erweitern sie aber um das automatische Verdoppeln des Kartendecks. Dabei besprechen wir die Möglichkeiten des Veränderns einer Liste während des Durchlaufens und die dabei entstehenden Risiken wie den Out-of-Memory-Fehler. Über einen Callback-Mechanismus legen wir die Animationsereignisse der Karte für andere Programmteile offen, so dass unterschiedliche Spielprinzipien auf gemeinsam definierte Ereignisse reagieren können. Für die leichtere Fehlersuche überschreiben wir die Konvertierung von Objekten zu Zeichenketten. Schließlich ermöglichen wir, dass eine zuvor aufgedeckte Karte wieder verdeckt werden kann und bauen Unterbrechungen der Spielrunden mit Dialogen ein.
Durch Duplizieren und Anpassen der Basis-Szene richten wir die Bühne für das Spielprinzip "Paare finden" ein. Wir erfassen die Szene im Build, verlinken sie im Menü und passen das UI-Layout geringfügig an.
Das Basis-Script für das neue Spielprinzip "Paare" lässt sich zunächst aus einer Neuanordnung bisher schon verwendeter Code-Teile konstruieren.
Um die Karten zu verdoppeln, durchlaufen wir den Stapel und duplizieren die Elemente. Die Probleme, die dabei auftauchen sowie deren Lösungen zeigt Dir dieses Video.
Da wir die Logik von Kartendarstellung, Kartenstapel und Spielprinzip möglichst unabhängig halten wollen, müssen die Komponenten über ein Benachrichtigungssystem erweitert werden. Nach dem Einbau eines Delegaten kann die Spiellogik fortan auf das vollständige Umdrehen der Karte reagieren.
Für die Prüfung und Fehlersuche ist es hilfreich, einen leicht verständlichen Namen für die Kartenobjekte in der Konsole anzuzeigen. Da der Standardname ledlich eine allgemeine Klasseninformation liefert, überschreiben wir die Method ToString() mit einer eigenen Version.
In der konkreten Implementierung der Benachrichtigungsfunktion vergleichen wir, ob zwei nacheinander angeklickte Karten den selben Wert aufweisen und entfernen sie im positiven Fall vom Spielbrett.
Wenn die zwei aufgedeckten Karten nicht den gleichen Wert zeigen, sollen sie wieder verdeckt werden. Dazu erweitern wir die Kartenlogik um die Fähigkeit des Zurückdrehens einer zuvor aufgedeckten Karte.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Beim sofortigen Umdrehen der Karten hat der Spieler kaum Gelegenheit sich die gesehenen Karten zu merken. Wir können dies lösen, in dem wir einen Dialog-Schritt einbauen, der erst nach einer Bestätigung durch den Spieler zum nächsten Zug übergeht.
Nach dem zuvor gezeigten Prinzip ist es nun sehr einfach möglich, das Spielende zu erkennen, anzuzeigen und den Start eines neuen Spiels anzubieten.
Eine Variante könnte darin bestehen, den Dialog nach Ablauf eines Zeitfensters automatisch zu schließen. Dieses Beispiel zeigt den Einsatz einer Coroutine zu diesem Zweck.
Da es dem Spieler möglich ist, durch schnelles Klicken mehrere Karten umzudrehen, wodurch Fehler entstehen, bauen wir nun einen Klick-Blocker mit Hilfe einer statischen Variable ein.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Hier findest du Übungsmaterial zur eigenständigen Bearbeitung.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt setzen wir das Spielprinzip 'Patience' oder 'Solitair' um. Hier zieht der Spieler eine Karte und legt sie auf einen von mehreren möglichen Ablagestapeln. Die Karte kann nur abgelegt werden, wenn die Farbe nicht der bereits liegenden Karte entspricht. Auf eine rote Karte kann also nur eine schwarze gelegt werden und umgekehrt. Außerdem muss der Wert der neuen Karte um eins niedriger sein als der Wert der liegenden Karte. Auf eine rote 10 kann also nur eine schwarze 9 gelegt werden. Auf die schwarze 9 nur eine rote 8 und so weiter.
Technisch kommt in diesem Abschnitt neu hinzu, dass wir mehrere Ablageziele anbieten, die außerdem jeweils nicht nur eine, sondern eine Folge von Karten enthalten. Deren überlappende Anordnung wiederum geschieht durch einen von uns implementierten Layout-Vorgang. Die Karten müssen um Farbe und Wert erweitert werden, so dass sie untereinander vergleichbar werden. Der Kartenstapel mit den verfügbaren Karten, der sogenannte Stock oder Talon, erhält jetzt die Möglichkeit eine Karte vor der Ablage anzuzeigen und diese Karte auch wieder zurück zu legen. Wann welche Karte wohin abgelegt werden darf, ermittelt unsere Spiellogik mit einer einfachen Rechnung. Die zugrunde liegende Ideen und den mathematischen Ansatz dazu sehen wir uns in diesem Abschnitt im Detail an.
Durch Duplizieren und Anpassen der Basis-Szene richten wir die Bühne für das Spielprinzip "Patience" ein. Wir erfassen die Szene im Build, verlinken sie im Menü, passen das UI-Layout an und ergänzen das Script für das neue Spielprinzip.
Ein Unterschied zu den anderen Spielprinzipien besteht darin, dass die Karten in mehreren Spalten auf dem Tisch liegen. Hierfür erzeugen wir ein Stapelcontainer-Script und verbinden die UI-Komponenten mit Button-Ereignissen.
Die zuvor angelegte Infrastruktur wird nun mit Anweisungen aufgefüllt, die das Erscheinen der Karte im Stapelcontainer der Spielszene bewirken.
Im Spielprinzip Patience kann eine Karte nicht zu jedem Zeitpunkt abgelegt werden, weshalb sie der Spieler zuerst ansehen können soll. Dazu erweitern wir die Szene um eine Vorschaukarte, die die oberste Karte des Stapels (Talon) darstellt.
Entscheidet sich der Spieler die oberste Karte des Stapels nicht zu legen, kann er die nächste Karte vom Stapel ziehen. Dabei muss jedoch die zuvor gezogene Karte wieder in den Stapel zurück gelegt werden.
Bei Patience soll keine zufällige Karte gezogen, sondern der Stapel der Reihe nach durchlaufen werden. Dazu erweitern wir den Kartenstapel um eine Funktion zum Abheben der obersten Karte.
Vorschau, Ablegen und Zurücklegen müssen den Sonderfall berücksichtigen, dass die letzte Karte ausliegt und der Stapel leer ist.
Da wir im Spielprinzip Patience sequenziell abheben, muss der Stapel zu Beginn einmal durchgemischt werden.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Die Regeln der Patience sehen das Ablegen mehrerer Karten aufeinander vor, wobei die Reihenfolge ein Rolle spielt, aber nur die oberste Karte für die Interaktion relevant ist. Zur effizienten Ausnutzung des Spielbretts in diesem Spiel programmieren wir nun ein eigenes Layout, das die Karten jeder Ablagespalte leicht versetzt übereinander zeichnet.
Jede Karte wird nun um ein Wert-Feld erweitert, dass die "Zahl" der Karte speichert. Vor der Ablage ergänzen wir einen Werte-Vergleich, der ermittelt, ob eine Karte gemäß den Regeln der Patience auf eine andere Karte gelegt werden darf.
Zur Erweiterung der Logik um Farbregeln interessiert uns der Abstand zweier Werte, unabhängig von der Reihenfolge/Richtung der Karten. Zu derartigen Zwecken kommt häufig das mathematische Absolut (Betragsfunktion) zum Einsatz, wie in diesem Video besprochen.
Die Ablage-Regeln für Kartenfarben sind komplizierter als die Wertregel der Patience. Dieses Video erklärt den mathematischen Hintergrund und einfache Rechenwege für 4 Ablageregeln mit Farbe bzw. Farbgruppen als Bewertungskriterium.
Durch Einbau einer weiteren Spielregel sorgen wir dafür, dass die Farbgruppe der Spielkarte nicht mit der Farbgruppe der aktuellen Karte übereinstimmen darf. Auf eine rote Karte darf nur eine schwarze gelegt werden und umgekehrt.
Durch unseren modularen Aufbau können wir die Anzahl der Ablagestapel durch einfaches Duplizieren schnell erhöhen.
Ähnlich der vorhergehenden Lektionen ergänzen wir eine grafische Gewinn- und Fehlermeldung.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt programmieren wir eine Erweiterung für den Unity-Editor mit der es möglich ist, den Kartenstapel mit wenigen Klicks mit Bilddateien zu befüllen. Da wir Wert und Farbe automatisch ermitteln, führt dieses Tool zu einer erheblichen Zeitersparnis beim Anlegen von umfangreichen Kartensets.
Da Editor-Erweiterungen im fertigen Spiel nicht verfügbar sind, müssen sie durch Platzierung im Editor-Ordner gekennzeichnet werden. Außerdem leitet sich ein Editor nicht von MonoBehaviour ab und erfordert die Verwendung spezieller Befehle und Funktionen, um dem Unity-Editor grafische Elemente hinzuzufügen. Wir sehen uns UnityEditor, den Editor, OnInspectorGUI und das Zeichnen eines GUILayout-Buttons an.
Über das Selection-Objekt lässt sich die momentane Auswahl im Editor durchlaufen. Der Inspector verfügt über eine Sperrfunktion, die wir brauchen, um gleichzeitig Assets auswählen und unseren Schalter drücken zu können.
Da wir nur Sprites suchen, prüfen wir jedes Objekt auf seinen Typ und bilden es bei entsprechender Eignung mit einem Type-Cast auf die Klasse ab. Damit lassen sich alle markierten Sprites in Karten des Stapels überführen.
Anhand des Dateinamens eines Sprites lässt sich der Wert der Karte ableiten (vorausgesetzt es wird ein Namensschema eingehalten). Dazu prüfen wir, ob Teile des Namens mit einem bestimmten Begriff übereinstimmen oder ob der Name mit einer Zahl beginnt.
Da der Farbcode Varianten unterliegt, untersuchen wir diesen mit einer Teilzeichenkettensuche. Der weitere Verlauf ähnelt dann wieder dem Ableiten des Namens.
Wir benötigen Sprites für unsere Kartenbeschreibung, doch diese sind in den Assets den Dateinamen untergeordnet. Um mühsames Suchen oder Aufklappen zu umgehen, erweitern wir unser Tool so, dass das zu einer Textur zugehörige Sprite automatisch ermittelt wird.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
In diesem Abschnitt realisieren wir ein Drag and Drop-System, so dass sich Karten mit der Maus vom Stapel auf das Spielbrett ziehen lassen. Dazu sehen wir uns Unitys EventSystem und die Drag and Drop-Interfaces an. Wir realisieren ein Geisterabbild, das die Karte während des Ziehens halbtransparent darstellt. Das Thema Drag and Drop wird vertieft, in dem unterschiedliche Datenquellen und Ablageflächen gleichzeitig unterstütz werden, so dass es möglich sein wird, Karten auch innerhalb von Ablagestapeln zu verschieben.
In diesem Abschnitt entstehen die Fehlermeldungen "Can not convert from method group" und "Can't remove RectTransfrom" deren Ursache und Lösung wir besprechen.
Da es sich um eine Patience-Variante handelt, duplizieren wir die Patience-Szene, fügen sie dem Build hinzu und ergänzen eine Menü-Option.
Errata
Werden bestimmte Interfaces des EventSystem-Namensraums in den MonoBehaviours implementiert, ist es möglich, das Ziehen einer Karte zu aktivieren und auszuwerten ohne dabei Anker im Inspector setzen zu müssen.
Auch für das Ablegen können wir ein Script durch Implementierung des DropHandlers ergänzen.
Im Drop-Ereignis rufen wir wieder das Ablegen der Vorschaukarte auf die Spalte unterhalb des Mauszeigers auf.
Die Darstellung der gezogenen Karte erfolgt durch den Einsatz eines Ghost-Images, das der Maus während des Ziehens folgt.
Beim echten Drag'n'Drop liest das Programm aus dem Drag-Ereignis-Parameter pointerDrag aus, welches Objekt mit der Maus gezogen wurde. Da wir bisher beim Droppen nur das Klick-Ereignis aufrufen, erweitern wir unser Script nun in einem ersten Schritt für mehr Flexibilität.
Um Karten zwischen den Ablagespalten verschieben zu können, müssen wir das Drop-Script um die Unterscheidung der Datenquelle erweitern.
Die Ereignisabläufe unterscheiden sich hinsichtlich der aufzuräumenden abhängigen Komponenten. Daher müssen wir nach Verteilung der Ablagelogik nun auch einige Folgeoperationen an andere Stellen verschieben.
Um das Spiel während der Entwicklung schneller testen zu können, reduzieren wir den Kartenstapel auf eine minimale repräsentative Menge von Karten. Außerdem verschieben räumen wir die Prüfung des Gewinnereignisses auf, so dass der Gewinndialog wieder zum richtigen Zeitpunkt erscheint.
Beim Ziehen zwischen den Spalten muss nun auch die Drag-Quelle berücksichtigt werden, um das richtige Vorschaubild zu zeigen und das Drag-Ereignis im Fall leerer Spalten abzubrechen.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Errata
In diesem Abschnitt realisieren wir die Patience-Variante "Klondike". Hier stehen sieben Ablagespalten bereit, durch deren stufenweise Befüllung mit verdeckten Karten die typische Harfenformation entsteht. Zu den Karten im Stock kommen nun also Karten auf dem Spielbrett hinzu, die zur Auswahl stehen, aber durch andere Karten zunächst blockiert werden.
Um verborgene Karten zu erreichen, lassen sich ganze Unterstapel bereits aufgedeckter Karten jetzt per Drag and Drop auf andere Spalten verschieben, wobei sich die freiwerdende verdeckte Karte automatisch umdreht. Hierfür nehmen wir einige Änderungen am Drag'n'Drop-System und dem Spielprinzip vor, das wir durch ein optionales Modul erweitern.
Damit wir vor allem das Spielende schnell testen können, realisieren wir einen Entwicklermodus mit dem sich zwischen der echten Spielsituation und der schnell lösbaren Testversion mit nur einem Klick umschalten lässt.
Für die Legeformation "Harfe" der Klondike-Patience duplizieren wir zunächst die vorhandenen Spalten, um 7 Ablagezonen zu erhalten. Da der Platz auf dem Spieltisch knapp wird, sehen wir uns das Skalierungswerkzeug sowie die hierarchische Skalierung an, um Größenänderungen zu stapeln.
Nur im Klondike-Spielprinzip liegen Karten sofort in den sieben Spalten. Um den Rest des Projekts möglichst wenig zu beeinflussen und um Code bei Bedarf an beliebige Stellen des Spielprinzips einschleusen zu können, realisieren wir die neue Logik als Erweiterungsmodul.
Um das Ansteigen der Anzahl der automatisch ausgelegten Karten zu bewirken, umgeben wir die Ausgabeformel mit einer weiteren For-Schleife in der wir den Spaltenindex als Indiz für die benötigte Kartenanzahl interpretieren.
In den automatisch befüllten Spalten soll nur die oberste Karte sichtbar sein, während die darunterliegenden erst freigespielt werden müssen. Hierfür nutzen wir die bereits früher eingebaute Umdreh-Funktion unserer Karte.
Beim Abheben einer Karte aus einer Spalte wird möglicherweise eine darunterliegende Karte frei, die nun automatisch aufgedeckt werden soll. Ein Problem besteht dabei darin, dass das Entfernen der vorherigen Karte erst verzögert ausgeführt wird, so dass die darunterliegende Karte nicht wie erwartet zu finden ist.
Für das Stapellayout haben wir den Pivotpunkt versetzt, was nun mit der Umdrehanimation kollidiert, die wiederum den Pivotpunkt in der Objektmitte erwartet. Wir lösen das Problem nun durch leichte Anpassung der Layout-Formel.
Um an verdeckte Karten heran zu kommen, kann der Spieler bereits gültige Teilstapel zwischen den Ablagespalten verschieben. Hierfür ermitteln wir zunächst die Karte unter der Maus und speichern die darauf liegenden Karten in einer temporären Liste.
Das Verschieben des Teilstapels wird nun durch Anpassen und Wiederholen bereits bekannter Vorgänge tatsächlich durchgeführt.
Damit der Spieler sieht, was beim Teilstapel-Ziehen am Mauszeiger hängt, erweitern wir das Ghost-Image um eine Gruppierungsfunktion.
Die Klondike-Variante ist erst gewonnen, wenn nach Ablagen aller Karten in die Harfe diese auch wieder rückwärts nach gemeinsamer Farbe und aufsteigendem Wert sortiert eingesammelt werden. Dazu legen wir vier Endablageflächen an und versehen sie mit einer vereinfachten Variante des Drop-Scripts.
Das Gewinnereignis unterliegt beim Einsatz der Endablagestapel anderen Abläufen und Bedingungen, deren Berücksichtigung wir in diesem Video einbauen.
Um das Gewinnereignis zu testen, müsste die gesamte Patience durchgespielt werden. Zur Vereinfachung bauen wir deshalb einen Entwickler-Modus zum schnellen Testen mittels eines Cheats ein und korrigieren die damit identifizierten Fehler.
Hier findest Du eine Kopie der C#-Scripte, wie sie in den Videos bis hier geschrieben wurden. Du kannst so Deinen Code mit dem Kurs-Code vergleichen, falls irgendwo Probleme entstanden sind.
Lerne Spiellogik mit C# in Unity umzusetzen, DEM weltweiten Industrie-Standard für Videospiel-Produktion.
In diesem Kurs lernst Du Spielregeln und Interaktionsabläufe in C# auszudrücken und in Kombination mit Unitys UI-Grafiksystem Deine eigenen Computerspiele zu produzieren. Wir setzen in diesem Kurs Kartenspiele um und programmieren Regelwerke für Tarot, Patience, Klondike und MauMau. Das Wissen, das Du während der Umsetzung dieser Spiele gewinnst, ist so aufbereitet, dass es sich auch auf andere Spielkonzepte übertragen lässt.
Der Kurs zielt darauf ab, die Funktionsweise von Unity so zu erklären, dass sie für Anfänger leicht zu verstehen sind. Für Einsteiger, die schonmal mit Unity experimentiert haben, ist dieser Kurs eine ideale Gelegenheit, um das technische Verständnis von Unitys Funktionsweise und der Programmierung in C# zu vertiefen und zu trainieren.
DAS WIRST DU LERNEN:
Unitys UI-System zur Darstellung von Spielobjekten nutzen
Spielbrett, Karten und Kartenstapel realisieren
Karten zeigen und/oder verdecken
Spielkarte per Zeitleiste und Code animiert umdrehen
Aufbau einer Spielobjektbibliothek und Wiederverwendung von Prefabs
Kartenstapel als Liste von Karten realisieren
Ziehen einer bestimmten oder zufälligen Karte, Mischen des Stapels, Zurücklegen einer Karte
Gezogene Karten durch per Script auf den Tisch legen
Unterschiedliche Spiele auf Szenen verteilen, Gemeinsamkeiten dabei wiederverwenden
Menü zum Szenenwechsel zentral einbauen
Beschränken von Spielzügen
Legen von vorgegebenen Formationen
Status-Texte, Gewonnen/Verloren-Dialoge und Hilfestellungen anzeigen
Karten im Stock duplizieren
einen oder mehrere Kartenablageplätze auf dem Tisch ermöglichen
Karten mit eigenen Layout-Funktionen anordnen
Farbe und Wert einer Karte definieren und per Code verarbeiten
Konkrete Beispiele für Rechenwege um Karten zu vergleichen
Realisierung von Kartenspielregeln
Eine oder mehrere Karten per Drag&Drop mit der Maus verschieben, Anzeige des Bilds am Mauszeiger (Ghost)
Kartensatz in der Hand des Spielers anlegen
Einen oder mehrere Computergegner für MauMau programmieren
Spielrunden umsetzen
...
UND AUßERDEM LERNST DU DIESE ESSENTIELLEN C#-KONZEPTE KENNEN:
Vorgehen zur selbständigen Fehlersuche und Problemanalyse
Funktionen an Animationszeitpunkten aufrufen
Trennung von Darstellungscode, Spiellogik und Kartenwerten
Code-Organisation in Modulen, Trennung von Unterschieden, Zentralisierung von Gemeinsamkeiten
Unity-Funktionen oder eigene Methoden an UI-Ereignisse binden, per Inspector sowie auch per Code
Delegaten und Callbacks schreiben
Verändern der Text-Konvertierung von C#-Objekten
mit Timern und Coroutinen Abläufe programmieren
Code nur per EventSystem-Interfaces in den Spielfluss integrieren
Entwickler-Cheats für schnelles Testen einbauen
Klassen-Hierarchien und Vererbung
Objekte nach Klasse unterscheiden
Spielparteien realisieren
...
Erweiterung des Unity-Editors:
Grundlagen der Editor-Erweiterung
Auslesen der im Editor markierten Assets
Sprites erkennen, suchen und in die Kartenliste des Kartenstapels eintragen
Kartenwerte vom Dateinamen ableiten
...
Typische Fehler, ihre Analyse und Behebung:
Index out of Range
Null Reference Exception
Out of Memory
Can not convert from method group
Can't remove RectTransform
Eingabe-Fokus vs. Tastenauswertung
...
DAS SETZEN WIR IN DIESEM KURS KONKRET UM:
Ein Projekt mit verschiedenen Kartenspielen, je als separate Szenen
Menü über das der Spieler zwischen den Kartenspielen wechseln kann
Tarot: Kleines Kreuz
· Es werden 4 zufällige Karten aus dem Kartenstapel gezogen.
· Die Karten werden in bestimmter Reihenfolge auf vorgegebene Ablageplätze der Formation "Kleines Kreuz" gelegt.
· Jedem Platz ist eine Bedeutung zugeordnet, die die Interpretation der Karte beeinflusst.
Paare finden
· Jedes Kartenbild liegt zweimal im Kartenstapel.
· Die Karten werden alle gleichzeitig verdeckt ausgelegt.
· Der Spieler dreht zwei Karten um. Sind sie identisch, werden sie vom Tisch genommen. Sind sie unterschiedlich, werden beide wieder verdeckt.
· Ziel ist es, alle Paare zu finden.
Minimale Patience
· Aus dem verdeckten und gemischten Kartenstock zieht der Spieler eine Karte.
· Die Karte kann in eine von vier Ablagespalten platziert werden.
· Ist die Spalte leer, ist nur ein Ass platzierbar.
· Liegen Karten in der Spalte kann nur eine Karte mit umgekehrter Farbe (rot auf schwarz) und dem nächst niedrigen Wert (9 auf 10) abgelegt werden.
· Ist keine Ablage möglich, wandert die Karte nach unten zurück in den Stapel und die nächste obere Stapelkarte wird gezogen.
· Ziel ist es, alle Karten abzulegen.
Klondike- Patience
Wie Minimale Patience, aber mit folgender Erweiterung:
· Es stehen sieben Ablagespalten zur Verfügung.
· Zu Beginn werden die sieben Spalten mit Karten befüllt. Dabei enthält jede Spalte eine Karte mehr als die vorherige. In der ersten Spalte liegt eine Karte, in der zweiten zwei, in der dritten drei, usw. Nur die oberste Karte jeder Spalte ist aufgedeckt.
· Übrige Karten verbleiben im Stock von dem jeweils die oberste umgedreht und ins Spiel eingebracht werden kann.
· Nur aufgedeckte Karten sind spielbar. Eine verdeckte Karte wird automatisch umgedreht, wenn sie die oberste Karte in der Spalte ist.
· Um verdeckte Karten zu erreichen, ist es möglich, bereits gelegte Kartenserien zwischen den Stapeln zu bewegen, sofern die Ablage gemäß den Patience-Regeln erlaubt ist.
· Zudem stehen vier Endablagestapel bereit. Das Spiel ist gewonnen, wenn alle Karten einer Farbe (z.B. Herz) in umgekehrter Reihenfolge (2 als erstes, Ass als letztes) auf den vier Endablagestapeln liegen.
Mau-Mau
· Der Spieler spielt gegen einen oder mehrere Computergegner.
· Aus dem gemischten Kartenstapel erhält jeder Spieler fünf Karten. Eine weitere Karte wird offen auf den Tisch ausgelegt.
· Abwechselnd darf jeder Spieler eine Karte ablegen. Eine Karte passt auf eine andere Karte, wenn die gewählte Karte und die bereits liegende Karte die gleiche Farbe oder den gleichen Wert haben.
· Hat der Spieler keine passende Karte, kann einmal pro Runde eine Karte vom Stock aufgenommen werden. Passt sie, kann sie abgelegt werden. Passt sie nicht, ist der nächste Spieler an der Reihe.
· Wer als erster alle Karten ablegen konnte, hat gewonnen.
ES WIRD NOCH BESSER:
Übungen mit Musterlösungen zur eigenen Vertiefung der Themen
kostenloses Asset-Paket mit den nötigen 3D-Modellen und Ressourcen, um sofort selbst mitzumachen
"Sicherungspunkte" mit dem kompletten Abschnitts-Code für Fehlersuche und Vergleich mit dem Deinem Code
pures Kompaktwissen - keine Compiler- oder Wartezeiten in den Videos!
... und natürlich Udemy's extrem kundenfreundliche Benefits: 30-Tage Rückgaberecht, integriertes Support-Forum und Abschlusszertifikat
Los geht's - starte jetzt mit der Programmierung Deiner Spiele!