Pisanie gier w VB
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. wykorzystać tablicę Imagełów bądź PictureBoxów. Jeśli nasze pole gry miałoby mieć wymiary 10x10, to trzeba ułożyć komponenty w taki oto sposób:
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 klockiem zielonym, 2 czerwonym, 3 niebieskim itd. Później można sprawdzać, czy któryś rząd został zapełniony i musi być usunięty z ekranu.
BTW: jeżeli robimy tetrisa, to zamiast Image'ów użyjmy kontrolek Shape lub Label. Figury w tetrisie różnią się tylko kolorem, więcej obrazki mogą być zbędne (chyba że przewidujemy jakieś dodatkowe atrakcje).
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 oznacza gracza
PrzesunGracza = True
Exit Function
Case Prawo
PoleGry(PozycjaGracza) = 0
PozycjaGracza = PozycjaGracza + 1
PoleGry(PozycjaGracza) = 5
PrzesunGracza = True
Exit Function
Case Gora
PoleGry(PozycjaGracza) = 0
PozycjaGracza = PozycjaGracza - WysokoscPolaGry
PoleGry(PozycjaGracza) = 5
PrzesunGracza = True
Exit Function
Case Dol
PoleGry(PozycjaGracza) = 0
PozycjaGracza = PozycjaGracza + WysokoscPolaGry
PoleGry(PozycjaGracza) = 5
PrzesunGracza = True
Exit Function
End Select
PrzesunGracza = False
End Function
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 ' 40 to tylko przykład, może być całkiem inna liczba, np. 3 kulki, 99 min itd.
Do While True ' tu jest nam potrzebna pętla nieskończona
x = Int((256 * Rnd) + 1) ' generujemy liczbę losową; 256 to całkowita ilość 'kratek' na planszy
If PoleGry(x) <> Mina Then ' Mina to stała określająca, że na polu gry w danym miejscu jest mina
PoleGry(x) = Mina ' ustawiamy, że w danym polu ma być mina
Exit Do ' wychodzimy z pętli
End If
Loop
Next i
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 Zaawansowany. Jeżeli nie znamy z góry planowanej liczby min (w tym przypadku było to 40), należy sprawdzić czy "starczy miejsca dla wszystkich". Ponieważ używamy pętli nieskończonej, ostrożności nigdy dość:
If LiczbaMin >= UBound(PoleGry, 1) - 10 Then
' tu komunikat o błędzie
End If
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
Wyszukiwarka
Podobne podstrony:
ART2 (10)ART2 (8)ART2 (15)ART2 (2)ART2 (12)ART2 (18)art2ART2 (3)ART2 (14)art2 (16)ART2 (13)więcej podobnych podstron