VB.NET Slot Machine

VB.NET Slot Machine
VB.NET Slot Machine

VB.NET Slot Machine

Lerne in diesem Beitrag, wie Du eine VB.NET Slot Machine erstellen und dessen Hintergrundarbeit (auf .NET bezogen) besser verstehen kannst.

YouTube

Falls Du die VideoVersion besser findest, kannst Du Dir das mittlerweile ältere (aber dennoch genauso funktionierende) Video auf YouTube ansehen, oder eben meinen neuen Beitrag hier verfolgen.

Da das Video mittlerweile knapp 50.000 Aufrufe hat und somit zu den Favoriten in meinem Kanal gehört, habe ich mich dazu entschieden, alles nochmal ein wenig aufzufrischen.

Vorschau – VB.NET Slot Machine

Wer keine Lust hat erst auf YouTube zu gehen um mein Einarmiger Bandit Beispiel zu sehen, hat hier mit dem GIF-Bild schonmal eine kleine Vorschau darauf!

Bitte beachte, dass das Bild aufgrund der Kompression etc. nicht die hundert prozentige Qualität widerspiegelt, ansonsten wäre dieses Vorschaubild knapp 4MB groß gewesen – bäh 🤢.

VB.NET Slot Machine
VB.NET Slot Machine

Gaming-Trip

Zu der Zeit, als ich die Idee mit der Slot Machine bekam, war ich so ein wenig auf dem programmier-technischen Gaming-Trip.

Ich hatte mir tagtäglich neue Ideen für kleine Spiele ausgedacht, Welche ich eventuell mal vor hätte umzusetzen.

Egal ob eine Schiffe Versenken, eine Online-Version von TicTacToe, oder weitere komplexere Sachen.

Auf jeden Fall war mein Ziel, irgendwas Neues zu machen und nicht das einhundertste billig-Spiel zu bauen.

Es sollte irgendetwas Ausgefalleneres werden und daher kam ich dann auf den „Trigger“ namens Casino und zum Schluss auf die Idee eine eigene Slot Machine – also einen eigenen Einarmiger Bandit zu bauen.

Schwierigkeit – Grafik

Es ist natürlich kein Geheimnis, dass die VB.NET Winforms nicht unbedingt ein grafischer Hingucker sind, daher war die erste Herausforderung die mir in den Kopf kam, die grafische Darstellung.

Ich denke allerdings, dass ich mit den Gegebenheiten die ich hatte, einiges mir Mögliche herausholen und ganz gut darstellen konnte.

Besonders toll finde ich zum Beispiel die Animation des Greifarms, bzw. das die Rollen sich in der VB.NET Slot Machine wirklich zu drehen scheinen.

Vereinfachung durch Controls

Viele Leute denken bei Spielen natürlich immer direkt an Sachen wie GDI+, natürlich ist das auch berechtigt, allerdings bin ich ein Fan vom KISS-Prinzip – auch Keep It Smart and Simple genannt.

Noch härtere Brocken wären natürlich solche Dinge wie XNA, allerdings habe ich auch zugegebenermaßen noch nie damit gearbeitet, da ich in nutzungsorientierten, statt Spiele-Apps angesiedelt bin.

Wir machen uns daher nicht das Leben schwer und bekommen wir man meiner Meinung nach sieht ein schönes und durchaus vorzeigbares Beispiel eines „Einarmiger Bandit“ in VB.NET, nur durch Nutzung von vorhandenen Controls hin.

Vorwort

Beachte bitte, dass ich den Code lange Zeit nach der Veröffentlichung des Videos noch einmal überarbeitet habe, deshalb findest Du in dem Beitrag hier 2 verschiedene Downloads.

Der Beitrag selbst verwendet die neuste Version des Codes, da ich den Beitrag zum Zeitpunkt des CodeRefactorings geschrieben habe.

Egal für welchen Code Du Dich nachher entscheidest, beide Testprojekte funktionieren problemlos.

Code erklärt – VB.NET Slot Machine

Konstanten

ROTATION_DELAY

Gibt die Pause in Millisekunden zwischen den einzelnen Rotationsbewegungen an.

DISPLAYED_TILES_PER_WHEEL

Steht für die Anzahl an angezeigten PictureBoxen (Tiles) pro Rad an.

Member

WheelFlags

Der Readonly Member „WheelFlags“ stellt eine Liste von Booleans dar, die den Status der einzelnen Räder repräsentieren: True = dreht, False = dreht nicht.

WheelCache

Dieser Readonly Member stellt eine Art Cache für die einzelnen FlowLayoutPanels – also die Wheels – dar, um darauf einfacher zugreifen zu können.

Vorher haben wir hier drauf immer durch den String-Indexer des Containers zugegriffen, ich denke so ist es schneller.

IsMouseDown

Ein kleines von wenigen Subs benötigte Flag um dementsprechend darauf reagieren zu können.

Eigenschaften

Running

Diese Readonly Property gibt an, ob das Spiel gerade läuft, dabei ist die Eigenschaft natürlich davon abhängig, ob irgendein Rad noch läuft.

Dafür verwenden wir die wunderschöne Any-Funktion aus dem System.Linq-Namespace, Welche es uns ermöglicht, zu bestimmen, ob irgendein Element aus der Auflistung unsere Bedingung erfüllt – also ob irgendein Rad noch läuft!

Konstruktoren

new

Der leere Konstruktor der Form instanziiert und initialisiert 2 Listen, die wir praktisch als Zwischenspeicher nutzen.

Methoden

Form1_Load

In der „Form1_Load“ Eventhandler-Methode laden wir alle Kacheln (Tiles/PictureBoxen) in die Räder.

LoadAllWheelTiles

Diese Methode lädt die Kacheln aller Räder mit Hilfe einer Schleife und einer Sub-Methode.

LoadWheelTiles(nr)

Hier ist oben drüber genannte Hilfsmethode, Welche die Kacheln eines einzelnen Rades anhand der Nummer initial lädt.

CreateWheelTile(nr)

Ist eine Hilfsfunktion, um eine Kachel, also eine PictureBox zu erstellen, Welche in der obigen Methode verwendet wird.

pbArm_MouseDown

Verwaltet den Zustand des obigen Feldes, also ob die Maus, bzw. die linke Maustaste gerade gedrückt wird.

pbArm_MouseUp

Geht Hand in Hand mit der Methode hier drüber und verwaltet den Maus-Zustand.

pbArm_MouseMove

Diese Methode ist für die Animation und das letztendliche Starten einer Spiel-Runde zuständig.

Falls die Anwendung nicht bereits läuft und die Maus, bzw. die linke Maustaste gedrückt ist, wird der Arm der Slot Machine animiert, falls nicht, wird die Methode durch EarlyReturnverlassen.

Falls der Arm weit genug nach unten bewegt wird, startet ein neues Spiel.

AnimateArmAsync(mousePosDifference)

Ist für die Animation des Armes der VB.NET Slot Machine zuständig und verzögert das „Hochpoppennachdem der Arm weit genug unten war.

DelayArmPopupAsync

Verzögert das Hochpoppen des Armes durch die Delay-Funktion der Task-Klasse.

StartRound

Ist für das Starten einer Spiel-Runde zuständig und wrappt zwei weitere Hilfsmethoden.

PlayStartSound

Spielt einen Sound der den Start einer Runde signalisiert im Hintergrund ab.

SpinWheels

Eine Funktion die mit Hilfe einer Schleife alle Räder startet.

SpinWheel(nr)

Startet die Dreh-Animation eines Rades anhand seiner Nummer asynchron.

ReInsertControl(flp)

Simuliert die Animation eines Rades mit Hilfe von dem Entfernen und Hinzufügen von dem ersten Steuerelement des FlowLayoutPanels (des Rades).

LetRotateABit

Wartet einen Moment, damit das Rad Zeit hat die Animation darzustellen.

StopButton_MouseDown

Wenn gerade ein Spiel läuft, wird das Bild des jeweiligen PictureBox-Buttons auf den visuellen „gedrückt„-Status gesetzt.

StopButton_MouseUp

Wenn auf einem PictureBox-Button die linke Maustaste losgelassen wird und das Spiel läuft, wird das Bild des Buttons erstmal wieder auf Standard, also „nicht gedrückt“ gesetzt.

Danach wird die jeweilige Nummer (1-3) des „geklickten“ Buttons ausgemacht und das passende Rad angehalten.

Zuletzt wird geprüft, ob das Spiel beendet ist, also ob alle 3 Räder angehalten wurden.

ResetButtonImage(pb)

Setzt das Bild eines PictureBox-Buttons wieder auf das „nicht gedrückt Bild“ zurück.

GetButtonNrByClickedPictureBox(pb)

Holt die Nummer des Rades, bzw. des Buttons durch den Namen der geklickten PictureBox.

CheckGameEnded

Prüft ob das Spiel geendet hat und bereitet dann die GameEndedEventArgs vor, welche dann für das passende „GameEnded“-Event und der passenden Methode verwendet werden.

GetTileMatrix

Erstellt eine Matrix (eine Liste von Listen), um die aktuell sichtbaren Kacheln zu speichern und später verarbeiten zu können.

GetTileListForWheel(wheelNr)

Sammelt die Kacheln eines jeweiligen Rades in einer Liste und gibt Diese wieder.

OnGameEnded

Eine ganz in .NET-Manier geschriebene Hilfsmethode, um das passende Event auszulösen.

Me_GameEnded

Ein interner Ereignishandler für das hier drüber angesprochene Event, hier könntest Du die Verarbeitung der Daten einbauen, also Punkte verteilen, etc.

pbExit_Click

Eine PictureBox, Welche die Möglichkeit zum Schließen der Anwendung bietet.

Form1_FormClosing

Ereignishandler des „FormClosing“-Events, um die Räder sauber vor dem Schließen der Form anzuhalten.

StopWheels

Eine Methode die weitere Hilfsmethoden verwendet, um alle Räder anzuhalten.

StopWheel(nr)

Hält ein jeweiliges Rad anhand der gegebenen Nummer als Parameter an.

Ereignisse

GameEnded

Wird aufgerufen sobald ein Spiel beendet ist und liefert entsprechende EventArgs, um den Ausgang des Spiels zu verarbeiten.

Refactorings seit Start

Wie oben schon erklärt, ist dieser Beitrag aufgrund der hohen Nachfrage nach der VB.NET Slot Machine entstanden, weshalb ich mich auch dazu entschieden habe, den Code zu überarbeiten.

Hier drunter, findest Du eine detailliertere Liste, was ich getan habe, um diverse Aspekte des Programmes zu verbessern.

Dateien komprimiert

Ich denke einer der wichtigsten Schritte, ohne den Code anfassen zu müssen, war es, die Größe der Dateien zu reduzieren.

Das war durch diverse Online-Tools natürlich relativ einfach aber effizient, denn die einzelnen Ressourcen verbrauchen nun jeweils ca. 60% weniger Speicher.

Methoden intuitiver

Die Methoden im Programm habe ich versucht (wie ich es heute nach den ganzen Jahren sowieso immer gestalte), ganz intuitiv benannt zu gestalten.

Das sieht man vor allem am Beispiel von z. B. folgender Methode, auch wenn Diese letztendlich nur eine Zeile als Inhalt kapselt, beschreibt der Name exakt, was passieren soll.

Auch wenn einige Programmierer nun im Sinne von „das ist Quatsch.“ nölen werden, ich halte mich da ganz an das Buch, bzw. der Art und Weise von meinem Namensvetter Robert C. Martin.

Er sagt sowas wie: „Code muss so smooth wie ein Buch, einfach von der Hand gelesen werden können.“ und ich denke, da halte ich mich dran.

Du findest das Buch „Clean Code: A Handbook of Agile Software Craftsmanship“ von Robert C. Martin auf meiner Startseite, oder hier (Affiliate Link).

Private Sub ResetButtonImage(pb As PictureBox)
    pb.Image = My.Resources.button_normal
End Sub

Alleinstehende Zahlen benannt

Zugegebenermaßen gab es glaube ich noch 1-2 Stellen, wo z. B. eine Integer- (!) Division durchgeführt wurde (<irgendwas> \ 3) und man nicht wusste, was die 3 denn bedeuten soll.

Obwohl ich auch schon vorher einige Konstanten verwendet habe, habe ich unter anderem Diese noch ergänzt, um dessen Zweck verständlicher zu gestalten.

Early Returns

Ich habe mich entschieden, an vielen Stellen die Kombination von „Ands“ und auch die Verschachtelung von „If-Statements“ durch Early Returns – meiner Meinung nach – zu verbessern.

Das verhindert einerseits dieses typische PyramidenKonstrukt:

VB.NET If-Pyramiden Konstrukt
VB.NET If-Pyramiden Konstrukt

und macht den Code im Gegensatz zum obigen Bild durch die lineare Form lesbarer:

VB.NET If-Pyramiden Konstrukt behoben – linearer Verlauf

Wie es endet

Nicht immer können wir bestimmen wie es endet, hier jedoch schon 😉, daher habe ich mich dazu entschieden, dass Ende des Spiels so zu gestalten, dass es Dir offen bleibt, wie Du die Punkte verarbeitest.

Ebenso kannst Du so frei entscheiden, ob Du auch noch die Oberfläche ein wenig „blingbling“ machen lassen möchtest.

Du bekommst daher im „Me_GameEnded„-Ereignishandler die Matrix der aktuellen Bilder die zu sehen sind übergeben und kannst an die Punkte, sowie auch an die PictureBoxen für’s Blinken selbst rankommen.

Downloads

Quellen:
Bild – http://www.designcontest.com/

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.