Pisanie gier w VB (2)
Generalnie VB zbyt dobrą platformą do gier nie jest. Niemniej niekiedy użycie go do napisania gierki nie jest do końca spalonym pomysłem.
W Visual Basicu można napisać gry logiczne (puzzle, mastermindy, sokobany itp.) oraz takie, w których element zręcznościowy jest niewielki i ściśle ograniczony (tetrisy, węża itp.). Większość takich opiera się prostokątnym polu gry podzielonych ma mniejsze elementy. Takie rozwiązanie daje duże możliwości, gdyż nadaje się do bardzo wielu rodzajów gier.
Jest tylko jeden problem – jakiego komponentu użyć do przedstawienia pola gry? Naturalne wydawałoby się użycie kontrolki Grid. Rzecz w tym, że jest to kontrolka o ograniczonych możliwościach – jest po prostu tabelką, w którą można wpisywać liczby i litery. A kto by grał w tetrisa w trybie znakowym :))
Ale można to zrobić inaczej. wy
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
17 |
18 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
Oczywiście nie musi ono mieć wymiary 10x10, może być całkiem inne, także nie-kwadratowe (np. 10x15).
Tablicę nazwiemy np. imgGameField. Każdy jej element nazwijmy 'kratką'. Deklarujemy też odpowiednią tablicę zmiennych, przechowujących nasze pole gry:
Option Base 1
Dim PoleGry(100) As Integer
Dyrektywa Option Base 1 jest po to, żeby kontrolce imgGameField(x) odpowiadała zmienna PoleGry(x). Można by się zapytać, czemu nie czynimy tablicy PoleGry dwuwymiarową. Powód jest prosty: VB nie pozwala na stworzenie dwuwymiarowej tablicy komponentów, tak więc przy każdym odwołaniu z tablicy Image'ów (widocznej dla gracza) do tablicy zmiennych (i odwrotnie) należałoby przeliczać indeksy. A po co?
Aby wyświetlić zawartość planszy na ekranie korzystamy z pętli For i funkcji LoadPicture():
Public Sub OdswiezPoleGry()
For i = 1 To 100
imgGameField(i) = LoadPicture(PoleGry(i) & “.bmp”)
Next i
End Sub
Oczywiście trzeba stworzyć odpowiednie rysunki (niekoniecznie bitmapy) i odpowiednio je ponumerować. Jeżeli na przykład tworzymy sokoban, czyli grę, która polega na układaniu pudełek na odpowiednich miejscach, to możemy np. przez 0 oznaczyć puste miejsce, 1 mur otaczający etap, 2 pudełko itd. Tak właśnie postapiłem tworząc grę Skrzynki.
Jeżeli naszą grą jest tetris, to np. 0 będzie pustym miejscem, 1 klocki
Pozostaje jeszcze kwestia poruszania się. Zaprezentuję przykład dla gracza zajmującego jedną kratkę, który zmienia swoje położenie tylko z woli grającego (a nie tak jak w tetrisach czy wężu). A więc definiujemy stałe odpowiadające kierunkom i odpowiednim klawiszom strzałek:
Const Lewo = vbKeyLeft
Const Prawo = vbKeyRight
Const Gora = vbKeyUp
Const Dol = vbKeyDown
Oczywiście nie jest to konieczne, ale wygodne - stałe są krótsze i łatwiejsze do zapamiętania. Deklarujemy jeszcze zmienną odpowiadają aktualnej pozycji gracza (ściślej: jaki numer ma element tablicy, w której znajduje się obecnie gracz):
Dim PozycjaGracza As Integer
Zanim przejdziemy do pisania funkcji przesuwającej gracza potrzebna nam będzie jeszcze jedna stała:
Const WysokoscPolaGry = 10
Jej przeznaczenie jest wiadome, należy tylko zmodyfikować jej wartość stosowanie do naszego pola gry (zauważ, że szerokość pola gry nie ma znaczenia, później dowiesz się dlaczego!).
Teraz piszemy funkcję:
Public Function PrzesunGracza(ByVal Kierunek As Integer) As Boolean
Select Case Kierunek
Case Lewo
PoleGry(PozycjaGracza) = 0
PozycjaGracza = PozycjaGracza - 1
PoleGry(PozycjaGracza) = 5 'przy założeniu, że wartość 5 ozn
Ten prosty kod przesuwa gracza w zadanym kierunku (teraz już wiesz do czego jest potrzebna stała WysokoscPolaGry). Dzięki temu, że jest to funkcja, a nie zwykły Sub, możemy sprawdzać czy posunięcie się powiodło (do tego potrzeba jednak dodatkowego kodu wewnątrz instrukcji Case).
Pozostaje jeszcze przypisać tę funkcję do klawiszy. Ustawiamy właściwość KeyPreview formularza na True i piszemy w zdarzeniu KeyDown (nie KeyPress!):
Private Sub Form_KeyDown(Keycode As Integer, Shift As Integer)
If Keycode = Lewo Or Keycode = Prawo Or Keycode = Gora Or Keycode = Dol Then
If PrzesunGracza(Keycode)= True Then
OdswiezPoleGry
Else
NieMozna
End If
End If
End Sub
Procedura NieMozna powinna być reakcją na brak możliwości wykonania ruchu. Może się rozlec ostrzegawczy sygnał (np. za pomocą funkcji API MessageBeep(-1)).
Nie samą klawiaturą człowiek żyje - jeżeli chcemy stworzyć grę obsługiwaną myszą (choćby Kulki), to należy wypełnić procedurę:
Private Sub imgGameField_Click(Index As Integer)
End Sub
Dzięki parametrowi Index wiemy, w którą kratkę gracz klika, co zwykle ma pierwszoplanowe znaczenie.
I jeszcze jedno: często musimy losowo rozmieścić na planszy jakieś elementy, np. miny w Saperze, kulki itp. Najprościej się to robi tak:
Randomize
For i = 1 To 40 Step 1 '
Visual Basic nie posiada instrukcji continue, więc trzeba sobie radzić inaczej (w C++ warunek wyglądałby: if (PoleGry[x] == Mina) continue;). Pętla Do będzie się wykonywać do skutku, tzn. aż zostanie znaleziona kratka, na której miny nie ma.
W tym przykładzie tworzona jest plansza, na jakiej gramy w windowsowym Saperze na poziomie
If LiczbaMin >= UBound(PoleGry, 1) - 10 Then
' tu
Zachowujemy sobie pewien zapas (10 kratek), żeby pole nie było całkowicie zaminowane (bo wtedy zgodnie z zasadami Sapera byłaby to natychmiastowa wygrana).
Cały czas mówię o Saperze, ale oczywiście można ten sposób zastosować także do Kulek i w ogóle wszędzie, gdzie musimy wybrać losową pozycję dla jakiegoś elementu.
I to by było na tyle. Nie zamierzałem się zagłębiać w niuanse grafiki i dźwięku, tylko pokazać jak zrobić szkielet prostej gry.
Karol Kuczmarski
qkarol@go2.pl
http://www.qkarol.prv.pl
ICQ (UIN): 69629311