Als weiterführende Übungsaufgaben werden in diesem Kapitel zwei lauffähige Beispielprojekte vorgeführt. Hat man den geschilderten Aufbau verstanden, kann man später eigene Veränderungen, Verbesserungen oder Erweiterungen einbringen.
12 Beispielprojekte
12.1 Spielprogramm Tetris 

Im Folgenden wird das bekannte Spielprogramm Tetris in einer vereinfachten, nachvollziehbaren Visual Basic 2008-Version realisiert und erläutert. Das Programm beinhaltet:
- ein zweidimensionales Feld
- einen Timer
- einen Zufallsgenerator
- die Erzeugung und Löschung von Steuerelementen zur Laufzeit
Abbildung 12.1 zeigt die Benutzeroberfläche des Programms:
Abbildung 12.1 Tetris
12.1.1 Spielablauf 

Nach Programmstart fällt ein Block in einer von acht möglichen Farben so weit herunter, bis er auf den Rand des Spielfelds oder einen anderen Block trifft. Er kann mithilfe der drei Buttons Links (Li), Rechts (Re) und Drop (Dr) bewegt werden. Drop bewirkt ein sofortiges Absenken des Blocks auf die unterste mögliche Position.
Level
Falls sich drei gleichfarbige Blöcke untereinander oder nebeneinander befinden, so verschwinden sie. Blöcke, die sich eventuell darüber befinden, rutschen nach. Anschließend wird die Fallgeschwindigkeit der Blöcke erhöht, d. h. die Schwierigkeitsstufe wird gesteigert, man gelangt zum nächsten Level.
Ende
Sobald ein Block nur noch in der obersten Zeile platziert werden kann, ist das Spiel zu Ende. Ziel des Spiels ist es, so viele Blöcke wie möglich zu platzieren. Mit der Taste Pause kann das Spiel unterbrochen werden, eine erneute Betätigung der Taste lässt das Spiel weiterlaufen.
12.1.2 Programmbeschreibung 

Hilfsfeld
Der Kasten, in dem sich die fallenden Blöcke befinden, ist 8 Spalten breit und 13 Zeilen hoch. Als Hilfskonstruktion steht das zweidimensionale Feld F mit 10 Spalten und 15 Zeilen zur Verfügung, in dem jeder existierende Block mit seiner laufenden Nummer vermerkt ist.
| Ze / Sp | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
|
1 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
2 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
3 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
4 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
5 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
6 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
7 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
8 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
9 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
10 |
–2 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
11 |
–2 |
–1 |
–1 |
–1 |
11 |
–1 |
–1 |
–1 |
–1 |
–2 |
|
12 |
–2 |
–1 |
–1 |
–1 |
3 |
8 |
9 |
–1 |
–1 |
–2 |
|
13 |
–2 |
–1 |
0 |
10 |
2 |
4 |
5 |
–1 |
–1 |
–2 |
|
14 |
–2 |
–2 |
–2 |
–2 |
–2 |
–2 |
–2 |
–2 |
–2 |
–2 |
Im oben angegebenen Beispiel wird der Inhalt des Felds F nach den Blöcken 0 bis 11, also nach 12 gefallenen Blöcken angezeigt. Die Blöcke 1, 6 und 7 hatten die gleiche Farbe, standen über- oder nebeneinander und sind deshalb schon verschwunden. Die Randelemente werden zu Spielbeginn mit dem Wert -2 besetzt. Alle Elemente, die keinen Block enthalten, also leer sind, haben den Wert -1.
12.1.3 Steuerelemente 

Es gibt zu Beginn des Programms folgende Steuerelemente:
- vier Buttons für Links, Rechts, Drop und Pause
- drei Panels als Begrenzungslinien des Spielfelds
- ein Timer, der den aktuellen Block automatisch weiter fallen lässt (Startwert für den Zeitintervall: 500ms).
Timer
Im Verlauf des Programms werden weitere Steuerelemente vom Typ Panel für die fallenden Blöcke hinzugefügt bzw. wieder entfernt.
12.1.4 Initialisierung des Programms 

Zu Beginn werden die modulweiten Variabeln vereinbart und die Formular-Load-Prozedur durchlaufen:
Public Class frm1201
' Index des aktuellen Blocks
Dim B As Integer
' Gesamtes Spielfeld inkl. Randfelder
Dim F(14, 9) As Integer
' Zeile und Spalte des aktuellen Blocks
Dim BZe As Integer
Dim BSp As Integer
' Schwierigkeitsstufe
Dim Stufe As Integer
' Eine zunächst leere Liste von Spiel-Blöcken
Dim Block As New List(Of Panel)
' Ein Feld von Farben für die Blöcke
Dim FarbenFeld() As Color = {Color.Red, _
Color.Yellow, Color.Green, Color.Blue, _
Color.Cyan, Color.Magenta, Color.Black, _
Color.White}
Private Sub frm1201_Load( ... ) Handles MyBase.Load
Dim Ze, Sp As Integer
' Zufallsgenerator initialisieren
Randomize()
' Feld besetzen
For Ze = 1 To 13
F(Ze, 0) = -2
For Sp = 1 To 8
F(Ze, Sp) = -1
Next Sp
F(Ze, 9) = -2
Next Ze
For Sp = 0 To 9
F(14, Sp) = -2
Next Sp
' Initialisierung
Stufe = 1
NächsterBlock()
End Sub
[ ... ]
End ClassZur Erläuterung der modulweiten Variablen:
- Die laufende Nummer (der Index) des aktuell fallenden Blocks wird in der Variablen B festgehalten.
- Das gesamte Spielfeld, das im Abschnitt »Programmbeschreibung« schematisch dargestellt wurde, wird im zweidimensionalen Feld F gespeichert.
Hilfsfeld
- Die Variablen BZe und BSp beinhalten die Zeilen- und Spalten-Position des aktuell fallenden Blocks innerhalb des Spielfelds.
- Die Variable Stufe kennzeichnet den Schwierigkeitsgrad des Spiels. Jedes Mal, wenn drei Blöcke, die untereinander oder nebeneinander lagen, gelöscht wurden, wird die Stufe um 1 erhöht. Dies sorgt für ein kürzeres TimerIntervall, die Blöcke werden schneller.
Level
- Block ist eine Liste von Steuerelementen vom Typ Panel. Diese Panels stellen die fallenden Blöcke dar. Zu Beginn ist die Liste leer.
Liste von Blöcken
- Das Feld FarbenFeld enthält insgesamt acht Farben. Die Farben der Blöcke werden per Zufallsgenerator ermittelt.
Zur Erläuterung der Formular-Load-Prozedur:
- Es wird zunächst der Zufallsgenerator initialisiert.
Zufallsgenerator
- Anschließend werden die Elemente des oben beschriebenen Hilfsfelds F mit -1 bzw. -2 besetzt. Der Wert -1 zeigt an, dass an dieser Stelle kein Block liegt. Der Wert -2 zeigt an, dass an dieser Stelle ein Randfeld liegt.
- Die Schwierigkeitsstufe wird auf 1 gesetzt.
- Es wird die Prozedur NächsterBlock() aufgerufen. Sie ist in diesem Fall für die Erzeugung des ersten fallenden Blocks zuständig.
12.1.5 Erzeugen eines neuen Blocks 

Diese Prozedur NächsterBlock() dient zur Erzeugung eines neuen fallenden Blocks. Dies geschieht zu Beginn des Spiels und nachdem ein Block auf dem unteren Rand des Spielfelds oder auf einem anderen Block zum Stehen gekommen ist.
Public Class frm1201
[ ... ]
Private Sub NächsterBlock()
Dim Farbe As Integer
' Neuen Block zum Formular hinzufügen
Block.Add(New Panel)
' Nummer des aktuellen Blocks ermitteln
B = Block.Count - 1
' Neuen Block platzieren
Block(B).Location = New Point(100, 80)
Block(B).Size = New Point(20, 20)
' Farbauswahl für neuen Block
Farbe = Math.Floor(Rnd() * 8)
Block(B).BackColor = FarbenFeld(Farbe)
' Zum Formular hinzufügen
Controls.Add(Block(B))
' Aktuelle Zeile, Spalte
BZe = 1
BSp = 5
End Sub
[ ... ]
End ClassZur Erläuterung:
- Zur Liste Block wird ein Element mithilfe der Methode Add() hinzugefügt.
Neues Listenelement
- Seine laufende Nummer (der Index) wird mithilfe der Eigenschaft Count ermittelt.
- Es werden die Eigenschaften »Ort«, »Größe« und »Farbe« des Blocks bestimmt.
- Der Block ist ein Steuerelement der Klasse Panel. Er wird mithilfe der Methode Add() zur Auflistung der Steuerelemente der aktuellen Klasse, also des Formulars, hinzugefügt. Dadurch wird der Block sichtbar.
Neues Steuerelement
- Die Variablen BZe und BSp, die die Position des Blocks im Spielfeld F angeben, werden gesetzt.
12.1.6 Der Zeitgeber 

In regelmäßigen Zeitabständen wird das Timer-Ereignis erzeugt und damit die Ereignisprozedur timT_Tick() aufgerufen. Diese sorgt dafür, dass sich ein Block nach unten bewegt, falls dies noch möglich ist.
Public Class frm1201
[ ... ]
Private Sub timT_Tick( ... ) Handles ...
' Falls es nicht mehr weiter geht
If F(BZe + 1, BSp) <> -1 Then
' Oberste Zeile erreicht
If BZe = 1 Then
timT.Enabled = False
MsgBox("Das war's")
Exit Sub
End If
F(BZe, BSp) = B ' Belegen
ReihePrüfen()
NächsterBlock()
Else
' Falls es noch weiter geht
Block(B).Top = Block(B).Top + 20
BZe = BZe + 1
End If
End Sub
[ ... ]
End ClassZur Erläuterung:
- Zunächst wird geprüft, ob sich unterhalb des aktuellen Blocks noch ein freies Feld befindet.
- Ist dies nicht der Fall, so hat der Block seine Endposition erreicht.
- Befindet sich diese Endposition in der obersten Zeile, so ist das Spiel zu Ende. Der Timer wird deaktiviert, andernfalls würden weitere Blöcke erzeugt. Es erscheint eine Meldung, und die Prozedur wird unmittelbar beendet. Will der Spieler erneut starten, so muss er das Programm beenden und neu starten.
Endposition
- Befindet sich die Endposition nicht in der obersten Zeile, so wird die Blocknummer im Feld F mit der aktuellen Zeile und Spalte vermerkt. Dies dient zur Kennzeichnung eines belegten Feldelements.
- Die Prozedur ReihePrüfen() wird aufgerufen (siehe unten), um festzustellen, ob es drei gleichfarbige Blöcke über- oder nebeneinander gibt. Anschließend wird der nächste Block erzeugt.
Prüfen
- Befindet sich unterhalb des Blocks noch ein freies Feld, so kann der Block weiter fallen. Seine Koordinaten und die aktuelle Zeilennummer werden verändert.
Fallen
12.1.7 Blöcke löschen 

Die Prozedur ReihePrüfen() ist eine rekursive Prozedur, in der festgestellt wird, ob es drei gleichfarbige Blöcke nebeneinander oder übereinander gibt. Ist dies der Fall, werden diese Blöcke entfernt und die darüber liegenden Blöcke rutschen nach.
Rekursiv
Möglicherweise befinden sich nun wieder drei gleichfarbige Blöcke nebeneinander oder übereinander, es muss also wiederum geprüft werden. Dies geschieht so lange, bis keine drei gleichfarbigen Blöcke nebeneinander oder übereinander gefunden wurden.
Public Class frm1201
[ ... ]
Private Sub ReihePrüfen()
Dim Ze, Sp, ZeX, SpX As Integer
Dim Neben, Über As Boolean
Neben = False
Über = False
' Drei gleiche Steine nebeneinander?
For Ze = 13 To 1 Step -1
For Sp = 1 To 6
' Falls drei Felder nebeneinander besetzt
If F(Ze, Sp) <> -1 And F(Ze, Sp + 1) <> -1 _
And F(Ze, Sp + 2) <> -1 Then
' Falls drei Farben gleich
If Block(F(Ze, Sp)).BackColor = _
Block(F(Ze, Sp + 1)).BackColor _
And Block(F(Ze, Sp)).BackColor = _
Block(F(Ze, Sp + 2)).BackColor Then
For SpX = Sp To Sp + 2
' Block aus dem Formular löschen
Controls.Remove(Block(F(Ze, SpX)))
' Feld leeren
F(Ze, SpX) = -1
' Blöcke oberhalb des entladenen
' Blockes absenken
ZeX = Ze - 1
Do While F(ZeX, SpX) <> -1
Block(F(ZeX, SpX)).Top = _
Block(F(ZeX, SpX)).Top + 20
' Feld neu besetzen
F(ZeX + 1, SpX) = F(ZeX, SpX)
F(ZeX, SpX) = -1
ZeX = ZeX - 1
Loop
Next SpX
Neben = True
End If
End If
If Neben Then Exit For
Next Sp
If Neben Then Exit For
Next Ze
' Drei gleiche Steine übereinander?
For Ze = 13 To 3 Step -1
For Sp = 1 To 8
' Falls drei Felder übereinander besetzt
If F(Ze, Sp) <> -1 And F(Ze - 1, Sp) <> -1 _
And F(Ze - 2, Sp) <> -1 Then
' Falls drei Farben gleich
If Block(F(Ze, Sp)).BackColor = _
Block(F(Ze - 1, Sp)).BackColor _
And Block(F(Ze, Sp)).BackColor = _
Block(F(Ze - 2, Sp)).BackColor Then
' 3 Blöcke entladen
For ZeX = Ze To Ze - 2 Step -1
' Block aus dem Formular löschen
Controls.Remove(Block(F(ZeX, Sp)))
' Feld leeren
F(ZeX, Sp) = -1
Next ZeX
Über = True
End If
End If
If Über Then Exit For
Next Sp
If Über Then Exit For
Next Ze
If Neben Or Über Then
' Schneller
Stufe = Stufe + 1
timT.Interval = 5000 / (Stufe + 9)
' Eventuell kann jetzt noch eine Reihe
' entfernt werden
ReihePrüfen()
End If
End Sub
[ ... ]
End ClassZur Erläuterung:
- Die Variablen Neben und Über kennzeichnen die Tatsache, dass drei gleichfarbige Blöcke neben- oder übereinander gefunden wurden. Sie werden zunächst auf False gesetzt.
- Zunächst wird geprüft, ob sich drei gleichfarbige Blöcke nebeneinander befinden. Dies geschieht, indem für jedes einzelne Feldelement geprüft wird, ob es selbst und seine beiden rechten Nachbarn mit einem Block belegt sind, und ob diese Blöcke gleichfarbig sind. Die Prüfung beginnt beim Block unten links und setzt sich bis zum drittletzten Block der gleichen Zeile fort. Anschließend werden die Blöcke in der Zeile darüber geprüft usw.
Nebeneinander
- Sobald eine Reihe gleichfarbiger Blöcke gefunden wurde, werden alle drei Blöcke mithilfe der Methode Remove() aus der Auflistung der Steuerelemente des Formulars gelöscht, d. h. sie verschwinden aus dem Formular. Ihre Position im Feld F wird mit 0 (=leer) besetzt. Nun müssen noch alle Blöcke, die sich eventuell oberhalb der drei Blöcke befinden, um eine Position abgesenkt werden. Die Variable Neben wird auf True gesetzt. Die doppelte Schleife wird sofort verlassen.
- Analog wird nun geprüft, ob sich drei gleichfarbige Blöcke übereinander befinden. Ist dies der Fall, so werden sie aus der Auflistung der Steuerelemente des Formulars gelöscht. Ihre Positionen im Feld F werden mit 0 besetzt. Über den drei Blöcken können sich keine weiteren Blöcke befinden, die entfernt werden müssten.
Übereinander
- Falls durch eine der beiden Prüfungen eine Reihe gefunden und entfernt wurde, so wird die Schwierigkeitsstufe erhöht und das Timer-Intervall verkürzt. Nun muss geprüft werden, ob sich durch das Nachrutschen von Blöcken wiederum ein Bild mit drei gleichfarbigen Blöcken über- oder nebeneinander ergeben hat. Die Prozedur ruft sich also so lange selbst auf (rekursive Prozedur), bis keine Reihe mehr gefunden wurde.
Rekursiv
12.1.8 Blöcke seitlich bewegen 

Mithilfe der beiden Ereignisprozeduren cmdLinks_Click() und cmdRechts_Click() werden die Blöcke nach links bzw. rechts bewegt, falls dies möglich ist.
Public Class frm1201
[ ... ]
Private Sub cmdLinks_Click( ... ) Handles ...
If F(BZe, BSp - 1) = -1 Then
Block(B).Left = Block(B).Left - 20
BSp = BSp - 1
End If
End Sub
Private Sub cmdRechts_Click( ... ) Handles ...
If F(BZe, BSp + 1) = -1 Then
Block(B).Left = Block(B).Left + 20
BSp = BSp + 1
End If
End Sub
[ ... ]
End ClassZur Erläuterung:
- Es wird geprüft, ob sich links bzw. rechts vom aktuellen Block ein freies Feldelement befindet. Ist dies der Fall, so wird der Block nach links bzw. rechts verlegt und die aktuelle Spaltennummer verändert.
Seitlich
12.1.9 Blöcke nach unten bewegen 

Die Ereignisprozedur cmdUnten_Click() dient zur wiederholten Bewegung der Blöcke nach unten, falls dies möglich ist. Diese Bewegung wird so lange durchgeführt, bis der Block auf die Spielfeld-Begrenzung oder einen anderen Block stößt.
Public Class frm1201
[ ... ]
Private Sub cmdUnten_Click( ... ) Handles ...
Do While F(BZe + 1, BSp) = -1
Block(B).Top = Block(B).Top + 20
BZe = BZe + 1
Loop
F(BZe, BSp) = B 'Belegen
ReihePrüfen()
NächsterBlock()
End Sub
[ ... ]
End ClassZur Erläuterung:
- Es wird geprüft, ob sich unter dem aktuellen Block ein freies Feldelement befindet. Ist dies der Fall, so wird der Block nach unten verlegt und die aktuelle Zeilennummer verändert. Dies geschieht so lange, bis der Block auf ein Hindernis stößt.
Nach unten
- Anschließend wird das betreffende Feldelement belegt. Es wird geprüft, ob nun eine neue Reihe von drei gleichfarbigen Blöcken existiert und der nächste Block wird erzeugt.
12.1.10 Pause 

Spiel anhalten
Abhängig vom aktuellen Zustand wird durch Betätigen des Buttons Pause in den Zustand »Pause« geschaltet oder wieder zurück.
Public Class frm1201
[ ... ]
Private Sub cmdPause_Click( ... ) Handles ...
timT.Enabled = Not timT.Enabled
End Sub
[ ... ]
End ClassZur Erläuterung:
- Der Zustand des Timers wechselt zwischen Enabled=True und Enabled=False.



Jetzt online bestellen






