Widziałem ostatnio w telewizji zajawkę fajnej gry planszowe, nazywa się „Magic Block Game„ i naprawdę wyglądała bardzo interesująco. Postanowiłem więc napisać tutorial jak taką grę napisać w języku vb.net. Oczywiście będzie to jedna z tych lekcji, w której pokażę wam jak to zrobić, jak to działa, a resztę zostawię waszej wyobraźni. Czy zrobicie grę na czas, czy rywalizację na jednym komputerze a może w sieci to już zostawiam wam, gra polega na przesuwaniu kwadracików tak, aby w środku głównej planszy utworzyć wygenerowany wzór, przy czym można przesuwać tylko te elementy sąsiadujące z pustym polem, gra będzie wyglądać tak:
Dodatkową zaletą będzie to, że będziemy mogli bez strat edytować jej rozmiar. Zaczniemy od przygotowania formy. Tutaj za dużo roboty nie będzie, ponieważ wszystkie elementy będą generowały się automatycznie:
Rodzaj elementu | Nazwa elementu | Ustawienia |
---|---|---|
Form | Form1 | Name: Form1 Text: Magiczne klocki Size: 675; 669 |
Splitter1 | Splitter1 | Size: 659; 188 |
Panel | wzor | Size: 282; 152 BackColor: Black Location: (dowolna na Splitterze) |
Panel | PlanszaGlowna | Size: 282; 152 BackColor: Black Location: (dowolna) |
Dodatkowo musimy dysponować sześcioma kafelkami. Nasza plansza główna będzie miała 25 pól, czyli 6*4=24 + puste pole. Kafelki do pobrania: kafelki
Należy je rozpakować do folderu i montujemy je tak jak na gifie:
Dobra, wszystko jest. Zaczniemy od dodania zmiennych, a następnie będziemy dodawać metody, których działanie będziemy sobie omawiać.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 |
Imports System.Drawing.Drawing2D Public Class Form1 'struktura głównych elementów przesuwalnych Private Structure polaGryS Dim kolor As Integer 'kolor jako index na liście listaKolorow Dim rect As Rectangle Dim x As Integer Dim y As Integer Dim img As Image End Structure Private Structure polaWzoruS Dim kolor As Integer Dim x As Integer Dim y As Integer Dim img As Image End Structure 'tablica wzoru Private polaWzoru(3, 3) As Rectangle 'główna tablica gry Private polaGlowne(4, 4) As Rectangle Private polaGlowneBool(4, 4) As Boolean Dim GlownaMapa As Bitmap 'bitmapa planszy gry (jako tło panelu) Dim WzorMapa As Bitmap 'bitmapa wzoru (jako tło panelu) Dim WielkoscPolaWzor As Integer 'wielkość pola wzoru Dim WielkoscPola As Integer 'wielkość pola głównej planszy Dim poczatek As Boolean = False 'zmienna oddzielająca generowanie wzoru od zmiany wielkości formy Dim listaKoncaGry As New List(Of Integer) 'lista sprawdzająca koniec gry Dim listaKolorow As New List(Of Image) ' lista obrazków (w tym wypadku kolorów) Dim kolekcjaWzor As New Collection 'kolekcja przechowuje elementy pól wzoru 'przechouje listę pól gry (lista a nie kolekcja, ponieważ lista jest bardziej elastyczna) Dim kolekcjapol As New List(Of polaGryS) Dim ran As New Random Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load End Sub End Class |
Musimy zaimportować bibliotekę System.Drawing.Drawing2D której element wykorzystamy do dostosowania wielkości obrazka do wielkości pola. Zaczniemy od przygotowania naszych kafelków, należy je dodać do listy „listaKolorow”, w tym celu utworzymy metodę, która zrobi to przed generowaniem wzoru i pól. Dodaj do projektu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Private Sub wybierzKolory() 'pobiera obrazki ruchomych kwadracików listaKolorow.Add(My.Resources.czerwony2) listaKolorow.Add(My.Resources.bialy2) listaKolorow.Add(My.Resources.niebieski) listaKolorow.Add(My.Resources.pomarancz) listaKolorow.Add(My.Resources.zielony) listaKolorow.Add(My.Resources.zolty) End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'ustawia grę wybierzKolory() ZmianaRozmiaru() poczatek = True End Sub |
Metoda „wybierzKolory()” zapełni nam naszą listę kafelkami. Należy dostosować ilość elementów listy do takiej liczby, aby jej przemnożenie przez ilość możliwości wyboru dawało 24. Teraz możliwość wyboru jednego kafelka to 4, ponieważ 4*6 =24, jeśli chcielibyśmy zwiększyć lub zmniejszyć ilość kafelków musielibyśmy robić to w następujący sposób 6*4=24 lub 8*3=24, 3*8 =24, 2*12=24, 1*24=24 itp. Kiedy załadujemy już sobie listę kafelków, przechodzimy do ustawienia planszy wzoru i głównej planszy gry. Należy dostosować ich wielkości, wielkość planszy wzoru będzie zależna od wielkości Splittera1 a planszy gry od wielkości formy, dodaj metodę do projektu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Private Sub ZmianaRozmiaru() 'Ustawia wielkości pól gry i wzoru wzor.Size = New Size(Splitter1.Height - 10, Splitter1.Height - 10) 'wielkość planszy wzor.Location = New Point((Splitter1.Width - wzor.Width) / 2, 5) ' plansza wzoru zawsze na środku 'Wielkość planszy gry If Me.Width > (Me.Height - Splitter1.Height) Then PlanszaGlowna.Size = New Size((Me.Height - Splitter1.Height) - 60, (Me.Height - Splitter1.Height) - 60) Else PlanszaGlowna.Size = New Size((Me.Width) - 20, (Me.Width) - 20) End If 'lokalizacja na środku PlanszaGlowna.Location = New Point((Me.Width - PlanszaGlowna.Width) / 2, Splitter1.Height + 10) 'generuj pola (wzoru i planszy główenj) GeneratorPol() End Sub |
Wygląda to tak:
Za zmianę w czasie rzeczywistym odpowiedzialna będzie metoda:
1 2 3 4 5 6 |
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize 'włączony dopiero po przygotowaniu gry If poczatek = True Then ZmianaRozmiaru() End If End Sub |
Podczas zmiany wielkości głównej formy, wielkość plansz zostanie zaktualizowana. Zajmijmy się teraz przygotowaniem wzoru i pól gry, aby gra miała sens, pola muszą być generowane losowo. Jeśli chodzi o wzór, jego pola nie będą ulegały zmianie lokalizacji, dlatego ten element będzie bardziej statyczny. Główna plansza gry będzie bardziej złożona, ta przestrzeń będzie składała się z kilku elementów:
PolaGlowneBool- określa lokalizacje pola pustego.
polaGlowne — ich wielkość jest generowana, gdy zmienia się wielkość planszy, w nie wpisujemy obrazki kolorów.
Metoda ta ma dwa stany. Pierwszy jest uruchamiany podczas uruchamiania gry, przygotowuje on obie plansze do gry. Drugi jest, wtedy gdy plansza jest załadowana, a my zmieniamy jej rozmiar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 |
Private Sub GeneratorPol() 'Przygotowuje czystą mapę pól, ich wielkość i położenie ' następnie klonuje tą magę plansz (wzoru i głównej planszy gry) i zapisuje w zmiennych:GlownaMapa ' i WzorMapa ' na których namalujemy odpowiednie kwadraciki Dim GlownaMapaPoczatek As New Bitmap(PlanszaGlowna.Width, PlanszaGlowna.Height) Dim WzorMapaPoczatek As New Bitmap(wzor.Width, wzor.Height) Dim g As Graphics = Graphics.FromImage(GlownaMapaPoczatek) Dim g2 As Graphics = Graphics.FromImage(WzorMapaPoczatek) WielkoscPolaWzor = (wzor.Width / 3) - 3 WielkoscPola = (PlanszaGlowna.Width / 5) - 5 If poczatek = False Then 'generowana na początku, ustawia kwadraty, ich wielkość i polożenie Dim kolorPola As New SolidBrush(Color.FromArgb(60, 240, 240, 240)) For i As Integer = 0 To 4 For j As Integer = 0 To 4 polaGlowne(i, j) = New Rectangle(10 + (WielkoscPola * i), 10 + (WielkoscPola * j), WielkoscPola - 1, WielkoscPola - 1) g.FillRectangle(kolorPola, polaGlowne(i, j)) If Not j >= 3 Then If Not i >= 3 Then polaWzoru(i, j) = New Rectangle(5 + (WielkoscPolaWzor * i), 5 + (WielkoscPolaWzor * j), WielkoscPolaWzor - 1, WielkoscPolaWzor - 1) g2.FillRectangle(kolorPola, polaWzoru(i, j)) End If End If 'tablica polaGlowneBool określa który kwadracik jest pusty, w tym wypadku, prawy dolny róg If Not (i = 4 And j = 4) Then polaGlowneBool(i, j) = False Else polaGlowneBool(i, j) = True End If Next Next Else 'jeśli to nie jest początek gry, zmieniamy tylko wielkość i położenie pól, zmieniamy wielkość pól na ' liście Dim kolorPola As New SolidBrush(Color.FromArgb(60, 240, 240, 240)) For i As Integer = 0 To 4 For j As Integer = 0 To 4 'zmieniamy wielkości w tablicy publicznej polaGlowne(i, j) = New Rectangle(10 + (WielkoscPola * i), 10 + (WielkoscPola * j), WielkoscPola - 1, WielkoscPola - 1) g.FillRectangle(kolorPola, polaGlowne(i, j)) For a As Integer = 0 To kolekcjapol.Count - 1 If i = kolekcjapol(a).x And j = kolekcjapol(a).y Then 'przypisujemy zmienione pole do listy stuktury Dim p As polaGryS = kolekcjapol(a) p.rect = polaGlowne(i, j) kolekcjapol(a) = p End If Next Next Next End If 'ustawiamy tło paneli GlownaMapa = GlownaMapaPoczatek.Clone WzorMapa = WzorMapaPoczatek.Clone g.Dispose() g2.Dispose() 'Jeśli jest to początek gry, należy przygotować wzór i losowo wyłożyć kolory If poczatek = False Then generujWzor() Else 'jeśli nie jest to początek, należy wtedy poustawiać odpowiednio kolory UzupelnijWzor() End If End Sub |
Chwilowo nic się jeszcze nie dzieje, ponieważ przygotowaliśmy tylko pola główne i określiliśmy ich wielkość. Jeśli dodamy sobie dwie linijki kodu, to zobaczymy, co zostało zrobione:
1 2 |
wzor.BackgroundImage = WzorMapa PlanszaGlowna.BackgroundImage = GlownaMapa |
Zajmiemy się teraz metodą „generujWzor()” która ładuje kafelki na plansze i przygotowuje puste pole:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 |
Private Sub generujWzor() ' Pierwszym etapem jest wygenerowanie wzoru do ułożenia i zapełnienie kolecji wzoru i listy pól 'inicjujemy struktury Dim polaW As polaWzoruS Dim polaG As polaGryS 'tworzymy chwilowe bitmapy, aby nie uszkodzić bitmapy oustej Dim chwilowaWzor As Bitmap = WzorMapa.Clone Dim chwilowaPola As Bitmap = GlownaMapa.Clone Dim gr_dest As Graphics = Graphics.FromImage(chwilowaWzor) Dim gr_dest2 As Graphics = Graphics.FromImage(chwilowaPola) Dim listaWylosowana(5) As Integer ' tablica będzie pilnowała aby kolorów nie było więcej niż 4 'zaczynamy od stworzenia wzoru 3x3 For i As Integer = 0 To 2 For j As Integer = 0 To 2 'losujemy kolor Dim randomowy As Integer Do randomowy = ran.Next(0, 6) 'jeśli już mamy trzy wylosowane takie kolory, wtedy losujemy ponownie If listaWylosowana(randomowy) + 1 <= 4 Then Exit Do End If Loop 'wypełniamy strukturę danymi polaW.x = i polaW.y = j polaW.kolor = randomowy polaW.img = ZmienRozmiar(listaKolorow(randomowy), New Size(WielkoscPolaWzor, WielkoscPolaWzor)) listaKoncaGry.Add(randomowy) listaWylosowana(randomowy) += 1 'uzupelniamy listę pilnującą ilości kolorów 'rysujemy element gr_dest.DrawImage(polaW.img, polaWzoru(i, j).Location.X, polaWzoru(i, j).Location.Y, polaW.img.Width - 1, polaW.img.Height - 1) kolekcjaWzor.Add(polaW) ' uzupełniamy kolekcję Next Next 'tworzymy tablicę 5x5 'czyścimy tablicę ReDim listaWylosowana(5) ' tablica będzie pilnowała aby kolorów nie było więcej niż 4 For i As Integer = 0 To 4 For j As Integer = 0 To 4 'uzupełnia tylko pola false, zostawi jedno pole czyste If polaGlowneBool(i, j) = False Then 'losujemy kolor Dim randomowy As Integer Do randomowy = ran.Next(0, 6) If listaWylosowana(randomowy) + 1 <= 4 Then Exit Do End If Loop 'wypełniamy strukturę danymi polaG.rect = polaGlowne(i, j) polaG.x = i polaG.y = j polaG.kolor = randomowy polaG.img = ZmienRozmiar(listaKolorow(randomowy), New Size(WielkoscPola, WielkoscPola)) listaWylosowana(randomowy) += 1 'uzupelniamy listę pilnującą ilości kolorów 'rysujemy element gr_dest2.DrawImage(polaG.img, polaGlowne(i, j).Location.X, polaGlowne(i, j).Location.Y, polaG.img.Width - 1, polaG.img.Height - 1) kolekcjapol.Add(polaG) ' uzupełniamy listę End If Next Next 'Ustawiamy nowe tła panaeli wzor.Image = chwilowaWzor PlanszaGlowna.Image = chwilowaPola End Sub |
Zmienna „randomowy„ odpowiedzialna jest za wylosowanie kafelka, „listaWylosowana„ pilnuje za to, aby jednego rodzaju kafelka nie było więcej niż cztery. Jeśli chcesz zwiększyć lub zmniejszyć ilość kafelków, musisz zmienić te opcje odpowiednio do ilości kafelków, które posiadasz. W zależności od wielkości pól musimy przygotować tak obrazki naszych kafelków tak, aby był wielkości wcześniej określonego pola. Czyli należy zmniejszyć lub zwiększyć jego rozmiar. Odpowiedzialna jest za to funkcja „ZmienRozmiar()„, która wykorzystuje do zmiany rozmiaru bibliotekę System.Drawing.Drawing2D.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Public Shared Function ZmienRozmiar(ByVal obrazek As Image, ByVal wielkosc As Size, Optional ByVal _ ZachowajProporcjeObrazu As Boolean = True) As Image Dim NowaSzerokosc As Integer Dim NowaWysokosc As Integer 'Określamy wielkość nowego obrazku, w zależności czy proporcje mają być zachowane If ZachowajProporcjeObrazu Then Dim OgyginalnaSzerokosc As Integer = obrazek.Width Dim OryginalnaWysokosc As Integer = obrazek.Height Dim SzerokoscProcent As Single = CSng(wielkosc.Width) / CSng(OgyginalnaSzerokosc) Dim WysokoscProcent As Single = CSng(wielkosc.Height) / CSng(OryginalnaWysokosc) Dim Procent As Single = If(WysokoscProcent < SzerokoscProcent, WysokoscProcent, SzerokoscProcent) NowaSzerokosc = CInt(OgyginalnaSzerokosc * Procent) NowaWysokosc = CInt(OryginalnaWysokosc * Procent) Else NowaSzerokosc = wielkosc.Width NowaWysokosc = wielkosc.Height End If Dim NowyObrazek As Image = New Bitmap(NowaSzerokosc, NowaWysokosc) 'generujemy nowy obrazek Using graphicsHandle As Graphics = Graphics.FromImage(NowyObrazek) graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic graphicsHandle.DrawImage(obrazek, 0, 0, NowaSzerokosc, NowaWysokosc) End Using 'funkcja zwraca NowyObrazek Return NowyObrazek End Function |
Zobaczmy jak to wszystko działa:
Jak widzimy, pola są już dodane, lecz nasze pola nie dostosowują się do wielkości formy, ponieważ podczas wywołania metody „Form1_Resize„ mamy już zmienną „poczatek„ ustawioną na wartość „true„ co oznacza, że jeśli zmieniamy rozmiar formy, wywoływana jest metoda „UzupelnijWzor()„, jeśli podczas zmiany rozmiaru wywoływana byłaby metoda „generujWzor()„ wtedy podczas każdej zmiany, program generowałby nowy losowy wzór i nowe losowe pola. Dodajmy więc metodę „UzupelnijWzor()„:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
Private Sub UzupelnijWzor() 'metoda zmienia rozmiary gry wzór i plansza są już wygenerowane Dim chwilowaWzor As Bitmap = WzorMapa.Clone Dim chwilowaPola As Bitmap = GlownaMapa.Clone Dim gr_dest As Graphics = Graphics.FromImage(chwilowaWzor) Dim gr_dest2 As Graphics = Graphics.FromImage(chwilowaPola) 'najpierw rysujemy kolory wzoru na podstawie zmienionych wielkości pól 'mimo iż nic zabardzo się tu nie zmienia (przez budowe formy) dodaje go może komuś się przyda 'nic nie psuje, można go usunąc For i As Integer = 0 To 2 For j As Integer = 0 To 2 For a As Integer = 1 To kolekcjaWzor.Count If i = kolekcjaWzor(a).x And j = kolekcjaWzor(a).y Then Dim myimage As Image = ZmienRozmiar(kolekcjaWzor(a).img, New Size(WielkoscPolaWzor, WielkoscPolaWzor)) gr_dest.DrawImage(myimage, polaWzoru(i, j).Location.X, polaWzoru(i, j).Location.Y, myimage.Width - 1, myimage.Height - 1) End If Next Next Next wzor.Image = chwilowaWzor 'ustawiamy tło panelu wzoru 'następnie rysujemy kolory pól głównej planszy na podstawie zmienionych wielkości pól For i As Integer = 0 To 4 For j As Integer = 0 To 4 If polaGlowneBool(i, j) = False Then For a As Integer = 0 To kolekcjapol.Count - 1 If i = kolekcjapol(a).x And j = kolekcjapol(a).y Then Dim myimage As Image = ZmienRozmiar(kolekcjapol(a).img, New Size(WielkoscPola, WielkoscPola)) gr_dest2.DrawImage(myimage, kolekcjapol(a).rect.Location.X, kolekcjapol(a).rect.Location.Y, myimage.Width - 1, myimage.Height - 1) End If Next End If Next Next PlanszaGlowna.Image = chwilowaPola KoniecGry() End Sub |
Etap pierwszy metody, tak naprawdę nic nie robi, gdyż plansza wzoru jest nieruchoma, drugi etap ustawia kafelki na podstawie „kolekcjipol„ w której zapisane są koordynaty pól, ich wielkość i obrazki. Nie działa już tylko ostatni element, który kontroluje czy gra już dobiegła końca:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
Private Sub KoniecGry() 'Metoda sprawdza koniec gry Dim graWygrana As Boolean = True 'zakładamy, że to koniec Dim listaPorownawcza As New List(Of Integer) ' lista przechowująca 'numery kolorów środka głównej planszy 'pobiera numey kolorów środka gry For i As Integer = 1 To 3 For j As Integer = 1 To 3 For k As Integer = 0 To kolekcjapol.Count - 1 If kolekcjapol(k).x = i And kolekcjapol(k).y = j Then listaPorownawcza.Add(kolekcjapol(k).kolor) End If Next Next Next ' jeśli na środku nie znajduje się puste pole, metoda przechodzi do 'porównania list If listaPorownawcza.Count = listaKoncaGry.Count Then For i As Integer = 0 To listaKoncaGry.Count - 1 If Not listaKoncaGry(i) = listaPorownawcza(i) Then 'listy nie są identyczne, koniec porównania graWygrana = False Exit For End If Next If graWygrana = True Then 'listy są jednakowe PlanszaGlowna.Enabled = False MsgBox("Koniec gry, ułożyłeś układanke") End If End If End Sub |
Tworzy ona listę porównawczą, w której przechowuje indeksy obrazków w liście „listaKolorow„. Następnie porównuje je i jeśli są identyczne (wzór — środek planszy gry) kończy grę.
Oczywiście nie jest to koniec projektu, ponieważ jakoś musimy te kafelki przesuwać. Zaczniemy od klawiszy funkcyjnych. Ja użyje strzałek, lecz ty możesz wybrać inne klawisze. Musisz się zastanowić, jak będzie ci najwygodniej, jeśli przyciśniesz strzałkę w górę to który kafelek przesuniesz? Możesz przesunąć kafelek pod pustym polem w górę lub powyżej pustego pola w dół, moja konfiguracja:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 |
Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown 'poruszanie za pomocą klawiszy, strzałek Dim lokalizacjaI As Integer Dim lokalizacjaJ As Integer 'pobieramy lokalizację pustego pola For i As Integer = 0 To 4 For j As Integer = 0 To 4 If polaGlowneBool(i, j) = True Then lokalizacjaI = i lokalizacjaJ = j End If Next Next 'jeśli to nie jst koniec gry, wtedy sprawdzamy który klawisz został użyty If PlanszaGlowna.Enabled = True Then If e.KeyCode = Keys.Down Then 'klawisz w dół If Not lokalizacjaJ = 0 Then 'jeśli byłoby mniejsze od 0 wtedy wyszło by poza tablicę For a As Integer = 0 To kolekcjapol.Count - 1 'pobiera lokalizację pola powyżej pola pustego If lokalizacjaI = kolekcjapol(a).x And (lokalizacjaJ - 1) = kolekcjapol(a).y Then ' i zmienia je na nowe Dim p As polaGryS = kolekcjapol(a) p.y = lokalizacjaJ p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(a) = p 'nadpisuje element na liście End If Next 'zmienia wartość logiczną pola polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI, lokalizacjaJ - 1) = True End If ElseIf e.KeyCode = Keys.Up Then If Not lokalizacjaJ = 4 Then 'jeśli byłoby większe od 4 wtedy wyszło by poza tablicę For a As Integer = 0 To kolekcjapol.Count - 1 If lokalizacjaI = kolekcjapol(a).x And (lokalizacjaJ + 1) = kolekcjapol(a).y Then Dim p As polaGryS = kolekcjapol(a) p.y = lokalizacjaJ p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(a) = p End If Next polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI, lokalizacjaJ + 1) = True End If ElseIf e.KeyCode = Keys.Right Then If Not lokalizacjaI = 0 Then 'jeśli byłoby mniejsze od 0 wtedy wyszło by poza tablicę For a As Integer = 0 To kolekcjapol.Count - 1 If (lokalizacjaI - 1) = kolekcjapol(a).x And lokalizacjaJ = kolekcjapol(a).y Then Dim p As polaGryS = kolekcjapol(a) p.x = lokalizacjaI p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(a) = p End If Next polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI - 1, lokalizacjaJ) = True End If ElseIf e.KeyCode = Keys.Left Then If Not lokalizacjaI = 4 Then 'jeśli byłoby większe od 4 wtedy wyszło by poza tablicę For a As Integer = 0 To kolekcjapol.Count - 1 If (lokalizacjaI + 1) = kolekcjapol(a).x And lokalizacjaJ = kolekcjapol(a).y Then Dim p As polaGryS = kolekcjapol(a) p.x = lokalizacjaI p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(a) = p End If Next polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI + 1, lokalizacjaJ) = True End If End If End If 'rysuje nowe kolory UzupelnijWzor() End Sub |
Moje ustawienia w stosunku do pustego pola to:
Strzałka w dół
Strzałka w górę
Strzałka w lewo
Strzałka w prawo
Kod pobiera lokalizację pustego pola na podstawie tablicy „polaGlowneBool” i lokalizuje pole według wciśniętego klawisza. Następnie klonuje strukturę i zmienia jej pole x lub y i zajmowane pole (rect).
Trochę trudniej będzie z kursorem myszy. Dodajemy do panelu „PlanszaGlowna„ zdarzenie „MouseMove„, kiedy kursor myszy znajdzie się nad panelem, pobrane zostaną koordynaty kursora e.x i e.y. Następnie poprzez określenie lokalizacji pustego pola przeszukujemy kolekcję „kolekcjapol„ i sprawdzamy, czy kursor nie znajduje się nad polem (rect) po lewej, prawej, powyżej lub poniżej. Jeśli znajduje się, wtedy kursor zamieni wygląd na rączkę, jeśli nie na strzałkę.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
'kliknięcie myszą Private Sub PlanszaGlowna_MouseMove(sender As Object, e As MouseEventArgs) Handles PlanszaGlowna.MouseMove 'Aby była możliwość wybrania pola za pomocą lewego przycisku myszy, należy najpierw 'określić nad którym polem znajduje się kursor myszy Dim lokalizacjaI As Integer Dim lokalizacjaJ As Integer For i As Integer = 0 To 4 For j As Integer = 0 To 4 If polaGlowneBool(i, j) = True Then lokalizacjaI = i lokalizacjaJ = j End If Next Next For i As Integer = 0 To kolekcjapol.Count - 1 If (kolekcjapol(i).rect.Location.X - 2 <= e.X And (kolekcjapol(i).rect.Location.X + kolekcjapol(i).rect.Width + 2 >= e.X)) _ And (kolekcjapol(i).rect.Location.Y - 2 <= e.Y And (kolekcjapol(i).rect.Location.Y + kolekcjapol(i).rect.Height + 2 >= e.Y)) Then 'jeśli kursor znajduje się po lewej lub po prawj stronie pustego pola, kursor zmieni rodzaj na rączkę If (kolekcjapol(i).x - 1 = lokalizacjaI Or kolekcjapol(i).x + 1 = lokalizacjaI) And kolekcjapol(i).y = lokalizacjaJ Then Me.Cursor = Cursors.Hand Exit For End If 'jeśli kursor znajduje się powyżej lub poniżej stronie pustego pola, kursor zmieni rodzaj na rączkę If (kolekcjapol(i).y - 1 = lokalizacjaJ Or kolekcjapol(i).y + 1 = lokalizacjaJ) And kolekcjapol(i).x = lokalizacjaI Then Me.Cursor = Cursors.Hand Exit For End If Else 'kursor pozostanie strzałką lub zmieni rodzaj na strzałkę jeśli nie spelnione są powyższe warunki Me.Cursor = Cursors.Arrow End If Next End Sub |
Efekt taki jak na gifie poniżej:
Jak widzicie, kursor zmienia swój stan na rączkę. Jeśli chodzi o metodę kliknięcia, jest ona taka sama jak podczas użycia klawiszy. Metoda sprawdza, czy kursor jest nad polem sąsiadującym z pustym polem (kod skopiowany z MouseMove), jeśli tak to określa, który kwadrat i klonuje jego strukturę, podmienia dane z pustym polem i zapisuje w kolekcji.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 |
Private Sub PlanszaGlowna_MouseClick(sender As Object, e As MouseEventArgs) Handles PlanszaGlowna.MouseClick Dim lokalizacjaI As Integer Dim lokalizacjaJ As Integer 'pobiera lokalizację pustego pola For i As Integer = 0 To 4 For j As Integer = 0 To 4 If polaGlowneBool(i, j) = True Then lokalizacjaI = i lokalizacjaJ = j End If Next Next 'sprawdza nad którym polem jest kursor For i As Integer = 0 To kolekcjapol.Count - 1 If (kolekcjapol(i).rect.Location.X - 2 <= e.X And (kolekcjapol(i).rect.Location.X + kolekcjapol(i).rect.Width + 2 >= e.X)) And (kolekcjapol(i).rect.Location.Y - 2 <= e.Y _ And (kolekcjapol(i).rect.Location.Y + kolekcjapol(i).rect.Height + 2 >= e.Y)) Then 'jeśli zostalo kliknięte pole po prawej stronie pustego pola If kolekcjapol(i).x + 1 = lokalizacjaI And kolekcjapol(i).y = lokalizacjaJ Then 'pobierze strukture pola z listy Dim p As polaGryS = kolekcjapol(i) ' zmieni jego lokalizację x p.x = lokalizacjaI 'przypisze nowy kwadrat p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) 'nadpisze nową strukture w liście kolekcjapol(i) = p 'ustawi nowe miejsce true i false polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI - 1, lokalizacjaJ) = True End If 'jeśli zostalo kliknięte pole po lewej stronie pustego pola If kolekcjapol(i).x - 1 = lokalizacjaI And kolekcjapol(i).y = lokalizacjaJ Then Dim p As polaGryS = kolekcjapol(i) p.x = lokalizacjaI p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(i) = p polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI + 1, lokalizacjaJ) = True End If 'jeśli zostalo kliknięte pole jest powyżej pustego pola If kolekcjapol(i).y - 1 = lokalizacjaJ And kolekcjapol(i).x = lokalizacjaI Then Dim p As polaGryS = kolekcjapol(i) p.y = lokalizacjaJ p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(i) = p polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI, lokalizacjaJ + 1) = True End If 'jeśli zostalo kliknięte pole jest poniżej pustego pola If kolekcjapol(i).y + 1 = lokalizacjaJ And kolekcjapol(i).x = lokalizacjaI Then Dim p As polaGryS = kolekcjapol(i) p.y = lokalizacjaJ p.rect = polaGlowne(lokalizacjaI, lokalizacjaJ) kolekcjapol(i) = p polaGlowneBool(lokalizacjaI, lokalizacjaJ) = False polaGlowneBool(lokalizacjaI, lokalizacjaJ - 1) = True End If End If Next UzupelnijWzor() End Sub |
Dobra gra gotowa:
Teraz wasza kolej, twórzcie dodawajcie i modyfikujcie ile chcecie. Stwórzcie grę taką jaką chcecie aby była.
Pełen projekt do pobrania tutaj: MagicznaUkladanka.zip
English: Magic_blocks.zip