Titel: MBSimonChallenge v1.02
       Autor: Manfred Becker
      E-Mail: mani.becker@web.de
         Url: http://manib.ma.funpic.de
    Umgebung: Win95/98/NT/2000/XP
 Schlagworte: Basic
       Stufe: Fortgeschrittene
Beschreibung: Eine Emulation des Spiels MB Simon Challenge
     Sektion: BASIC
UnterSektion: VisualBasic

Druck-Version PDF-Datei

Bild von MBSimonChallenge

Einführung

Dieser Artikel beschreibt die Umsetzung des Spiels MB Simon Challenge. Ich habe es programmiert, damit ich beim Spiel gegen meinen Neffen hoffentlich auch einmal gewinne.

Dieses Programm ist die Weiterentwicklung der Version 1.01. Neu dazugekommen sind:

Simon Challenge - Nachmachen erlaubt!

Simon Challenge ist ein elektronisches Spielzeug, das schnelle Reaktionsfähigkeit fordert! Per Sprachchip ruft es Spielkommandos aus, die so rasch wie möglich befolgt werden müssen – und das mit immer steigendem Tempo! Ob allein, zu zweit oder in einer Gruppe sorgt Simon Challenge für dynamischen Spielspaß und ist stets eine Herausforderung!

Wer ist "Simon"?

Aber wer ist eigentlich dieser Simon? Er ist nicht der Erfinder. Simon ist der Namensgeber eines amerikanischen Kinderspieles, dessen kompletter Name "Simon says ..." lautet. Einer in der Gruppe ist "Simon" und ruft den anderen Kommandos zu, etwa "Spring auf" oder "Berühr' Deine Zehen". Diese müssen sofort befolgt werden – aber nur, wenn sie mit der Formel "Simon sagt ..." beginnen. Wer bei einem simplen „Spring“ aufspringt, ist "raus", genauso wie der, der das "Simon sagt ..."-Kommando nicht befolgt. Es gilt also, genau zuzuhören, was da an Befehlen gegeben wird ... Das klingt einigermaßen vertraut – etwas ähnliches gibt es im deutschen Sprachraum als "Alle Vögel fliegen hoch ..." Aber daraus wurde nicht, wie aus "Simon", ein elektronisches Spiel – und zwar schon 1978!

Der Vorläufer

Damals in kam in den USA ein rundes, schwarzes Ding aus Plastik auf den Markt, das man auf den Tisch stellen konnte. Es hatte vier verschiedenfarbige Leuchttasten und stieß Töne aus. Diese vorgegebenen Kombinationen mussten die dann Spieler fehlerfrei nachahmen. Dieses Spiel hieß "Simon" und war das erste elektronische Spiel, das einen sensationellen Erfolg verbuchen konnte und zum Kultobjekt wurde. Das klingt einigermaßen vertraut – im deutschen Sprachraum hieß das Gerät allerdings "Senso", denn einen Simon kannte man hier noch nicht ...

Zugepackt - und los geht's!

Doch das ändert sich jetzt mit Simon Challenge! Denn diese neue Variante fordert vom Spieler mehr als Knöpfe zu drücken – hier ist echte Agilität gefragt. Auf fünf verschiedene Kommandos hin müssen Knöpfe gedrückt, Räder gedreht und Schalter angetippt werden, alles untermalt von Musik. Langzeitspaß bieten hierbei der vielfältig einstellbare Schwierigkeitsgrad und die wechselnde Anzahl an Personen, mit denen man gemeinsam spielen kann: in einer Spielvariante die auf Runden basiert, gibt man das Gerät reihum immer weiter.

Die Kommandos lauten: “Drehen“: Den gelben Knopf drehen - “Tippen“: Den grünen Schalter antippen - “Klopfen“: Auf den großen Knopf in der Mitte klopfen - “Ziehen“: Am blauen Knauf ziehen - “Rollen“: Das orangefarbene Zahnrad rollen.

Hat man richtig reagiert, kommt rasch ein weiterer Befehl hinterher. Die Geschwindigkeit steigt dabei immer weiter, sodass es stets schwieriger wird, zur rechten Zeit das Richtige zu tun. Irrt man sich, gibt es einen Alarmton und das Spiel endet. Um das alles noch eine Stufe schwieriger zu gestalten, kann man auch im Sound-Modus spielen. Dabei werden keine Kommandos erteilt, sondern es wird lediglich ein Geräusch eingespielt, etwa ein Heulton für den Befehl Rollen.

Drei Spielvarianten

- "Solo": Ein Spieler spielt alleine gegen den Highscore

- "Kopf an Kopf": Die einzelnen Kommandos werden jeweils einem von zwei Spielern zugeteilt, sodass jeder Spieler für 2 Anweisungen zuständig ist. Kommt der Befehl zum Klopfen, geht es darum, welcher der beiden Spieler schneller reagiert und den mittleren Knopf betätigt.

- "Weitergeben": In diesem Modus können mehrere Spieler ihre Reaktion unter Beweis stellen. Wer einen Fehler macht, scheidet aus. Beim Kommando „weitergeben“, wird Simon Challenge an den nächsten Spieler weitergegeben. Gespielt wird, bis nur noch ein Spieler übrig bleibt.

Mal laut - mal leise

Alle drei Spielarten die Simon Challenge bietet, können sowohl im Sprach- als auch im Sound-Modus gespielt werden. Simon Challenge besitzt einen Lautstärkeregler und einen Kopfhörerausgang: so kann kann man still für sich spielen oder das Gerät für den großen Partyspaß an die Stereoanlage anschließen. Zum Betrieb sind 3 LR6 Batterien erforderlich.

PC-Emulation mit VisualBasic 6 Programmsource

Bei dieser Emulation werden nun alle drei Spielvarianten emuliert! Allerdings bleibt es euch frei, Verbesserungen oder Erweiterungen daran vorzunehmen. Mit diesem VisualBasic 6 Programmsource sollte das für euch ja kein Problem sein.

Programmierung (Einleitung)

Spielvariante "Solo"

Die Umsetzung für die Spielvariante "Solo" gestaltet sich eigentlich recht einfach. Man benötigt das Hintergrundbild und jeweils einen Bereich für die Aktionsschalter. Dafür kann man jeweils ein Image verwenden, denn ein Image ist unsichtbar, kann aber auf einen Maus-Klick reagieren.

Dann lassen wir uns einen zufälligen Wert für das nächste Kommando ermitteln, und machen die jeweilige Sprachausgabe. Eine eigene Klasse für die WavFile-Anbindung macht die Sprachausgabe sehr einfach. Gleichzeitig starten wir einen Timer, der kontrolliert, ob die Timeout-Zeit schon abgelaufen ist.

Nun muss der Spieler einen der Aktionsschalter anklicken. Dabei prüfen wir, ob der jeweils richtige betätigt wurde. Falls ja, dann kommt das nächste Kommando. Falls nein, dann hat der Spieler verloren.

Verloren ist das Spiel auch dann, wenn es der Spieler nicht schafft innerhalb der Timeoutzeit einen Schalter zu betätigen. Das ist anfangs sehr einfach, wird aber mit der Zeit immer schwieriger, da sich die Timeoutzeit kontinuierlich verkürzt.

Spielvariante "Weitergeben"

Hier spielen beliebig viele Spieler nach den gleichen Regeln wie bei der Spielvariante "Solo". Es gibt aber das zusätzliche Kommando "Weitergeben", welches angibt, dass ein Spielerwechsel vollzogen werden muss.

Macht ein Spieler einen Fehler, dann darf er nicht mehr weiterspielen. Gewonnen hat derjenige Spieler, welcher am Ende als Einziger übrig bleibt.

Spielvariante "Kopf an Kopf"

Da hier zwei Spieler beteiligt sind, die gegeneinander spielen, benötigen wir eine weitere Punkteanzeige. Die Eingaben erfolgen hier über die Tastatur. Die Maus wird bei dieser Spielvariante deaktiviert.

Beim Kommando "Klopfen" kommt es darauf an, welcher Spieler zuerst die jeweilige Taste betätigt. Der Schnellere erhält einen Punkt. Derjenige Spieler, welcher zuerst drei Punkte hat, ist der Gewinner.

Die Infoseite

Es gibt auch noch eine Info-Seite, die dem Spieler die Spielregeln aufzeigt. Diese Spielregeln befinden sich in dem Textfile MBSimonChallenge.txt, welches vor der Anzeige der Form geladen wird.

Die Highscore Seite

Mit dieser Version wurde auch eine Highscore Seite eingebunden. Die Liste der Namen wird dabei dynamisch aufgebaut. Bis zu zehn Einträge werden angezeigt, und in einer Textdatei (CSV-File) gespeichert.

Programmierung (Quelltext)

Modul: frmMain

Zunächst setzen wir alle notwendigen Objekte auf unsere Form:

Bild von MBSimonChallenge
  • CheckBox für Hintergrundmusik ein/ausschalten: chkPlayMidi
  • Label für Überschrift: lblCaption
  • Label für Info-Fenster: lblInfo
  • Image für Hintergrundbild: imgBackground
  • Image für Tippen: imgType
  • Image für Drehen: imgRotate
  • Image für Klopfen: imgKnock
  • Image für Rollen: imgRoll
  • Image für Ziehen: imgPull
  • Label für Punktestand: lblScore1
  • Timer für Countdowm-Timer: TimerCountdown
  • Shape für Umrandung des Laufbalken: shpCountdownBorder
  • Shape für Laufbalken: shpCountdownValue
  • Label für Punktestand Spieler 2: lblScore2
  • Timer für Splash-Timer: TimerSplash
  • Label für Hinweistext: lblHint

Als erstes definieren wir ein paar notwendige Variable:

'///////////////////////////////////////////////////////////////////////////
'//
'// Projekt : MBSimonChallenge
'// Sprache : Basic
'// Compiler: MS Visual Basic 6.0
'// Autor   : Manfred Becker
'// E-Mail  : mani.becker@web.de
'// Url     : http://manib.ma.funpic.de
'// Modul   : frmMain
'// Version : 1.02
'// Datum   : 27.01.2008
'//
'///////////////////////////////////////////////////////////////////////////

Option Explicit

'Einstellung Spielvariante: "Solo", "Kopf an Kopf" oder "Weitergeben"
Private Enum GamePlayMode
    gcSolo = 0
    gcHeadToHead = 1
    gcGiveToNext = 2
End Enum

'Einstellung der Lautstärke: "Leise", "Mittel" oder "Laut"
Private Enum GameVolume
    gcVolSilent = 0
    gcVolMedium = 1
    gcVolLoud = 2
End Enum

'Einstellung Spielmodus: "Sound-Modus" oder "Voice-Modus"
Private Enum GameSoundMode
    gcVoiceMode = 0 'Sprachausgabe
    gcSoundMode = 1 'Soundausgabe
    gcSilentMode = 2 'ohne jegliche Sprach- oder Soundausgabe (nur am PC)
End Enum

'Aufzählungstyp aller Kommandos
Private Enum GameCommands
    gcKnock = 0
    gcRoll = 1
    gcType = 2
    gcRotate = 3
    gcPull = 4
    gcNext = 5
End Enum

'Aufzählungstyp aller Spielzustände
Private Enum GameConditions
    gcInitial = 0
    gcRunning = 1
    gcLost = 2
    gcSetupPlayMode = 3
    gcSetupVolume = 4
    gcSetupSoundMode = 5
End Enum

'Aufzählungstyp aller Spieler
Private Enum Player
    gcNoPlayer = 0
    gcPlayer1 = 1
    gcPlayer2 = 2
End Enum

'Datentyp zur Definition eines Rechtecks
Private Type Rect
    Left As Long
    Top As Long
    Width As Long
    Height As Long
End Type

'Lokale Variable
Private m_WavFile As clsWavFile
Private m_GamePlayMode As GamePlayMode
Private m_GameVolume As GameVolume
Private m_GameSoundMode As GameSoundMode
Private m_GameCondition As GameConditions
Private m_GameCommand As GameCommands
Private m_GameCommandOld As GameCommands
Private m_GameCommandMax As Integer
Private m_GameCommands(6) As String
Private m_GameTimeout As Long
Private m_GameTimeoutMax As Long
Private m_GameTimeoutStart As Long
Private m_GameLevel As Integer
Private m_GameScore1 As Long
Private m_GameScore2 As Long
Private m_GameHighScore As Long
Private m_GameName As String
Private m_GameCopyright As String
'Private m_GameUseSound As Boolean 'Das wird jetzt von der Klasse clsWavFile übernommen
Private m_GameSoundModes(3) As String
Private m_GamePlayModes(3) As String
Private m_GameVolumes(3) As String
Private m_GameVolumeValues(3) As Long
Private m_GameKeyDownPlayer As Player
Private m_GameCounter As Integer
'Lokale Variable für die Koordinaten aller Images
Private m_Background As Rect
Private m_Knock As Rect
Private m_Type As Rect
Private m_Pull As Rect
Private m_Roll As Rect
Private m_Rotate As Rect
Private m_Form As Rect

Nun kümmern wir uns um die Initialisierung der Objekte. Dafür ist die Load-Funktion bestens geeignet, denn sie wird beim Programmstart einmalig aufgerufen. Hier wird auch unser WavFile Objekt erzeugt:

Private Sub Form_Load()

    'Formular zentrieren
    Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2

    'Variable initialisieren
    Randomize Timer
    m_GameName = "MB Simon Challenge v1.02"
    m_GameCopyright = m_GameName & " (c) 26.01.2008 by Manfred Becker"
    m_GamePlayMode = gcSolo
    m_GameCommandMax = 5
    m_GameVolume = gcVolMedium
    m_GameSoundMode = gcVoiceMode
    m_GameCondition = gcInitial

    m_GameCommands(0) = "Klopfen"
    m_GameCommands(1) = "Rollen"
    m_GameCommands(2) = "Tippen"
    m_GameCommands(3) = "Drehen"
    m_GameCommands(4) = "Ziehen"
    m_GameCommands(5) = "Weitergeben"

    m_GameSoundModes(0) = "Voice"
    m_GameSoundModes(1) = "Sound"
    m_GameSoundModes(2) = "Silent"

    m_GamePlayModes(0) = "Solo"
    m_GamePlayModes(1) = "Kopf an Kopf"
    m_GamePlayModes(2) = "Weitergeben"

    m_GameVolumes(0) = "leise"
    m_GameVolumes(1) = "mittel"
    m_GameVolumes(2) = "laut"

    m_GameVolumeValues(0) = &H27EF26B0  'leise
    m_GameVolumeValues(1) = &H80007C00  'mittel
    m_GameVolumeValues(2) = &HFFFFF800  'laut

    m_GameTimeoutMax = 2000
    m_GameHighScore = 0

    'wir sichern uns die original Positionsdaten der Images.
    'Diese werden später bei der Positionsberechnung benötigt.
    m_Background.Left = imgBackground.Left
    m_Background.Top = imgBackground.Top
    m_Background.Width = imgBackground.Width
    m_Background.Height = imgBackground.Height
    m_Knock.Left = imgKnock.Left
    m_Knock.Top = imgKnock.Top
    m_Knock.Width = imgKnock.Width
    m_Knock.Height = imgKnock.Height
    m_Type.Left = imgType.Left
    m_Type.Top = imgType.Top
    m_Type.Width = imgType.Width
    m_Type.Height = imgType.Height
    m_Pull.Left = imgPull.Left
    m_Pull.Top = imgPull.Top
    m_Pull.Width = imgPull.Width
    m_Pull.Height = imgPull.Height
    m_Roll.Left = imgRoll.Left
    m_Roll.Top = imgRoll.Top
    m_Roll.Width = imgRoll.Width
    m_Roll.Height = imgRoll.Height
    m_Rotate.Left = imgRotate.Left
    m_Rotate.Top = imgRotate.Top
    m_Rotate.Width = imgRotate.Width
    m_Rotate.Height = imgRotate.Height

    'Ein paar ToolTip-Hinweise können nie schaden
    imgKnock.ToolTipText = "Klopfen! (Spielstart)"
    imgPull.ToolTipText = "Ziehen! (Spielvariante einstellen)"
    imgRoll.ToolTipText = "Rollen! (Lautstärke einstellen)"
    imgRotate.ToolTipText = "Drehen! (Highscore anzeigen)"
    imgType.ToolTipText = "Tippen! (Spielmodus einstellen)"

    'WavFile Objekt erzeugen
    'Das Objekt erkennt nun automatisch, ob eine Soundkarte installiert ist
    Set m_WavFile = New clsWavFile
    'testen, ob Soundkarte installiert ist
    'm_GameUseSound = m_WavFile.TestSoundkarte

    'Lautstärke einstellen
    Call m_WavFile.SetWaveVolume(m_GameVolumeValues(m_GameVolume))
    Call m_WavFile.SetMidiVolume(m_GameVolumeValues(m_GameVolume))

    'Copyright-Meldung ausgeben
    Me.Caption = m_GameCopyright
    Me.KeyPreview = True

    'Spiel initialisieren
    Call GameLost("")
End Sub

Funktion für Programmende. Hier muss unser WavFile Objekt wieder gelöscht werden:

Private Sub Form_Unload(Cancel As Integer)
    'Sprachausgabe bei Programmende
    If m_GameSoundMode <> gcSilentMode Then
        Call m_WavFile.SndPlaySound("MBSimonChallenge.Aus.wav", SND_SYNC)
    End If

    'WavFile Objekt löschen
    Set m_WavFile = Nothing
End Sub

Funktion für Anpassung bei Grössenänderung:

Private Sub Form_Resize()
    Dim BorderTop As Long, BorderWidth As Long
    Dim fx As Single, fy As Single

    If Me.WindowState = vbMinimized Then Exit Sub

    'Prüfe die Mindest-Breite
    If Me.Width < 4000 Then Me.Width = 4000

    'Prüfe die Mindest-Höhe
    If Me.Height < 4000 Then Me.Height = 4000

    'Prüfe, ob sich die Größe verändert hat
    If m_Form.Width = Me.Width And m_Form.Height = Me.Height Then Exit Sub

    'Neue Größe sichern
    m_Form.Width = Me.Width
    m_Form.Height = Me.Height

    'Hintergrund-Image ausblenden
    imgBackground.Visible = False

    'Positioniere alle Labels und Images
    lblCaption.Width = Me.Width - 420

    imgBackground.Width = Me.Width - 420
    imgBackground.Height = Me.Height - 2000

    BorderTop = imgBackground.Top + imgBackground.Height + 120
    BorderWidth = imgBackground.Width - 2400

    lblScore1.Top = BorderTop + 60
    lblScore2.Top = BorderTop + 60

    shpCountdownBorder.Top = BorderTop
    shpCountdownBorder.Width = BorderWidth
    shpCountdownValue.Top = BorderTop + 60
    shpCountdownValue.Width = BorderWidth - 120

    lblScore2.Left = imgBackground.Left + imgBackground.Width - lblScore2.Width

    lblHint.Width = Me.Width - 480
    lblHint.Top = BorderTop + shpCountdownBorder.Height + 120

    lblInfo.Left = imgBackground.Left + imgBackground.Width - lblInfo.Width


    'X- und Y-Faktor zur Positionsberechnung der Images
    fx = imgBackground.Width / m_Background.Width
    fy = imgBackground.Height / m_Background.Height

    'Positionsberechnung der Images
    imgKnock.Left = imgBackground.Left + (m_Knock.Left - m_Background.Left) * fx
    imgKnock.Top = imgBackground.Top + (m_Knock.Top - m_Background.Top) * fy
    imgKnock.Width = m_Knock.Width * fx
    imgKnock.Height = m_Knock.Height * fy

    imgType.Left = imgBackground.Left + (m_Type.Left - m_Background.Left) * fx
    imgType.Top = imgBackground.Top + (m_Type.Top - m_Background.Top) * fy
    imgType.Width = m_Type.Width * fx
    imgType.Height = m_Type.Height * fy

    imgPull.Left = imgBackground.Left + (m_Pull.Left - m_Background.Left) * fx
    imgPull.Top = imgBackground.Top + (m_Pull.Top - m_Background.Top) * fy
    imgPull.Width = m_Pull.Width * fx
    imgPull.Height = m_Pull.Height * fy

    imgRoll.Left = imgBackground.Left + (m_Roll.Left - m_Background.Left) * fx
    imgRoll.Top = imgBackground.Top + (m_Roll.Top - m_Background.Top) * fy
    imgRoll.Width = m_Roll.Width * fx
    imgRoll.Height = m_Roll.Height * fy

    imgRotate.Left = imgBackground.Left + (m_Rotate.Left - m_Background.Left) * fx
    imgRotate.Top = imgBackground.Top + (m_Rotate.Top - m_Background.Top) * fy
    imgRotate.Width = m_Rotate.Width * fx
    imgRotate.Height = m_Rotate.Height * fy

    'Hintergrund-Image einblenden
    imgBackground.Visible = True
End Sub

Funktion zum Starten des Spiels:

Private Sub GameStart()
    'Midifile als Hintergrunfmusik abspielen
    If chkPlayMidi.Value = vbChecked Then
        Call m_WavFile.PlayMidi("MBSimonChallenge.Midifile.2.mid")
    End If

    lblHint.Caption = "Spiel """ & m_GamePlayModes(m_GamePlayMode) & """ wurde gestartet..."
    m_GameCondition = gcRunning
    m_GameCounter = -1 'wir beginnen bei -1, weil durch GameNextCommand der Wert hochgezählt wird
    m_GameScore1 = -1 'wir beginnen bei -1, weil durch GameNextCommand der Wert hochgezählt wird
    m_GameScore2 = -1 'wir beginnen bei -1, weil durch GameNextCommand der Wert hochgezählt wird
    m_GameLevel = -1 'wir beginnen bei -1, weil durch GameNextCommand der Wert hochgezählt wird
    m_GameKeyDownPlayer = gcNoPlayer
    Call GameNextCommand 'nächstes Kommando ausgeben
    TimerCountdown.Enabled = True 'Countdown-Timer starten
End Sub

Funktion für Spielende:

Private Sub GameLost(Reason As String, Optional Loser As Player)
    'Sprachausgabe für Spielende
    If m_GameSoundMode <> gcSilentMode And Reason <> "" Then
        Call m_WavFile.SndPlaySound("MBSimonChallenge.Waah.wav", SND_SYNC)
    End If

    TimerCountdown.Enabled = False 'Countdown-Timer stoppen
    m_GameCondition = gcLost

    'Um welche Spielvariante handelt es sich?
    If m_GamePlayMode = gcHeadToHead Then
        'Spielvariante "Kopf an Kopf", Hinweis und Punktestand ausgeben
        Select Case Loser
            Case gcPlayer1
                'Spieler 1 hat einen Fehler gemacht!
                lblHint.Caption = "Spieler 2 hat gewonnen!"
            Case gcPlayer2
                'Spieler 2 hat einen Fehler gemacht!
                lblHint.Caption = "Spieler 1 hat gewonnen!"
            Case Else
                'Timeout
                If m_GameCommand = gcType Or m_GameCommand = gcRoll Then
                    'Spieler 1 hat sein Kommando nicht befolgt
                    lblHint.Caption = "Spieler 2 hat gewonnen!"
                ElseIf m_GameCommand = gcPull Or m_GameCommand = gcRotate Then
                    'Spieler 2 hat sein Kommando nicht befolgt
                    lblHint.Caption = "Spieler 1 hat gewonnen!"
                Else
                    'Keider der beiden Spieler hat geklopft
                    If m_GameScore1 > m_GameScore2 Then
                        lblHint.Caption = "Spieler 1 hat gewonnen!"
                    ElseIf m_GameScore1 < m_GameScore2 Then
                        lblHint.Caption = "Spieler 2 hat gewonnen!"
                    Else
                        lblHint.Caption = "Unentschieden!"
                    End If
                End If
        End Select
        lblHint.Caption = lblHint.Caption & " " & _
        "Das Komando war " & m_GameCommands(m_GameCommand) & "! " & _
        Reason & " " & _
        "Der Punktestand = " & Str(m_GameScore1) & " :" & Str(m_GameScore2)
    Else
        'Spielvariante: "Solo" und "Weitergeben", Hinweis und Punktestand ausgeben
        lblHint.Caption = "Spiel ist beendet! " & _
        "Das Komando war " & m_GameCommands(m_GameCommand) & "! " & _
        Reason & " " & _
        "Der Punktestand = " & Str(m_GameScore1)

        If m_GameScore1 > 0 Then
            'falls Highscore erreicht, dann Highscore-Wert sichern und ausgeben
            If m_GameHighScore < m_GameScore1 Then
                m_GameHighScore = m_GameScore1
                lblHint.Caption = lblHint.Caption & _
                " (Highscore!)"
            End If

            Call GameSetHighScore(m_GameScore1)
        End If
    End If

    'Hinweis für Programmstart
    lblCaption.Caption = "Zum Start: Klopfen!"

    'Midifile als Hintergrunfmusik abspielen
    If chkPlayMidi.Value = vbChecked Then
        Call m_WavFile.PlayMidi("MBSimonChallenge.Midifile.1.mid")
    End If
End Sub

Funktion zum Setzen des nächsten Kommandos:

Private Sub GameNextCommand()
    m_GameCommandOld = m_GameCommand

    If m_GameCommand <> gcNext Then

        'Zählerstand erhöhen
        m_GameCounter = m_GameCounter + 1

        'jedes mal, wenn 16 Punkte dazugekommen sind, wird das Level erhöht,
        'und damit die Timeout-Zeit verkürzt!
        If m_GameCounter Mod 16 = 0 Then
            m_GameLevel = m_GameLevel + 1
            m_GameTimeoutStart = m_GameTimeoutMax - m_GameLevel * (m_GameTimeoutMax / 10)
        End If

        'Um welche Spielvariante handelt es sich?
        If m_GamePlayMode = gcHeadToHead Then
            'Spielvariante "Kopf an Kopf"
            If m_GameKeyDownPlayer = gcNoPlayer Then
                'Spielstart, Punkte zurücksetzen
                m_GameScore1 = 0
                m_GameScore2 = 0
                lblScore1.Caption = m_GameScore1
                lblScore2.Caption = m_GameScore2
            Else
                'den Punk macht derjenige Spieler, welcher zuerst geklopft hat.
                'Hat ein Spieler 5 Punkte gesammelt, ist er der Gewinner.
                If m_GameCommand = gcKnock Then
                    'Punkte erhöhen und anzeigen
                    If m_GameKeyDownPlayer = gcPlayer1 Then
                        m_GameScore1 = m_GameScore1 + 1
                        lblScore1.Caption = m_GameScore1
                        If m_GameScore1 = 5 Then
                            Call GameWinner(gcPlayer1)
                            Exit Sub
                        End If
                    ElseIf m_GameKeyDownPlayer = gcPlayer2 Then
                        m_GameScore2 = m_GameScore2 + 1
                        lblScore2.Caption = m_GameScore2
                        If m_GameScore1 = 5 Then
                            Call GameWinner(gcPlayer2)
                            Exit Sub
                        End If
                    End If
                End If
            End If
        Else
            'Spielvariante "Solo" oder "Weitergeben"
            'Punkte erhöhen und anzeigen
            m_GameScore1 = m_GameCounter
            lblScore1.Caption = m_GameScore1
        End If
    End If

    'Spieler zurücksetzen
    m_GameKeyDownPlayer = gcNoPlayer

    'Timeoutzeit zurückstellen
    m_GameTimeout = m_GameTimeoutStart

    'Für die Ermittlung des nächsten Kommandos, benötigen wir einen Zufallswert
    'von 0 bis 4 bzw. 0 bis 5 (je nach Spielvariante)
    Do
        m_GameCommand = Int(Rnd * m_GameCommandMax)
        'Wir verhindern, daßs das Kommando gcNext zweimal direkt hintereinander kommt!
    Loop While (m_GameCommandOld = gcNext And m_GameCommand = gcNext)

    'nächstes Kommando anzeigen
    lblCaption.Caption = m_GameCommands(m_GameCommand) & "!"

    'Sprachausgabe des Kommandos
    If m_GameSoundMode <> gcSilentMode Then
        Call m_WavFile.Play("MBSimonChallenge." & m_GameCommands(m_GameCommand) & "." & m_GameSoundModes(m_GameSoundMode) & ".wav")
    End If
End Sub

Funktion für Spielende bei Spielvariante "Kopf an Kopf":

Private Sub GameWinner(winner As Player)
    Dim strHint As String
    If winner = gcPlayer1 Then
        strHint = "Spieler 1 hat gewonnen!"
    Else
        strHint = "Spieler 2 hat gewonnen!"
    End If

    'Sprachausgabe für Spielende
    If m_GameSoundMode <> gcSilentMode Then
        Call m_WavFile.Play("MBSimonChallenge.HighScore.wav")
    End If

    TimerCountdown.Enabled = False 'Countdown-Timer stoppen
    m_GameCondition = gcLost

    'Hinweis und Punktestand ausgeben
    lblHint.Caption = strHint & " " & _
    "Der Punktestand = " & Str(m_GameScore1) & " :" & Str(m_GameScore2)

    'Hinweis für Programmstart
    lblCaption.Caption = "Zum Start: Klopfen!"
End Sub

Funktion zum Anzeigen der HighScore:

Private Sub GameShowHighScore()
    Dim bFileExist As Boolean
    bFileExist = frmHighScore.SetHighScoreFilename("MBSimonChallenge.HighScore.csv", m_GameName & " - HighScore")
    If bFileExist Then
        frmHighScore.TimerAutoUnload.Enabled = True
        Call frmHighScore.Show(vbModal)
    End If
    m_GameHighScore = frmHighScore.GetHighScore
End Sub

Funktion zum Setzen einer neuen HighScore:

Private Sub GameSetHighScore(Score As Long)
    'die Funktion CheckHighScore() gibt zurück, ob ein neuer HighScore erreicht wurde
    If frmHighScore.CheckHighScore(Score) Then
        'Sprachausgabe für neuen Highscore
        If m_GameSoundMode <> gcSilentMode Then
            Call m_WavFile.Play("MBSimonChallenge.HighScore.wav")
        End If
        Call frmHighScore.SetHighScoreFilename("MBSimonChallenge.HighScore.csv", m_GameName & " - HighScore")
        Call frmHighScore.SetHighScore(Score)
        Call frmHighScore.Show(vbModal)
        'eigene HighScore aktualisieren
        m_GameHighScore = frmHighScore.GetHighScore
    End If
End Sub

Funktion zum Starten und Stoppen der Hintergrundmusik (Midi-File)

Private Sub chkPlayMidi_Click()
    If chkPlayMidi.Value = vbChecked Then
        If m_GameCondition <> gcRunning Then
            Call m_WavFile.PlayMidi("MBSimonChallenge.Midifile.1.mid")
        Else
            Call m_WavFile.PlayMidi("MBSimonChallenge.Midifile.2.mid")
        End If
    Else
        Call m_WavFile.StopMidi
    End If
End Sub

Funktion für Tastaturabfrage

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    Select Case KeyCode
        'Escape
        Case vbKeyEscape 'Spielabbruch
            Unload Me

        'Tasten für Spieler 1
        Case Asc("q"), Asc("Q") 'Tippen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer1
            Call imgType_Click
        Case Asc("y"), Asc("Y") 'Rollen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer1
            Call imgRoll_Click
        Case Asc("a"), Asc("A") 'Klopfen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer1
            Call imgKnock_Click

        'Tasten für Spieler 2
        Case Asc("o"), Asc("O") 'Drehen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer2
            Call imgRotate_Click
        Case Asc("k"), Asc("K") 'Klopfen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer2
            Call imgKnock_Click
        Case Asc("m"), Asc("M") 'Ziehen
            If m_GameKeyDownPlayer = gcNoPlayer Then m_GameKeyDownPlayer = gcPlayer2
            Call imgPull_Click
    End Select
End Sub

Funktion für Fehleingabe

Private Sub imgBackground_Click()
    'Sprachausgabe bei Fehleingabe
    If m_GameSoundMode <> gcSilentMode Then
        Call m_WavFile.Play("MBSimonChallenge.Duerfen.wav")
    End If
End Sub

Funktion zum Aufruf der Info-Maske:

Private Sub lblInfo_Click()
    'Sprachausgabe für Info-Maske
    If m_GameSoundMode <> gcSilentMode Then
        Call m_WavFile.Play("MBSimonChallenge.TunSoll.wav")
    End If

    Call frmInfo.OpenFile("MBSimonChallenge.txt", m_GameName & " - Info")
    Call frmInfo.Show(vbModal)
End Sub

Funktion Klopfen:

Private Sub imgKnock_Click()
    If m_GameCondition = gcRunning Then
        Select Case m_GamePlayMode
            Case gcSolo 'Spielvariante "Solo"
                If m_GameCommand = gcKnock Then
                    Call GameNextCommand
                Else
                    Call GameLost("Sie haben geklopft!")
                End If
            Case gcHeadToHead 'Spielvariante "Kopf an Kopf"
                If m_GameKeyDownPlayer <> gcNoPlayer Then
                    If m_GameCommand = gcKnock Then
                        Call GameNextCommand
                    Else
                        If m_GameCommandOld <> gcKnock Then
                            Call GameLost("Sie haben geklopft!", m_GameKeyDownPlayer)
                        End If
                    End If
                End If
            Case gcGiveToNext 'Spielvariante "Weitergeben"
                If m_GameCommand <> gcNext Then
                    If m_GameCommand = gcKnock Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben geklopft!")
                    End If
                End If
        End Select
    Else
        'Bei Spielvariante "Kopf an Kopf" müßsen Tasten verwendet werden
        If m_GamePlayMode = gcHeadToHead Then
            'Hinweis zur Tastenbelegung ausgeben
            Dim strPrompt As String
            strPrompt = strPrompt & "Spieler 1" & vbTab & vbTab & "Spieler 2" & vbCrLf
            strPrompt = strPrompt & "[Q]=Tippen" & vbTab & "[O]=Drehen" & vbCrLf
            strPrompt = strPrompt & "[A]=Klopfen" & vbTab & "[K]=Klopfen" & vbCrLf
            strPrompt = strPrompt & "[Y]=Rollen" & vbTab & "[M]=Ziehen" & vbCrLf & vbCrLf
            strPrompt = strPrompt & "Die Maus kann hierbei nicht verwendet werden!"
            Call MsgBox(strPrompt, vbInformation, "Tastenbelegung")
        End If
        Call GameStart
    End If
End Sub

Funktion Ziehen:

Private Sub imgPull_Click()
    If m_GameCondition = gcRunning Then
        Select Case m_GamePlayMode
            Case gcSolo 'Spielvariante "Solo"
                If m_GameCommand = gcPull Then
                    Call GameNextCommand
                Else
                    Call GameLost("Sie haben gezogen!")
                End If
            Case gcHeadToHead 'Spielvariante "Kopf an Kopf"
                If m_GameKeyDownPlayer <> gcNoPlayer Then
                    If m_GameCommand = gcPull Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gezogen!", m_GameKeyDownPlayer)
                    End If
                End If
            Case gcGiveToNext 'Spielvariante "Weitergeben"
                If m_GameCommand <> gcNext Then
                    If m_GameCommand = gcPull Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gezogen!")
                    End If
                End If
        End Select
    Else
        If m_GameCondition <> gcSetupPlayMode Then
            'In den Setup-Modus umschalten
            m_GameCondition = gcSetupPlayMode
        Else
            'Einstellung Spielvariante: "Solo", "Kopf an Kopf" oder "Weitergeben"
            m_GamePlayMode = m_GamePlayMode + 1
            If m_GamePlayMode > gcGiveToNext Then m_GamePlayMode = gcSolo

            'Anzahl Spiele-Kommandos
            If m_GamePlayMode = gcGiveToNext Then
                m_GameCommandMax = 6
            Else
                m_GameCommandMax = 5
            End If

            'Punkteanzeige
            If m_GamePlayMode = gcHeadToHead Then
                lblScore2.Visible = True
            Else
                lblScore2.Visible = False
            End If
        End If

        'Spachausgabe
        If m_GameSoundMode <> gcSilentMode Then
            Select Case m_GamePlayMode
                Case GamePlayMode.gcSolo
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielvariante.Solo.wav")
                Case GamePlayMode.gcGiveToNext
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielvariante.Weitergeben.wav")
                Case GamePlayMode.gcHeadToHead
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielvariante.KopfAnKopf.wav")
            End Select
        End If

        'Anzeige des Spielvariante
        lblHint.Caption = "Spielvariante = " & m_GamePlayModes(m_GamePlayMode)
    End If
End Sub

Funktion Rollen:

Private Sub imgRoll_Click()
    If m_GameCondition = gcRunning Then
        Select Case m_GamePlayMode
            Case gcSolo 'Spielvariante "Solo"
                If m_GameCommand = gcRoll Then
                    Call GameNextCommand
                Else
                    Call GameLost("Sie haben gerollt!")
                End If
            Case gcHeadToHead 'Spielvariante "Kopf an Kopf"
                If m_GameKeyDownPlayer <> gcNoPlayer Then
                    If m_GameCommand = gcRoll Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gerollt!", m_GameKeyDownPlayer)
                    End If
                End If
            Case gcGiveToNext 'Spielvariante "Weitergeben"
                If m_GameCommand <> gcNext Then
                    If m_GameCommand = gcRoll Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gerollt!")
                    End If
                End If
        End Select
    Else
        If m_GameCondition <> gcSetupVolume Then
            'In den Setup-Modus umschalten
            m_GameCondition = gcSetupVolume
        Else
            'Einstellung der Lautstärke: "Leise", "Mittel" oder "Laut"
            m_GameVolume = m_GameVolume + 1
            If m_GameVolume > gcVolLoud Then m_GameVolume = gcVolSilent
            m_WavFile.SetWaveVolume (m_GameVolumeValues(m_GameVolume))
            m_WavFile.SetMidiVolume (m_GameVolumeValues(m_GameVolume))
        End If

        'Spachausgabe
        If m_GameSoundMode <> gcSilentMode Then
            Select Case m_GameVolume
                Case GameVolume.gcVolLoud
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Lautstaerke.Laut.wav")
                Case GameVolume.gcVolMedium
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Lautstaerke.Mittel.wav")
                Case GameVolume.gcVolSilent
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Lautstaerke.Leise.wav")
            End Select
        End If

        'Anzeige des Lautstärke
        lblHint.Caption = "Lautstärke = " & m_GameVolumes(m_GameVolume)
    End If
End Sub

Funktion Drehen:

Private Sub imgRotate_Click()
    If m_GameCondition = gcRunning Then
        Select Case m_GamePlayMode
            Case gcSolo 'Spielvariante "Solo"
                If m_GameCommand = gcRotate Then
                    Call GameNextCommand
                Else
                    Call GameLost("Sie haben gedreht!")
                End If
            Case gcHeadToHead 'Spielvariante "Kopf an Kopf"
                If m_GameKeyDownPlayer <> gcNoPlayer Then
                    If m_GameCommand = gcRotate Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gedreht!", m_GameKeyDownPlayer)
                    End If
                End If
            Case gcGiveToNext 'Spielvariante "Weitergeben"
                If m_GameCommand <> gcNext Then
                    If m_GameCommand = gcRotate Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben gedreht!")
                    End If
                End If
        End Select
    Else
        'Spachausgabe
        If m_GameSoundMode <> gcSilentMode Then
            Call m_WavFile.Play("MBSimonChallenge.Einstellung.Highscore.wav")
        End If

        'Anzeige der Highscore
        Call GameShowHighScore

        lblHint.Caption = "Highscore = " & Str(m_GameHighScore)
    End If
End Sub

Funktion Tippen:

Private Sub imgType_Click()
    If m_GameCondition = gcRunning Then
        Select Case m_GamePlayMode
            Case gcSolo 'Spielvariante "Solo"
                If m_GameCommand = gcType Then
                    Call GameNextCommand
                Else
                    Call GameLost("Sie haben getippt!")
                End If
            Case gcHeadToHead 'Spielvariante "Kopf an Kopf"
                If m_GameKeyDownPlayer <> gcNoPlayer Then
                    If m_GameCommand = gcType Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben getippt!", m_GameKeyDownPlayer)
                    End If
                End If
            Case gcGiveToNext 'Spielvariante "Weitergeben"
                If m_GameCommand <> gcNext Then
                    If m_GameCommand = gcType Then
                        Call GameNextCommand
                    Else
                        Call GameLost("Sie haben getippt!")
                    End If
                End If
        End Select
    Else
        If m_GameCondition <> gcSetupSoundMode Then
            'In den Setup-Modus umschalten
            m_GameCondition = gcSetupSoundMode
        Else
            'Einstellung Spielmodus: "Sound-Modus" oder "Voice-Modus"
            m_GameSoundMode = m_GameSoundMode + 1
            If m_GameSoundMode > gcSilentMode Then m_GameSoundMode = gcVoiceMode
        End If

        'Spachausgabe
        'If m_GameSoundMode <> gcSilentMode Then
            Select Case m_GameSoundMode
                Case GameSoundMode.gcSoundMode
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielmodus.Sound.wav")
                Case GameSoundMode.gcVoiceMode
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielmodus.Voice.wav")
                Case GameSoundMode.gcSilentMode
                    Call m_WavFile.Play("MBSimonChallenge.Einstellung.Spielmodus.Silent.wav")
            End Select
        'End If

        'Anzeige des Spielemodus
        lblHint.Caption = "Spielmodus = " & m_GameSoundModes(m_GameSoundMode)
    End If
End Sub

Funktion für Countdown-Timer:

Private Sub TimerCountdown_Timer()
    m_GameTimeout = m_GameTimeout - TimerCountdown.Interval
    If m_GameTimeout > 0 Then
        'Scroll-Bar aktualisieren
        shpCountdownValue.Width = (shpCountdownBorder.Width - 120) / m_GameTimeoutStart * m_GameTimeout
    Else
        'Scroll-Bar auf 0 setzen
        shpCountdownValue.Width = 0

        If m_GamePlayMode = gcGiveToNext And m_GameCommand = gcNext Then
            'Spielvariante "Weitergeben" und Kommando "gcNext" ermittelt das nächste Kommando
            Call GameNextCommand
        Else
            Call GameLost("Die Zeit ist abgelaufen!", gcNoPlayer)
        End If
    End If
End Sub

Funktion für Splash-Timer. Hierbei wird beim Programmstart die HighScore-Seite angezeigt. Dadurch ermitteln wir ganz nebenbei den abgespeicherten HighScore-Wert.

Private Sub TimerSplash_Timer()
    TimerSplash.Enabled = False
    Call GameShowHighScore
End Sub

Modul: frmInfo

Zunächst setzen wir alle notwendigen Objekte auf unsere Form:

Bild von MBSimonChallenge
  • TextBox für die Darstellung des Info-Textes: txtInfo

Als erstes definieren wir ein paar notwendige Variable:

'///////////////////////////////////////////////////////////////////////////
'//
'// Projekt : MBSimonChallenge
'// Sprache : Basic
'// Compiler: MS Visual Basic 6.0
'// Autor   : Manfred Becker
'// E-Mail  : mani.becker@web.de
'// Url     : http://manib.ma.funpic.de
'// Modul   : frmInfo
'// Version : 1.02
'// Datum   : 27.01.2008
'//
'///////////////////////////////////////////////////////////////////////////

Option Explicit

Funktion für Initialisierung der Variable:

Private Sub Form_Load()
    'Formular zentrieren
    Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2

    Me.txtInfo.Text = "Please use OpenFile() to show any text from a textfile."
End Sub

Funktion für Grössenänderung der Form:

Private Sub Form_Resize()
    If Me.WindowState = vbMinimized Then Exit Sub
    txtInfo.Left = 0
    txtInfo.Top = 0
    txtInfo.Width = Me.Width - 120
    txtInfo.Height = Me.Height - 400
End Sub

Funktion zum Öffnen einer beliebigen Textdatei:

Public Sub OpenFile(PathAndFilename As String, Optional Title As Variant)
On Error GoTo ErrorHandler
    Dim strFileContent As String
    Dim bFileIsOpen As Boolean
    Dim nLen As Long
    Dim FileNr As Long

    'Variable initialisieren
    bFileIsOpen = False

    'Wir ermitteln die Dateilänge in Bytes
    nLen = FileLen(PathAndFilename)

FileInput:
    'nächste verfügbare Dateinummer
    FileNr = FreeFile

    'Öffnen der gewählten Datei
    Open PathAndFilename For Input As #FileNr

    'Das Öffnen hat funktioniert
    bFileIsOpen = True

    'Ändern des Mauszeigers in eine Sanduhr
    Screen.MousePointer = vbHourglass

    'Laden des Dateiinhalts
    strFileContent = Input(nLen, FileNr)

    'Das Laden hat funktioniert!
    txtInfo.Text = strFileContent

    'Wurde eine Überschrift übergeben?
    If Not IsMissing(Title) Then
        Me.Caption = Title
    End If

ExitSub:
    'Schliessen der Datei
    If bFileIsOpen Then Close #FileNr

    'Zurücksetzen des Mauszeigers
    Screen.MousePointer = vbDefault
    Exit Sub

ErrorHandler:
    Dim ErrNumber As Integer
    Dim ErrDescription As String

    ErrNumber = Err.Number
    ErrDescription = Err.Description
    Select Case ErrNumber
        Case 53
            MsgBox "Datei kann nicht geöffnet werden: " + PathAndFilename
        Case 62
            If bFileIsOpen Then Close #FileNr
            bFileIsOpen = False
            nLen = nLen - 1
            Resume FileInput
        Case Else
            MsgBox "Fehler:" & Str(ErrNumber) & vbCrLf & vbCrLf & ErrDescription
    End Select
    Resume ExitSub
End Sub

Funktion für Tasteneingaben:

Private Sub Form_KeyPress(KeyAscii As Integer)
    Select Case KeyAscii
        Case vbKeyEscape
            Unload Me
    End Select
End Sub

Modul: frmHighScore

Zunächst setzen wir alle notwendigen Objekte auf unsere Form:

Bild von MBSimonChallenge
  • Label: lblId
  • Label: lblName
  • Label: lblScore
  • Label: lblDate
  • Label: lblTime
  • TextBox: txtId
  • TextBox: txtName
  • TextBox: txtScore
  • TextBox: txtDate
  • TextBox: txtTime
  • Timer: TimerAutoUnload

Als erstes definieren wir ein paar notwendige Variable:

'///////////////////////////////////////////////////////////////////////////
'//
'// Projekt : MBSimonChallenge
'// Sprache : Basic
'// Compiler: MS Visual Basic 6.0
'// Autor   : Manfred Becker
'// E-Mail  : mani.becker@web.de
'// Url     : http://manib.ma.funpic.de
'// Modul   : frmHighScore
'// Version : 1.02
'// Datum   : 27.01.2008
'//
'///////////////////////////////////////////////////////////////////////////

Option Explicit

'Datentyp für HighScore-Eintrag
Private Type HighScoreEntry
    Id As String * 5
    Name As String * 20
    Score As String * 6
    Date As String * 10
    Time As String * 8
End Type

'Mit dieser Konstanten wird festgelegt,
'wie viele Einträge in der Liste angezeigt werden
Private Const INDEX_MAX As Integer = 10

'Lokale Variable
Private m_HighScoreFilename As String
Private m_HighScoreLines As Integer
Private m_HighScoreMin As Long
Private m_HighScoreMax As Long
Private m_HighScoreNew As Long
Private m_HighScoreChanged As Boolean
Private m_HighScoreTitle As String

Funktion zum Setzen des HighScore-Dateinamens. Optional kann eine Überschrift mitgegeben werden:

Public Function SetHighScoreFilename(PathAndFilename As String, Optional Title As Variant) As Boolean
    m_HighScoreFilename = PathAndFilename
    If Not IsMissing(Title) Then
        m_HighScoreTitle = Title
    Else
        m_HighScoreTitle = ""
    End If
    SetHighScoreFilename = FileExist(PathAndFilename)
End Function

Funktion zur Ermittlung des aktuellen HighScore Punktestand:

Public Function GetHighScore() As Long
    GetHighScore = m_HighScoreMax
End Function

Funktion zum Setzen der HighScore:

Public Sub SetHighScore(Score As Long)
    Dim bRet As Boolean

    If Score > m_HighScoreMin Then
        m_HighScoreNew = Score
    Else
        m_HighScoreNew = 0
    End If
End Sub

Funktion die prüft, ob der angegebene Punktestand in die HighScore-Liste aufgenommen würde:

Public Function CheckHighScore(Score As Long) As Boolean
    Dim bRet As Boolean

    If Score > m_HighScoreMin Then
        bRet = True
    Else
        bRet = False
    End If

    CheckHighScore = bRet
End Function

Funktion die prüft, od die angegebene Datei existiert:

Private Function FileExist(FileName) As Boolean
On Error GoTo ErrorHandler
    FileExist = Dir$(FileName) <> ""
    Exit Function
ErrorHandler:
    FileExist = False
    Resume Next
End Function

Diese Funktion ermittelt aus einer Textzeile die HighScore-Einträge:

Private Function GetEntryFromTextline(Textline As String, ByRef Entry As HighScoreEntry) As String
    Dim sRet As String
    Dim nStart As Integer
    Dim nEnd As Integer
    Dim sValue As String
    Dim Index As Integer

    nEnd = 0
    For Index = 0 To 4
        nStart = nEnd + 1
        nEnd = InStr(nStart, Textline, ";", vbTextCompare)
        If nEnd = 0 Then nEnd = Len(Textline) + 1

        If nStart <= nEnd Then
            sValue = Trim(Mid(Textline, nStart, nEnd - nStart))
            Select Case Index
                Case 0: Entry.Id = sValue
                Case 1: Entry.Name = sValue
                Case 2: Entry.Score = sValue
                Case 3: Entry.Date = sValue
                Case 4: Entry.Time = sValue
            End Select
        Else
            sRet = "Spaltenwert" & Str(Index) & " fehlt!"
            Exit For
        End If
    Next Index

    GetEntryFromTextline = sRet
End Function

Funktion zum Lesen der HighScore-Datei. Dabei werden auf der Form die Zeilen dynamisch aufgebaut. Wurde zuvor über die Funktion SetHighScore() ein neuer Punktestand angegeben, dann wird das Textfeld zur Eingabe des Namens freigeschaltet.

Private Function ReadHighScoreFile(PathAndFilename As String) As String
On Error GoTo ErrorHandler
    Dim sRet As String
    Dim strTextLine As String
    Dim bFileIsOpen As Boolean
    Dim nLen As Long
    Dim FileNr As Long
    Dim Index As Integer
    Dim MyEntry As HighScoreEntry
    Dim nScore As Long

    'Variable initialisieren
    m_HighScoreMin = 0
    m_HighScoreMax = 0
    sRet = ""
    Index = -1
    bFileIsOpen = False

    'Wir ermitteln die Dateilänge in Bytes
    nLen = FileLen(PathAndFilename)

FileInput:
    'nächste verfügbare Dateinummer
    FileNr = FreeFile

    'Öffnen der gewählten Datei
    Open PathAndFilename For Input As #FileNr

    'Das Öffnen hat funktioniert
    bFileIsOpen = True

    'Ändern des Mauszeigers in eine Sanduhr
    Screen.MousePointer = vbHourglass

    'Laden des Dateiinhalts
    Do While Not EOF(FileNr)   ' Schleife bis Dateiende.
        Line Input #FileNr, strTextLine   ' Zeile in Variable einlesen.

        sRet = GetEntryFromTextline(strTextLine, MyEntry)
        If sRet = "" Then
            If Index = -1 Then
                'Überschrift zuweisen
                lblId.Caption = Trim(MyEntry.Id)
                lblName.Caption = Trim(MyEntry.Name)
                lblScore.Caption = Trim(MyEntry.Score)
                lblDate.Caption = Trim(MyEntry.Date)
                lblTime.Caption = Trim(MyEntry.Time)
            ElseIf Index >= 0 And Index < INDEX_MAX Then
                If Index > 0 Then
                    Call LoadNewEntry(Index)
                End If

                If Val(m_HighScoreNew) > 0 And Val(m_HighScoreNew) > Val(MyEntry.Score) Then
                    'Neuer Punktestand einfügen
                    Call InsertNewEntry(Index)
                    Index = Index + 1
                    If Index = INDEX_MAX Then
                        Exit Do
                    End If
                    Call LoadNewEntry(Index)
                End If

                txtId(Index).Text = Trim(Str(Index + 1) & ".")
                txtName(Index).Text = Trim(MyEntry.Name)
                txtScore(Index).Text = Trim(MyEntry.Score)
                txtDate(Index).Text = Trim(MyEntry.Date)
                txtTime(Index).Text = Trim(MyEntry.Time)

                nScore = Val(Trim(MyEntry.Score))
                If m_HighScoreMax < nScore Then m_HighScoreMax = nScore
                If m_HighScoreMin = 0 Then m_HighScoreMin = nScore
                If m_HighScoreMin > nScore Then m_HighScoreMin = nScore
            Else
                Exit Do
            End If

            Index = Index + 1
        End If
    Loop

    If Val(m_HighScoreNew) > 0 And Index < INDEX_MAX Then
        'Neuer Punktestand einfügen
        Call LoadNewEntry(Index)
        Call InsertNewEntry(Index)
        Index = Index + 1
    End If

ExitSub:

    If Index < INDEX_MAX Then
        m_HighScoreMin = 0
    End If

    m_HighScoreLines = Index - 1

    'Schliessen der Datei
    If bFileIsOpen Then Close #FileNr

    'Zurücksetzen des Mauszeigers
    Screen.MousePointer = vbDefault

    'Höhe der Form setzen
    Me.Height = txtId(m_HighScoreLines).Top + txtId(m_HighScoreLines).Height + 480

    'Rückgabewert
    ReadHighScoreFile = sRet

    Exit Function

ErrorHandler:
    Dim ErrNumber As Integer
    Dim ErrDescription As String

    ErrNumber = Err.Number
    ErrDescription = Err.Description
    Select Case ErrNumber
        Case 53
            'Falls die Datei nicht existiert, aber ein neuer Eintrag
            'gesichert werden soll, umgehen wir die Fehlermeldung!
            If Val(m_HighScoreNew) > 0 And Index = -1 Then
                'Neuer Punktestand einfügen
                Index = 0
                Call InsertNewEntry(Index)
                Index = Index + 1
                Resume ExitSub
            End If

            sRet = "Datei " & PathAndFilename & " nicht vorhanden!"
            Index = 1
        Case 62
            If bFileIsOpen Then Close #FileNr
            bFileIsOpen = False
            nLen = nLen - 1
            Resume FileInput
        Case Else
            sRet = "Fehler:" & Str(ErrNumber) & vbCrLf & vbCrLf & ErrDescription
    End Select
    Resume ExitSub
End Function

Funktion zum Schreiben der HighScore-Datei:

Private Function WriteHighScoreFile(PathAndFilename As String) As String
On Error GoTo ErrorHandler
    Dim sRet As String
    Dim strTextLine As String
    Dim bFileIsOpen As Boolean
    Dim FileNr As Long
    Dim Index As Integer

    'Variable initialisieren
    sRet = ""
    bFileIsOpen = False

    'nächste verfügbare Dateinummer
    FileNr = FreeFile

    'Öffnen der gewählten Datei
    Open PathAndFilename For Output As #FileNr

    'Das Öffnen hat funktioniert
    bFileIsOpen = True

    'Ändern des Mauszeigers in eine Sanduhr
    Screen.MousePointer = vbHourglass

    'Sichern der Überschrift
    strTextLine = lblId.Caption & ";" & _
                  lblName.Caption & ";" & _
                  lblScore.Caption & ";" & _
                  lblDate.Caption & ";" & _
                  lblTime.Caption
    Print #FileNr, strTextLine

    'Sichern der Daten
    For Index = 0 To m_HighScoreLines
        strTextLine = txtId(Index).Text & ";" & _
                      txtName(Index).Text & ";" & _
                      txtScore(Index).Text & ";" & _
                      txtDate(Index).Text & ";" & _
                      txtTime(Index).Text
        Print #FileNr, strTextLine
    Next Index

ExitSub:
    'Schliessen der Datei
    If bFileIsOpen Then Close #FileNr

    'Zurücksetzen des Mauszeigers
    Screen.MousePointer = vbDefault

    'Rückgabewert
    WriteHighScoreFile = sRet

    Exit Function

ErrorHandler:
    Dim ErrNumber As Integer
    Dim ErrDescription As String

    ErrNumber = Err.Number
    ErrDescription = Err.Description
    Select Case ErrNumber
        Case 53
            sRet = "Datei kann nicht geöffnet werden: " & PathAndFilename
        Case Else
            sRet = "Fehler:" & Str(ErrNumber) & vbCrLf & vbCrLf & ErrDescription
    End Select
    Resume ExitSub
End Function

Funktion zu Hinzufügen eines neuen HighScore-Eintrags:

Private Sub InsertNewEntry(Index As Integer)
    Dim nScore As Long

    txtId(Index).Text = Trim(Str(Index + 1) & ".")
    txtName(Index).Text = "?"
    txtScore(Index).Text = Trim(m_HighScoreNew)
    txtDate(Index).Text = Date
    txtTime(Index).Text = Left(Time, 5) 'ohne Sekunden

    txtName(Index).Enabled = True
    txtName(Index).Locked = False
    txtName(Index).SelStart = 0
    txtName(Index).SelLength = Len(txtName(Index).Text)

    nScore = Val(m_HighScoreNew)
    If m_HighScoreMax < nScore Then m_HighScoreMax = nScore
    If m_HighScoreMin = 0 Then m_HighScoreMin = nScore
    If m_HighScoreMin > nScore Then m_HighScoreMin = nScore

    m_HighScoreChanged = True

    m_HighScoreNew = 0
End Sub

Funktion zum Erstellen neuer Objekte für den HighScore-Eintrag:

Private Sub LoadNewEntry(Index As Integer)
    Load txtId(Index)
    txtId(Index).Move txtId(0).Left, txtId(0).Top + Index * (txtId(0).Height + 60)
    txtId(Index).Visible = True

    Load txtName(Index)
    txtName(Index).Move txtName(0).Left, txtName(0).Top + Index * (txtName(0).Height + 60)
    txtName(Index).Visible = True

    Load txtScore(Index)
    txtScore(Index).Move txtScore(0).Left, txtScore(0).Top + Index * (txtScore(0).Height + 60)
    txtScore(Index).Visible = True

    Load txtDate(Index)
    txtDate(Index).Move txtDate(0).Left, txtDate(0).Top + Index * (txtDate(0).Height + 60)
    txtDate(Index).Visible = True

    Load txtTime(Index)
    txtTime(Index).Move txtTime(0).Left, txtTime(0).Top + Index * (txtTime(0).Height + 60)
    txtTime(Index).Visible = True
End Sub

Funktion für Tasteneingabe:

Private Sub Form_KeyPress(KeyAscii As Integer)
    Select Case KeyAscii
        Case vbKeyEscape, vbKeyReturn
            Unload Me
    End Select
End Sub

Funktion für Initialisierung der Variable:

Private Sub Form_Load()
    'Titel anzeigen?
    If m_HighScoreTitle <> "" Then Me.Caption = m_HighScoreTitle

    m_HighScoreLines = 1
    m_HighScoreChanged = False

    'Falls ein Dateiname angegeben wurde...
    If m_HighScoreFilename <> "" Then
        '...Datei einlesen
        Dim sRet As String
        sRet = ReadHighScoreFile(m_HighScoreFilename)
        If sRet <> "" Then
            'MsgBox sRet
        End If
    Else
        '...Hinweis ausgeben
        Call MsgBox("Sie müssen einen Dateinamen angeben!" & vbCrLf & _
        "Verwenden Sie dazu die Funktion SetHighScoreFilename()", vbOKOnly)
    End If

    'Formular zentrieren
    Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2
End Sub

Funktion zum Entladen aller Objekte:

Private Sub Form_Unload(Cancel As Integer)
    If m_HighScoreChanged Then
        Dim sRet As String
        sRet = WriteHighScoreFile(m_HighScoreFilename)
        If sRet <> "" Then
            MsgBox sRet
        End If
    End If

    If (m_HighScoreLines > 1) Then
        Dim Index As Integer
        For Index = 1 To m_HighScoreLines
            Unload txtId(Index)
            Unload txtName(Index)
            Unload txtScore(Index)
            Unload txtDate(Index)
            Unload txtTime(Index)
        Next Index
    End If
End Sub

Timer-Funktion für ein automatisches Entladen:

Private Sub TimerAutoUnload_Timer()
    Unload Me
End Sub

Funktion für Tasteneingabe der Textbox:

Private Sub txtName_KeyPress(Index As Integer, KeyAscii As Integer)
    Select Case KeyAscii
        Case vbKeyEscape, vbKeyReturn
            'Überprüfe Eingabe
            If txtName(Index).Text = "" Then
                txtName(Index).SetFocus
            Else
                Unload Me
            End If
        Case vbKeyBack
            'Taste Backspace lassen wir zu
        Case Else
            'Nur bestimmte Zeichen für die Eingabe zulassen.
            If InStr(1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.-+*#_=?<>()[]{} ", UCase(Chr(KeyAscii)), vbTextCompare) = 0 Then
                KeyAscii = 0
            End If
    End Select
End Sub

Modul: clsWavFile

Hier ist meine Klasse für die WavFile-Anbindung.

'///////////////////////////////////////////////////////////////////////////
'//
'// Projekt : MBSimonChallenge
'// Sprache : Basic
'// Compiler: MS Visual Basic 6.0
'// Autor   : Manfred Becker
'// E-Mail  : mani.becker@web.de
'// Url     : http://manib.ma.funpic.de
'// Modul   : clsWavFile
'// Version : 1.02
'// Datum   : 27.01.2008
'//
'///////////////////////////////////////////////////////////////////////////

Option Explicit

'Lokale Variable
Private snd_Handle&
Private snd_Soundcard As Boolean
Private snd_Recording As Boolean
Private snd_NumDevs As Long
Private snd_PlayMidi As Boolean

'Deklaration der notwendigen API-Funktionen
Private Declare Function MySndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As Any, ByVal uFlags As Long) As Long
Private Declare Function MyMciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long
Private Declare Function MyWaveOutGetNumDevs Lib "winmm.dll" Alias "waveOutGetNumDevs" () As Long
Private Declare Function MyPlaySound Lib "winmm.dll" Alias "PlaySoundA" (ByVal lpszName As String, ByVal hModule As Long, ByVal dwFlags As Long) As Long
Private Declare Function MyWaveOutGetVolume Lib "winmm.dll" Alias "waveOutGetVolume" (ByVal uDeviceID As Long, lpdwVolume As Long) As Long
Private Declare Function MyWaveOutSetVolume Lib "winmm.dll" Alias "waveOutSetVolume" (ByVal uDeviceID As Long, ByVal dwVolume As Long) As Long
Private Declare Function MyGetShortPathName Lib "kernel32" Alias "GetShortPathNameA" (ByVal lpszLongPath As String, ByVal lpszShortPath As String, ByVal cchBuffer As Long) As Long
Private Declare Function MyMidiOutGetVolume Lib "winmm.dll" Alias "midiOutGetVolume" (ByVal uDeviceID As Long, lpdwVolume As Long) As Long
Private Declare Function MyMidiOutSetVolume Lib "winmm.dll" Alias "midiOutSetVolume" (ByVal uDeviceID As Long, ByVal dwVolume As Long) As Long


'Notwendige Flags, siehe WIN32API.TXT von VisualBasic
Public Enum SND_FLAGS
    SND_SYNC = &H0         '  play synchronously (default)
    SND_ASYNC = &H1        '  play asynchronously
    SND_NODEFAULT = &H2    '  silence not default, if sound not found
    SND_MEMORY = &H4       '  lpszSoundName points to a memory file
    SND_LOOP = &H8         '  loop the sound until next sndPlaySound
    SND_NOSTOP = &H10      '  don't stop any currently playing sound
End Enum


'Diese Prozedur wird einmal bei Instanzieren der Klasse ausgeführt
'und ist somit mit einem C++ Konstruktor vergleichbar
Private Sub Class_Initialize()
    Call TestSoundkarte
    snd_Recording = False
End Sub


'Diese Prozedur wird einmal bei Beenden der Klasse ausgeführt
'und ist somit mit einem C++ Destruktor vergleichbar
Private Sub Class_Terminate()
    If snd_Soundcard Then
        If snd_Recording Then
            Call StopRecord
        End If
        SndPlaySound 0&, 0

        If snd_PlayMidi Then
            Call StopMidi
        End If
    End If
End Sub


'Funktion zum Test der Soundkarte
Public Function TestSoundkarte() As Boolean
    snd_NumDevs = MyWaveOutGetNumDevs() 'Anzahl verfügbarer Soundkarten
    snd_Soundcard = (snd_NumDevs > 0)
    TestSoundkarte = snd_Soundcard
End Function


'Funktion zum Abspielen einer Wav-Datei mittels MyMciSendString
Public Sub Play(PathAndFilename As String)
    If snd_Soundcard Then
        MyMciSendString "CLOSE mysound", "", 0, snd_Handle
        MyMciSendString "OPEN WAVEAUDIO!" & PathAndFilename & " ALIAS mysound", "", 0, snd_Handle
        MyMciSendString "PLAY mysound from 0", "", 0, snd_Handle
    End If
End Sub


'Funktion zum Abspielen einer Wav-Datei mittels SndPlaySound (incl. Flag-Steuerung)
Public Sub SndPlaySound(PathAndFilename As String, Flags As SND_FLAGS)
    If snd_Soundcard Then
        MySndPlaySound PathAndFilename, Flags
    End If
End Sub


'Funktion zum Stoppen einer Wav-Datei
Public Sub SndStopSound()
    If snd_Soundcard Then
        MySndPlaySound 0&, 0
    End If
End Sub


'Funktion zum Abspielen einer Wav-Datei mittels PlaySound (incl. Modul und Flag-Steuerung)
Public Function PlaySound(ByVal lpszName As String, ByVal hModule As Long, ByVal dwFlags As Long) As Long
    If snd_Soundcard Then
        PlaySound = MyPlaySound(lpszName, hModule, dwFlags)
    Else
        PlaySound = -1
    End If
End Function


'Funktion zum Aufnehmen einer Wav-Datei
Public Sub StartRecord()
    If snd_Soundcard Then
        MyMciSendString "OPEN NEW TYPE WAVEAUDIO ALIAS mysound", "", 0, snd_Handle
        MyMciSendString "SET mysound TIME FORMAT MS BITSPERSAMPLE 8 CHANNELS 2 SAMPLESPERSEC 22050 BYTESPERSEC 22050", "", 0, snd_Handle
        MyMciSendString "DELETE mysound from 0", "", 0, snd_Handle
        MyMciSendString "RECORD mysound from 0 overwrite", "", 0, snd_Handle
        snd_Recording = True
    End If
End Sub


'Funktion zum Stoppen der Aufnahme einer Wav-Datei
Public Sub StopRecord()
    If snd_Soundcard Then
        MyMciSendString "STOP mysound", "", 0, snd_Handle
        snd_Recording = False
    End If
End Sub


'Funktion zum Abspielen einer aufgenommenen Wav-Datei
Public Sub PlayRecord()
    If snd_Soundcard Then
        MyMciSendString "PLAY mysound from 0", "", 0, snd_Handle
    End If
End Sub


'Funktion zum Sichern einer aufgenommenen Wav-Datei
Public Sub SaveRecord(PathAndFilename As String)
    If snd_Soundcard Then
        MyMciSendString "SAVE mysound " & PathAndFilename, "", 0, snd_Handle
        MyMciSendString "CLOSE mysound", "", 0, snd_Handle
    End If
End Sub


'Funktion zur Ermittlung der Wave-Lautstärke
Public Function GetWaveVolume() As Long
    Dim dwRet As Long
    Dim dwVolume As Long
    Dim uDeviceID As Long

    dwVolume = -1
    uDeviceID = 0
    If snd_Soundcard Then
        dwRet = MyWaveOutGetVolume(uDeviceID, dwVolume)
    End If
    GetWaveVolume = dwVolume
End Function


'Funktion zum Setzen der Wave-Lautstärke
Public Sub SetWaveVolume(dwVolume As Long)
    Dim dwRet As Long
    Dim uDeviceID As Long

    uDeviceID = 0
    If snd_Soundcard Then
        dwRet = MyWaveOutSetVolume(uDeviceID, dwVolume)
    End If
End Sub


'Funktion ermittelt den kurzen Pfad-/Dateinamen einer Datei (8.3)
Private Function Long2ShortPath(ByVal LongPath As String) As String
    Dim Buffer As String

    Buffer = Space$(256)
    If MyGetShortPathName(LongPath, Buffer, Len(Buffer)) <> 0 Then
        Long2ShortPath = Left$(Buffer, InStr(Buffer, vbNullChar) - 1)
    Else
        Long2ShortPath = ""
    End If
End Function


'Funktion zum Abspielen einer MIDI-Datei
Public Function PlayMidi(ByVal PathAndFilename As String) As Boolean
    Dim Buffer As String
    Dim ErrHandler As Long
    Dim ShortPath As String

    'Prüfen ob eine MIDI-Datei übergeben wurde
    If UCase$(Mid$(PathAndFilename, Len(PathAndFilename) - 2)) <> "MID" Then
        PlayMidi = False
        Exit Function
    End If

    'Pfad-/Dateinamen in kurzen Pfad-/Dateinamen wandeln
    ShortPath = Long2ShortPath(PathAndFilename)
    If Len(ShortPath) = 0 Then
        PlayMidi = False
        Exit Function
    End If

    If snd_Soundcard Then
        If snd_PlayMidi Then
            Call StopMidi
        End If

        Buffer = Space$(256)
        ErrHandler = MyMciSendString("open sequencer!" & ShortPath & " alias MIDI", Buffer, Len(Buffer), 0)
        ErrHandler = MyMciSendString("play MIDI", Buffer, Len(Buffer), 0)

        snd_PlayMidi = (ErrHandler = 0)
    Else
        snd_PlayMidi = False
    End If
    PlayMidi = snd_PlayMidi
End Function


'Funktion zum Stoppen des Abspielvorgangs
Public Sub StopMidi()
    If snd_Soundcard Then
        MyMciSendString "stop MIDI", 0, 0, 0
        MyMciSendString "close MIDI", 0, 0, 0
        snd_PlayMidi = False
    End If
End Sub


'Funktion zur Ermittlung der Midi-Lautstärke
Public Function GetMidiVolume() As Long
    Dim dwRet As Long
    Dim dwVolume As Long
    Dim uDeviceID As Long

    dwVolume = -1
    uDeviceID = 0
    If snd_Soundcard Then
        dwRet = MyMidiOutGetVolume(uDeviceID, dwVolume)
    End If
    GetMidiVolume = dwVolume
End Function


'Funktion zum Setzen der Wave-Lautstärke
Public Sub SetMidiVolume(dwVolume As Long)
    Dim dwRet As Long
    Dim uDeviceID As Long

    uDeviceID = 0
    If snd_Soundcard Then
        dwRet = MyMidiOutSetVolume(uDeviceID, dwVolume)
    End If
End Sub

Das war's mal wieder. Ich hoffe dieser Artikel hat euch gefallen. Über einen Eintrag in meinem Gästebuch würde ich mich freuen. Wenn ihr Anregungen habt, oder Verbesserungsvorschläge, dann gebt mir bitte ein Feedback. Falls ihr weitere interessante Artikel lesen wollt, dann schaut mal hier rein.

Ciao,
Manfred

Historie