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ć.
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:
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:
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:
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.
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:
wzor.BackgroundImage = WzorMapa
PlanszaGlowna.BackgroundImage = GlownaMapa
Zajmiemy się teraz metodą „generujWzor()” która ładuje kafelki na plansze i przygotowuje puste pole:
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.
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()„:
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:
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:
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ę.
'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.
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

