Es handelt sich um ein Enum in Java, das alle gültigen Poker-Handtypen definiert.
Diese werden später verwendet, um zu entscheiden, welche Hand der Spieler gerade spielt (z. B. „Flush“) und wie viele Punkte dafür vergeben werden.
Optional erwähnbar:
Solche Enums sind auch nützlich für Switch-Statements oder zur Punktevergabe-Logik, weil man mit einem einzigen Wert eine ganze Kombination klassifizieren kann.
Die Methode evaluate bewertet eine gegebene Kartenhand. Der hier gezeigte Ausschnitt stellt sicher, dass die Hand nicht mehr als 5 Karten enthält, sonst wird sie als ungültig (PokerHandType.INVALID) eingestuft. Das schützt gegen fehlerhafte Eingaben oder Client-Manipulation. Später in der Methode würde dann bestimmt, ob es sich z. B. um ein Paar, einen Flush usw. handelt.
evaluate
PokerHandType.INVALID
Dieser Code ist der Konstruktor der Klasse GameController, also der Spiel-Logik-Controller auf der Clientseite. Er verbindet die wichtigsten Bestandteile der Benutzeroberfläche und der Netzwerkkommunikation miteinander:
GameController
Referenzzuweisungen:
networkClient, screenManager und gameScreen werden den Instanzvariablen zugewiesen. Dadurch hat der GameController Zugriff auf die Netzwerkverbindung, das aktive GUI-Fenstermanagement und das Spielfenster.
networkClient
screenManager
gameScreen
Button-Handler registrieren:
Es wird festgelegt, was passieren soll, wenn der Spieler auf „Info“ oder „Optionen“ klickt. Die Methoden onInfo() und onOptions() werden als Event-Handler gesetzt.
onInfo()
onOptions()
Selbst-Referenz setzen:
gameScreen.setController(this) sorgt dafür, dass das Spielfenster Zugriff auf den Controller bekommt. Das ist z. B. nützlich für Rückmeldungen bei Button-Clicks oder Anzeigeupdates.
gameScreen.setController(this)
Netzwerk-Nachrichtenhandler setzen:
networkClient.setMessageListener(this::onServerMessage) registriert eine Methode, die automatisch aufgerufen wird, wenn der Server eine Nachricht an den Client sendet – das ist essenziell für asynchrone Kommunikation.
networkClient.setMessageListener(this::onServerMessage)
Der Konstruktor vernetzt GUI und Netzwerk mit der Spiellogik. Ohne diese Verbindung könnte der Client keine Nachrichten empfangen oder auf Benutzereingaben reagieren – er wäre quasi "tot".
Neues Spiel initialisieren (startGame)
startGame
Deck neu erstellen und mischen
Zähler zurücksetzen: Team-Score, Handanzahl, Discards
Spielerreihenfolge und Kartenzustände bereinigen
Spielerhände neu austeilen (8 Karten pro Spieler)
Der aktuelle Spielerindex wird auf 0 gesetzt – das zeigt, wer als Erstes am Zug ist
Die Methode bereitet alles für den Start der ersten Runde vor, ist also der Einstiegspunkt nach der Lobby
„Beschreiben Sie die Architektur Ihres Projekts auf High-Level-Ebene. Welche Rollen spielen Client und Server, und wie ist die Verantwortung zwischen ihnen aufgeteilt?“
Unser Projekt basiert auf einer Client-Server-Architektur: Der Client ist zuständig für die Benutzeroberfläche (GUI), die Eingabe der Spieler sowie die Darstellung des Spielstatus. Er folgt dem MVC-Prinzip: Die View zeigt die Karten und Buttons, der Controller reagiert auf Nutzereingaben, und das Model verwaltet die Kartendaten auf Client-Seite.
Der Server übernimmt die zentrale Spiellogik – insbesondere die Bewertung von Pokerhänden, die Verwaltung des Team-Scores, und die Abwurf-Logik. Jeder Client verbindet sich über eine IP/Port-Kombination mit dem Server.
Durch diese Trennung bleibt die Spiel-Logik sicher auf dem Server, was Manipulation verhindert. Gleichzeitig bleibt der Client schlank und fokussiert auf Benutzerinteraktion.
Diese Methode mischt den Kartenstapel mithilfe von Collections.shuffle(). Das sorgt dafür, dass die Karten in zufälliger Reihenfolge liegen – genau wie bei einem echten Kartenspiel. Ohne diese Methode würde das Spiel vorhersehbar oder manipulativ werden.
Collections.shuffle()
Mögliche Antworten:
✅ Positive Designentscheidungen:
Info-Button mit Spielregeln:
Hilft neuen Spielern beim Einstieg
Unterstützt Selbsthilfe bei Unklarheiten
Punktestand immer sichtbar (Sidebar):
Spieler sehen sofort, wie nah sie am Ziel sind
Wichtiges Feedback-Element
Karten des Mitspielers sichtbar:
Fördert Kooperation und Kommunikation
Passt zur kooperativen Spielidee
Animationen bei Spielaktionen:
Erhöhen Interaktivität und Spielgefühl
Machen das Spiel lebendiger
Fehlereingaben werden verhindert:
Nicht klickbare Karten oder Buttons bei ungültigen Aktionen
Reduziert Frust und erhöht Sicherheit
Visuelle Trennung von Spielfeld, Sidebar und Buttons:
Gute Strukturierung, erleichtert Orientierung
🟡 Verbesserungspotenzial / Kritikpunkte:
Wenig Feedback bei Punktevergabe:
Spieler sehen nicht direkt, welche Poker-Hand erkannt wurde
→ Verbesserungsidee: Tooltip oder kurze Textnachricht ("Straight – 90 Punkte!")
Einige UI-Komponenten (z. B. schwarze Fenster) mehrfach redundant implementiert:
→ Verbesserungsidee: eine zentrale, parametrisierbare Methode für Seitenelemente
Responsives Design oder Skalierung nicht erwähnt:
Aktuell möglicherweise auf feste Fenstergrößen beschränkt
Die run()-Methode des ClientHandler ist der zentrale Loop, der dauerhaft auf Nachrichten vom Client wartet. Sie deserialisiert JSON-Nachrichten und entscheidet, ob es sich um einen Beitritt (JOIN) handelt – dann wird der Spieler registriert – oder um andere Aktionen, die an den LobbyManager weitergereicht werden. Diese Struktur sorgt für eine saubere Trennung von Verbindungsmanagement und Spiellogik.
run()
ClientHandler
JOIN
LobbyManager
„Du siehst hier den Konstruktor der GameScreen-Klasse. Was würdest du an dieser Implementierung verbessern oder refactoren – und warum?“
GameScreen
Konstruktor ist zu lang → verletzt das SRP (Single Responsibility Principle)
Könnte in Methoden wie setupSidebar(), setupMainGameArea(), initPopupBox() zerlegt werden
setupSidebar()
setupMainGameArea()
initPopupBox()
Erhöht:
Lesbarkeit
Wartbarkeit
Testbarkeit
Teamverständnis
Optional: Wiederholte UI-Elemente wie MiniBox oder SidebarBox als eigene Klassen extrahieren
MiniBox
SidebarBox
Dieser Codeausschnitt stammt aus der Bewertung einer Pokerhand – wahrscheinlich aus der evaluate()-Methode in PokerHand.java. Er prüft, welche Handkombination eine übergebene Kartenhand darstellt.
evaluate()
PokerHand.java
🔍 Schritt für Schritt:
isFlush = isFlush(hand) prüft, ob alle Karten dieselbe Farbe haben.
isFlush = isFlush(hand)
isStraight = isStraight(hand) prüft, ob die Karten aufeinanderfolgende Werte haben.
isStraight = isStraight(hand)
getRankCounts(hand) zählt, wie oft jeder Kartenwert vorkommt.
getRankCounts(hand)
counts.contains(4) prüft, ob es vier Karten desselben Rangs gibt → also ein Vierling.
counts.contains(4)
🃏 Bewertung:
Wenn sowohl isFlush als auch isStraight true sind → STRAIGHT_FLUSH
isFlush
isStraight
STRAIGHT_FLUSH
Wenn vier Karten denselben Rang haben → FOUR_OF_A_KIND
FOUR_OF_A_KIND
💡 Kontext in Duolatro:
Diese Logik wird auf dem Server verwendet, um die vom Client übergebene Hand zu bewerten. Das Ergebnis (z. B. „Straight Flush“) wird dann mit einer festen Punktzahl verknüpft und an den Client zurückgeschickt. Es handelt sich um einen zentralen Teil der Spielmechanik, da die Bewertung direkt den Spielausgang beeinflusst.
„Wie funktioniert die Abwurf-Mechanik in eurem Spiel genau – technisch und spielerisch? Warum habt ihr das so gemacht und was bringt das für den Spielfluss?“
Welchen Vorteil hat es eine HashMap zu Verwenden für die Abwurf-Mechanik?
HashMap
In der Abwurf-Logik speichern wir, welcher Spieler welche Karte als Erster abgeworfen hat. Dafür eignet sich eine HashMap<Card, String> besonders gut – aus mehreren Gründen:
HashMap<Card, String>
✅ 1. Schneller Zugriff (O(1))
HashMap ermöglicht konstante Zugriffszeit auf Elemente
Bei jedem neuen Abwurf können wir sofort prüfen, ob die Karte bereits existiert:
if (discardedCards.containsKey(card)) { ... }
Das ist viel schneller als z. B. eine Liste durchzugehen (O(n))
✅ 2. Direkte Zuordnung (Key → Value)
Die Card ist der Key – eindeutig und direkt abrufbar
Card
Der Wert (String) ist der Spielername, der die Karte zuerst abgeworfen hat
String
Das macht den Code lesbar und logisch:
discardedCards.get(card) → gibt den ursprünglichen Spieler zurück
✅ 3. Einfache Verwaltung von Zuständen
Mit put() und remove() kann der Zustand einer Karte gezielt aktualisiert oder entfernt werden
put()
remove()
Kein komplexes Durchsuchen nötig – ideal für Spiellogik mit vielen Kartenoperationen
✅ 4. Keine Duplikate
Eine Map lässt jeden Key nur einmal zu – damit ist sichergestellt, dass dieselbe Karte nicht mehrfach gleichzeitig gespeichert wird (z. B. versehentlich bei zwei Spielern gleichzeitig)
Map
Die Verwendung einer HashMap ist hier ideal, weil sie effizient, klar und verlässlich ist. Sie erlaubt es, pro Karte genau einen „Besitzer“ im Abwurfstatus zu verwalten – bei gleichzeitig minimalem Rechenaufwand. Perfekt für die Echtzeitspiel-Logik von Duolatro.
„Welche Ressourcen sind im Spiel Duolatro begrenzt – und wie beeinflusst das das Spielgefühl und die Taktik? Warum habt ihr euch dafür entschieden, z. B. den Nachziehstapel nicht neu zu mischen?“
Begrenzte Ressourcen:
Handzüge (Hands): Anzahl erlaubter Pokerzüge
Abwürfe (Discards): Taktische Möglichkeit zum Kartenmanagement
Kartenstapel: wird nicht neu gemischt → jede Karte ist einmalig
Spielerische Wirkung:
Planung statt Zufall
Kooperation wird wichtiger
Timing & Kartenkenntnis entscheidend
Technische Umsetzung:
Deck wird zu Beginn erstellt (2×52 Karten), dann nicht mehr verändert
Hands/Discards werden auf dem Server gezählt und verwaltet
Warum kein Neumischen:
Erhöht Spannung & Schwierigkeit
Gehört zum zentralen Designprinzip
„Welche Zusatzfeatures habt ihr bereits eingebaut – und welche würdet ihr als Nächstes implementieren, wenn ihr weiter am Projekt arbeiten würdet? Begründe deine Auswahl.“
Bereits eingebaute Zusatzfeatures:
Lobby
Hintergrundmusik
Info-Button mit den Spielregeln
Options-Button mit der Möglichkeit sich eine eigenen Challenge zu setzen
Was würden wir als Nächstes implementieren?
Möglichkeit eine neue Runde zu starten
Benachrichtigung, falls ein Spieler das Spiel mittendrin verlässt
Shop
…
„Wie habt ihr im Team zusammengearbeitet? Wie war eure Arbeitsaufteilung, und wie habt ihr sichergestellt, dass der Code zusammenpasst (z. B. mit Git, Code Reviews, Absprachen)?“
Ich war im Team für das Frontend zuständig, insbesondere für die Views. N. hat sich um die Controller gekümmert, und der Rest des Teams war für das Model und den Server verantwortlich.
Anfangs haben wir unabhängig voneinander gearbeitet – es gab zuerst Model- und View-Komponenten, die später über die Controller verbunden wurden.
🔧 Code-Zusammenführung & Git:
Wir haben regelmäßig gepullt, um Konflikte zu vermeiden
Wenn Merge-Konflikte auftraten, haben wir diese manuell gelöst
Teilweise wurde in Absprache mit Teammitgliedern entschieden, welche Version übernommen wird
📞 Absprache & Kommunikation:
Wir haben uns in Meetings (persönlich & über Zoom) abgestimmt
Zusätzlich haben wir über Textnachrichten (WhatsApp) kommuniziert
Für die Organisation haben wir Aufgabenlisten erstellt, um Verantwortlichkeiten zu klären
🔁 Reflexion & Verbesserungsvorschläge:
Im Nachhinein hätten wir zuerst die Server-Client-Architektur vollständig festlegen und implementieren sollen
Stattdessen haben wir die Struktur erst spät erkannt und mussten große Teile überarbeiten
Dadurch hätten wir Schnittstellenprobleme und Zeitverlust vermeiden können
📝 Musterlösung – Konstruktor von StartController
StartController
Der Konstruktor der Klasse StartController initialisiert zwei zentrale Abhängigkeiten des Startbildschirms:
🔗 Parameterbedeutung:
NetworkClient:
NetworkClient
Wird benötigt, um vom Startscreen aus eine Verbindung zum Server herzustellen
Enthält Methoden zur Verbindung mit IP/Port und zur Kommunikation (z. B. „JOIN“-Nachricht senden)
ScreenManager:
ScreenManager
Verwaltet die Navigation zwischen verschiedenen Bildschirmen im Spiel (Startscreen, Lobby, GameScreen, usw.)
Erlaubt es dem Controller z. B., nach erfolgreicher Verbindung zur Lobby oder ins Spiel zu wechseln
🎮 Rolle im Projekt:
StartController ist zuständig für den Einstieg ins Spiel:
Verbindungsaufbau zum Server
Wechsel zur Lobby
Eventuelle Fehlermeldung bei Verbindungsproblemen
Die beiden Komponenten networkClient und screenManager sind dafür unverzichtbar – ohne sie könnte der Controller weder eine Verbindung aufbauen noch den Bildschirm wechseln
🧠 Warum wichtig:
Diese Konstruktorinitialisierung macht Abhängigkeiten explizit – was gut für Testbarkeit und Kapselung ist
Außerdem folgt es dem Dependency Injection-Prinzip: Der Controller ist nicht selbst verantwortlich für das Erzeugen von Netzwerk- oder Screenobjekten
„Was habt ihr bei der Gestaltung eures Spiels unternommen, um es für möglichst viele Nutzer zugänglich zu machen – z. B. hinsichtlich Verständlichkeit, Farben, Steuerung oder Barrierefreiheit? Was wäre aus deiner Sicht noch verbesserbar?“
✅ Umgesetzte Maßnahmen:
Gute Farbkontraste in UI-Elementen
Keine schwer unterscheidbaren Farbkombinationen wie Rot-Grün oder Gelb-Blau (größtenteils vermieden; falls doch diese Kombinationen verwendet, dann noch unterstützend mit einem sich ändernden Text zur zusätzlichen Unterscheidung)
Große Buttons zur leichteren Bedienung – gut für Nutzer mit motorischen Einschränkungen
Kombination aus Farbe + Text
Beispiel: In der Lobby wird „Bereit“ nicht nur farblich, sondern auch textlich angezeigt
Dadurch bleibt die Information auch für farbenblinde Nutzer zugänglich
🟡 Noch verbesserbar:
Rot-Grün-Kennzeichnung in der Lobby zwar mit Text – aber evtl. ergänzen durch Symbole (✔ / ✖) zur besseren Orientierung
Keine explizite Unterstützung für:
Tastatursteuerung
Screenreader-Kompatibilität
Lautstärkeoptionen / Audio-Hinweise könnten ergänzt werden (z. B. bei Spielzugwechsel)
❓ Was hast du persönlich und fachlich aus dem Projekt gelernt?
Beispielantworten:
🧠 Fachlich gelernt:
Client-Server-Architektur praktisch angewendet → Wie man Daten zwischen zwei Clients über einen zentralen Server zuverlässig austauscht
Netzwerkprogrammierung in Java mit Sockets und JSON → Verständnis für Verbindungsaufbau, Nachrichtentypen, Fehlerbehandlung
GUI-Design mit JavaFX → Umgang mit Layouts, Event-Handling, Styling, Benutzerführung
Anwendung von MVC-Prinzipien → Trennung von Logik, Datenhaltung und Anzeige im Client
Versionsverwaltung mit Git im Team → Konfliktlösung, Pull-Strategien, Branch-Handling, Zusammenarbeit mit anderen
Testen und Debugging in komplexen Projekten → Warum Tests wichtig sind und wie man systematisch Fehler eingrenzt
👤 Persönlich gelernt:
Teamarbeit und Kommunikation sind entscheidend → Gerade bei parallelem Arbeiten sind klare Schnittstellen und regelmäßige Absprachen nötig
Fehler sind normal – wichtig ist, sie früh zu erkennen und offen anzusprechen
Zeitmanagement → Grobe Planung hilft, aber auch spontane Umstellungen muss man gut auffangen können
Reflexionsfähigkeit → Nicht alles funktioniert beim ersten Versuch – wichtig ist, daraus zu lernen und es beim nächsten Mal besser zu machen
Mehr Selbstvertrauen im Umgang mit komplexen Systemen → Nach dem Projekt traue ich mir deutlich mehr zu – z. B. in Bezug auf Architekturentscheidungen oder UI-Design
Die Methode sendTurnUpdate() benachrichtigt alle Spieler darüber, wer aktuell am Zug ist. Dazu wird für jeden ClientHandler eine JSON-Nachricht erzeugt, die angibt, ob der jeweilige Spieler selbst am Zug ist (yourTurn: true/false) und wer aktuell spielt (playerName). Die Clients nutzen diese Information, um das UI und die Eingabemöglichkeiten entsprechend zu aktualisieren. Ohne diese Methode wäre keine saubere Zugsteuerung im Multiplayer möglich.
sendTurnUpdate()
yourTurn: true/false
playerName
Die Methode evaluate() ist static, weil sie keine Objektinstanz benötigt. Sie führt lediglich eine Berechnung auf einer gegebenen Kartenliste durch – deshalb reicht ein statischer Methodenaufruf.Die Bedingung hand.size() > 5 stellt sicher, dass nur gültige Pokerhände mit maximal 5 Karten bewertet werden. Bei mehr als 5 Karten kann keine klassische Hand eindeutig zugeordnet werden – deshalb gibt die Methode in diesem Fall PokerHandType.INVALID zurück.
static
hand.size() > 5
In diesem Codeabschnitt wird geprüft, ob die Hand eine Straight Flush ist – das ist eine der höchsten möglichen Pokerhände.Dazu wird zuerst mit isFlush() geprüft, ob alle Karten dieselbe Farbe (z. B. Karo) haben, und mit isStraight() ob sie aufeinanderfolgende Werte haben (z. B. 4–5–6–7–8).Nur wenn beide Bedingungen zutreffen, liegt ein PokerHandType.STRAIGHT_FLUSH vor.Die rankCounts-Map zählt, wie oft jede Kartenwert-Stufe (z. B. Dame, 8, Ass) vorkommt – sie wird später z. B. genutzt, um Paare, Drillinge oder Vierlinge zu erkennen.
isFlush()
isStraight()
PokerHandType.STRAIGHT_FLUSH
rankCounts
Wenn ein Spieler auf den Button „Play Hand“ klickt, wird die Methode controller.onPlayHand() aufgerufen.Diese sammelt die aktuell ausgewählten Karten und sendet sie an den Server. Dort wird überprüft, welche Pokerhand gespielt wurde, wie viele Punkte das Team dafür erhält, und ob der Boss besiegt wurde.Die Antwort des Servers enthält u. a. die neuen Punkte, die Anzahl der verbleibenden Karten und Spielzüge. Diese Daten werden im Client genutzt, um die Sidebar zu aktualisieren, neue Karten zu ziehen und den Spielzustand visuell darzustellen. Die Animation sorgt dabei für ein klares Feedback der Aktion.
controller.onPlayHand()
Die Message-Klasse wird für die Kommunikation zwischen Client und Server verwendet. Sie enthält ein type-Feld, das beschreibt, welche Art von Nachricht es ist (z. B. "JOIN" oder "TURN_UPDATE"), und ein content-Feld, das die eigentlichen Daten der Nachricht enthält.Der type ist ein String, damit man leicht damit filtern und schalten kann.Das content-Feld ist als Object deklariert, weil die Inhalte je nach Nachricht sehr unterschiedlich sein können. Beim Empfangen wird der Inhalt mit Gson geparst und je nach Bedarf interpretiert.Dadurch ist die Klasse universell einsetzbar, was die Netzwerkkommunikation stark vereinfacht.
Message
type
"JOIN"
"TURN_UPDATE"
content
Object
Diese Zeile leitet eine empfangene Nachricht vom Client (message) weiter an den LobbyManager.Der ClientHandler ist dafür zuständig, die Verbindung zum Client zu halten und eingehende Nachrichten zu empfangen. Er ist aber nicht für Spiel- oder Lobbysteuerung zuständig.Diese Aufgaben übernimmt der LobbyManager, der als Singleton verwaltet wird (getInstance()).Die Weiterleitung mit handleMessage(this, message, playerName) ermöglicht es dem LobbyManager, Spielaktionen und Statusänderungen zentral zu verarbeiten – z. B. ob ein Spieler bereit ist, ein Spiel starten will, oder eine Nachricht an andere Clients geschickt werden soll.Diese Trennung sorgt für klare Verantwortlichkeiten und eine bessere Wartbarkeit des Codes.
message
getInstance()
handleMessage(this, message, playerName)
Die Methode setDiscardButtonDisabled(boolean disabled) aktiviert oder deaktiviert den „Discard“-Button auf der Benutzeroberfläche.Sie wird aufgerufen, wenn der Spieler nicht an der Reihe ist oder keine Discards mehr übrig hat.Der null-Check stellt sicher, dass die Methode nicht abstürzt, falls discardButton noch nicht initialisiert wurde – z. B. während des Aufbaus der GUI oder bei frühem Spielstart.Die Deaktivierung des Buttons verhindert, dass Spieler unerlaubte Aktionen ausführen können und sorgt so für ein konsistentes Spielerlebnis.
setDiscardButtonDisabled(boolean disabled)
null
discardButton
Dieser Code registriert einen Mausklick auf eine Karte und überprüft dabei, ob die Karte zum aktuell aktiven Spieler gehört.Nur wenn das der Fall ist, darf die Karte ausgewählt oder anderweitig verwendet werden.Wenn diese Prüfung fehlen würde, könnten Spieler Karten des Teamkollegen anklicken, was nicht erlaubt ist und die Spielmechanik durcheinanderbringen würde.Die Prüfung sorgt für ein regelkonformes Verhalten der GUI und schützt das Spiel vor falschen Benutzereingaben.
Die Zeile prüft, ob der infoButton existiert, und weist ihm dann einen EventHandler zu – dieser wird ausgeführt, wenn der Spieler auf den Button klickt.Der Handler öffnet typischerweise ein Popup-Fenster mit den Spielregeln.Der null-Check verhindert, dass es zu einem Fehler kommt, wenn der Button noch nicht geladen oder gesetzt wurde.Durch das Setzen des Handlers von außen kann der Controller steuern, was passiert, wenn der Button geklickt wird – ohne dass die View die Logik enthalten muss. Das verbessert die Trennung von Darstellung und Verhalten (MVC-Prinzip).
infoButton
EventHandler
Diese Methode erlaubt es dem Controller, einen eigenen EventHandler für den Options-Button zu setzen.Dadurch wird das MVC-Prinzip eingehalten: Die View zeigt nur die Benutzeroberfläche, die Logik – z. B. das Öffnen des „Set new challenge“-Fensters – bleibt im Controller.Der null-Check stellt sicher, dass der Button existiert, bevor man auf ihn zugreift.Diese Trennung ermöglicht eine leichtere Wartbarkeit, bessere Testbarkeit und saubere Struktur.
Dieses Codestück gehört zur visuellen Rücknahme der Kartenauswahl.Wenn ein Spieler eine zuvor ausgewählte Karte erneut anklickt, wird sie durch setTranslateY(0) wieder in die normale Position bewegt.Gleichzeitig wird die Karte aus dem targetSet entfernt, damit sie nicht mehr als aktive Spielkarte gewertet wird.Abschließend wird der Controller mit onCardDeselected(code) benachrichtigt, sodass die Spiel-Logik entsprechend aktualisiert werden kann.Dieses Zusammenspiel aus UI-Feedback und Steuerung sorgt für eine intuitive Interaktion mit der Hand.
setTranslateY(0)
targetSet
onCardDeselected(code)
1. Konstruktor zu lang
✔️ Richtig: Der Konstruktor enthält viel Setup-Logik (Layouts, Labels, Buttons etc.)
💡 Besser: Aufteilen in klar benannte Hilfsmethoden wie setupSidebar(), initCardZone(), setupButtons(), bindEventHandlers()
initCardZone()
setupButtons()
bindEventHandlers()
Vorteil: Der Konstruktor bleibt lesbar, besser testbar und übersichtlich
2. Wiederverwendbare Methoden für Sidebar-Fenster
✔️ Sehr gute Idee: Viele Methoden (z. B. createBankBox, createBossBox, createScoreBox) wiederholen sich stark
createBankBox
createBossBox
createScoreBox
💡 Besser: Eine Methode wie createSidebarBox(String title, Label label) oder createLabeledBox(String title)
createSidebarBox(String title, Label label)
createLabeledBox(String title)
Vorteil: Weniger Redundanz, einheitliches Design, einfacher zu ändern
Es ist wichtig, dass Animation und Spiellogik synchronisiert ablaufen, damit das Spiel für den Nutzer nachvollziehbar bleibt.Wird z. B. der Punktestand schon vor Abschluss der Kartenanimation angezeigt, entsteht der Eindruck, dass die Punkte aus dem Nichts kommen.Außerdem kann es zu Logikfehlern kommen, wenn neue Karten gezogen oder Buttons aktiviert werden, bevor die laufende Animation abgeschlossen ist (Bsp.: Wenn Animation und Logik nicht getrennt sind, kann es zu race conditions kommen – z. B. zieht der Spieler neue Karten, bevor die alten "verschwunden" sind). Um das zu vermeiden, sollte man Animationen mit setOnFinished(...) versehen und erst nach dem visuellen Feedback die nächste Logik ausführen.Das sorgt für ein konsistentes und stabiles Spielgefühl.
setOnFinished(...)
In diesem Code wird die Kartenanzeige eines Spielers aktualisiert – z. B. nach einem Zug oder Spielstart.Zuerst wird mit cardRow.getChildren().clear() die bestehende Darstellung entfernt, damit keine alten Karten erhalten bleiben oder doppelt angezeigt werden.Auch selectedSet.clear() ist wichtig, um sicherzustellen, dass keine Karten mehr als „ausgewählt“ markiert sind.Danach werden die neuen Kartenobjekte erstellt, in ImageView-Komponenten umgewandelt und ins GUI (cardRow) eingefügt.Ohne diesen Reset würde die Anzeige nicht mehr dem Spielzustand entsprechen – das wäre verwirrend und potentiell fehleranfällig.
cardRow.getChildren().clear()
selectedSet.clear()
ImageView
cardRow
Dieser Code aktualisiert die Sidebar-Labels im Spielbildschirm – darunter die aktuelle Punktzahl, der Basiswert der letzten Pokerhand, sowie Titel und Zielpunktzahl des Bosses. Es ist essenziell, dass diese Informationen nach jedem Zug aktualisiert werden, damit die Spieler jederzeit wissen, wo sie im Spiel stehen. Fehlt diese Aktualisierung, kann es zu Verwirrung oder Fehlinformation kommen – z. B. wenn der Server schon neue Punkte berechnet hat, aber der Client noch alte Daten anzeigt. Die Sidebar ist daher ein zentrales Kommunikationsmittel zwischen Logik und Spieler.
Die Animation selbst sollte in der View definiert sein, da sie rein visuelles Feedback ist.Der Controller steuert jedoch, wann und warum die Animation ausgelöst wird – z. B. beim Klicken auf „Play Hand“.Dabei wird auch gleichzeitig der Spielzug an den Server gesendet, um die Punktzahl zu berechnen.Damit es zu keiner Inkonsistenz kommt, sollte die Aktualisierung des Scores erst nach Abschluss der Animation erfolgen – z. B. über einen setOnFinished()-Callback in der View, der den Controller benachrichtigt.Dieses Zusammenspiel sorgt für klare Verantwortlichkeiten und eine flüssige Nutzererfahrung.
setOnFinished()
In der GameScreen.java befinden sich an mehreren Stellen wiederkehrende Animationen – z. B. für das Verschieben, Hervorheben oder Entfernen von Karten.
GameScreen.java
Was könnte man an der Strukturierung der Animationslogik verbessern? Wie könnte man den Code modularer oder wiederverwendbarer gestalten, um doppelte Animationseffekte zu vermeiden?
👉 Denk z. B. an Methodenstruktur, Wiederverwendbarkeit und Lesbarkeit. Danach bekommst du Feedback.
Wiederverwendbare Methoden für häufige Animationen (z. B. „Karte nach oben verschieben“, „Karte ausblenden“) reduzieren Code-Dopplung ✔️
Durch Parameter oder einfache Bedingungen (if/else) kann man solche Methoden anpassbar machen, ohne den Code zu kopieren ✔️
if/else
Statt Event-Logik direkt in der View zu definieren, sollte diese möglichst in den Controller ausgelagert werden.Die View weist dem Button dann lediglich eine Methode oder einen Handler aus dem Controller zu.So bleibt die View rein für Darstellung und Benutzerinteraktion zuständig, während die Spiel- und Ablaufsteuerung im Controller erfolgt.Dadurch wird die Architektur klarer, modularer und einfacher zu testen.
Für barrierefreies Design ist es wichtig, dass Farben nie das einzige Mittel zur Informationsübermittlung sind.Besonders für farbenblinde Nutzer sollte es zusätzliche Merkmale geben – z. B. Icons, Textbeschriftungen, Muster oder Formunterschiede.Statt z. B. Buttons nur rot oder grün einzufärben, kann man zusätzlich Texte wie „Bereit“ / „Nicht bereit“ anzeigen.Hohe Kontraste zwischen Text und Hintergrund sowie Symbolunterstützung bei Spielkarten helfen ebenfalls, die Oberfläche für alle zugänglich zu machen.Ziel ist, dass alle Spielinformationen auch ohne Farbwahrnehmung verständlich bleiben.
Last changed13 days ago