Aplikacja do przetestowania: Tangram
Czym jest tangram? Ja pierwszy raz jak zobaczyłem tą prostą grę stwierdziłem, że to gra dla dzieci i nic w niej skomplikowanego nie ma. Trochę się pomyliłem w tych ocenach i podczas tworzenia tego małego projektu, rozrósł się on do dużego projektu. Przeszkody na które natrafiłem musiałem jakoś przeskoczyć a gdzieniegdzie wymagało to ode mnie dużego kombinowania i pomysłowości. Gra będzie wyglądała tak jak na gifie:
Prawym przyciskiem myszy, będziemy obracać nasze obiekty. Zaczynamy więc od stworzenia formy:
![]() |
|
Poniżej opis ułożenia elementów w panelu 2, który będzie zawierał przyciski i wzór do wykonania.
Reszta elementów, będzie tworzona w sposób dynamiczny. Nasza gra będzie się składać z Formy, modułu i jednej klasy:
- Form1 – forma
- GenerujKsztalty – klasa
- PubliczneElementy – moduł
Czy taka hierarchia jest potrzebna? Oczywiście nie, wszystko można wrzucić do jednej formy i też będzie działać ale tak jest bardziej schludnie i przejrzyście.
Klasa GenerujKsztalty będzie tworzyć nam nasze elementy (głównie bitmapy) i strukturę a moduł PubliczneElementy będzie przechowywał listę wzorów i naszą strukturę. Zaczniemy od przygotowania planszy, to na niej odbywać będzie się gra i nie jest powiązana z innymi elementami, po prostu generuje obrazek tła formy dlatego ją dodamy sobie na początku. Kiedy forma jest już przygotowana, przechodzimy do jej kodu (F7).
Public Class Form1
Dim trzymany As Integer = 0 'przechowuje aktualny indeks (na liście kolekcjaElementow) trzymanego obiektu
Dim jestWRuchu As Boolean = False 'wskazuje, czy trzymamy jakiś obiekt
Dim GenerujKsztalty As New GenerujKsztalty 'inicjujemy nową klasę
Dim ran As New Random 'wartość losowa
Dim WybranyWzor As Integer(,) 'tablica położenia elementów wybranego wzoru
Dim kolekcjaElementow As New List(Of ksztalt) 'przechowuje struktury
Dim miejsceNamalowaniaKwadratu As Point 'punkt rysowania planszy
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
PrzygotujTapete()
' kolekcjaElementow = GenerujKsztalty.GenerujElementyGry()
' PrzygotujWzory()
End Sub
Dim listaKwadratow(5, 5) As Rectangle 'przechowuje obiekty rectangle naszej planszy
Private Sub PrzygotujTapete()
Dim tapeta As New Bitmap(Me.Width, Me.Height)
Dim g As Graphics = Graphics.FromImage(tapeta)
'podział formy na prawą i lewą stronę
'jasny szary
g.FillRectangle(New SolidBrush(Color.FromArgb(224, 224, 224)),
New Rectangle(0, 0, Me.Width - 74 - 400, Me.Height))
'ciemny szary
g.FillRectangle(New SolidBrush(Color.Gray), New Rectangle(Me.Width - 74 - 400, 0, 74 + 400, Me.Height))
'Wielkość planszy ustalamy na 480x480
'pole będzie miało wymiar 80x80
'tło planszy (musi być białe!)
g.FillRectangle(New SolidBrush(Color.White), New Rectangle((Me.Width - 274 - 680) / 2,
(Me.Height - 680) / 2, 480, 480))
'przygotowujemy linie kropkowaną
Dim dashValues As Single() = {5, 2, 5, 4}
Dim blackPen As New Pen(Color.Black, 2)
blackPen.DashPattern = dashValues
'rysujemy za jej pomocą linie dzielące pola
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2 + 80, (Me.Height - 680) / 2),
New Point((Me.Width - 274 - 680) / 2 + 80, (Me.Height - 680) / 2 + 480))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2 + 160, (Me.Height - 680) / 2),
New Point((Me.Width - 274 - 680) / 2 + 160, (Me.Height - 680) / 2 + 480))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2 + 240, (Me.Height - 680) / 2),
New Point((Me.Width - 274 - 680) / 2 + 240, (Me.Height - 680) / 2 + 480))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2 + 320, (Me.Height - 680) / 2),
New Point((Me.Width - 274 - 680) / 2 + 320, (Me.Height - 680) / 2 + 480))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2 + 400, (Me.Height - 680) / 2),
New Point((Me.Width - 274 - 680) / 2 + 400, (Me.Height - 680) / 2 + 480))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2 + 80),
New Point((Me.Width - 274 - 680) / 2 + 480, (Me.Height - 680) / 2 + 80))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2 + 160),
New Point((Me.Width - 274 - 680) / 2 + 480, (Me.Height - 680) / 2 + 160))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2 + 240),
New Point((Me.Width - 274 - 680) / 2 + 480, (Me.Height - 680) / 2 + 240))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2 + 320),
New Point((Me.Width - 274 - 680) / 2 + 480, (Me.Height - 680) / 2 + 320))
g.DrawLine(blackPen, New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2 + 400),
New Point((Me.Width - 274 - 680) / 2 + 480, (Me.Height - 680) / 2 + 400))
Dim x As Integer = (Me.Width - 274 - 680) / 2
Dim y As Integer = (Me.Height - 680) / 2
'Rysujemy pola któr będą ułatwiać grę poprzez auto ułożenie elementów w momęcie ich ułożenia
'więcej na ten temat powiem na blogu
For j As Integer = 0 To 5
For i As Integer = 0 To 5
listaKwadratow(i, j) = New Rectangle((x - 40) + i * 80, (y - 40) + j * 80, 80, 80)
'Dim pan As New Panel
'pan.Location = New Point((x - 40) + i * 80, (y - 40) + j * 80)
'pan.BackColor = Color.Transparent
'pan.BorderStyle = BorderStyle.Fixed3D
'pan.Size = New Size(80, 80)
'Me.Controls.Add(pan)
Next
Next
'rusujemy ramkę pola gry
Dim thickRedPen As Pen = New Pen(Color.Tomato, 5)
g.DrawRectangle(thickRedPen, New Rectangle((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2, 480, 480))
'pobieramy punkt rysowania planszy, potrzebny nam będzie do sprawdzenia czy wszystkie elementy zostały
'ułożone i nie zostawiliśmy pustych pól
miejsceNamalowaniaKwadratu = New Point((Me.Width - 274 - 680) / 2, (Me.Height - 680) / 2)
'ustawiamy tapetę formy
Me.BackgroundImage = tapeta
End Sub
End Class
Co tu się dzieje i co jest co? Po pierwsze, trzeba tutaj napomknąć, że jest to zwykłe malowanie/dodawanie grafiki do/na bitmapę. Najpierw inicjujemy bitmapę, w tym wypadku jest to zmienna „tapeta” na którą nanosimy elementy graficzne przy użyciu zmiennej „g”, na samym końcu ustawiamy bitmapę „tapeta” jako tło formy. Tutaj na szczególną uwagę zasługuje utworzona tablica obiektów „Rectangle”:
Dim listaKwadratow(5, 5) As Rectangle 'przechowuje obiekty rectangle naszej planszy
Posłuży nam ona do równania położonych obiektów. Aby to zobaczyć, odblokujcie elementy w 57 linijce:
For j As Integer = 0 To 5
For i As Integer = 0 To 5
listaKwadratow(i, j) = New Rectangle((x - 40) + i * 80, (y - 40) + j * 80, 80, 80)
Dim pan As New Panel
pan.Location = New Point((x - 40) + i * 80, (y - 40) + j * 80)
pan.BackColor = Color.Transparent
pan.BorderStyle = BorderStyle.Fixed3D
pan.Size = New Size(80, 80)
Me.Controls.Add(pan)
Next
Next
teraz na naszą formę nałożone zostaną przezroczyste panele:
Pod tymi panelami, są obiekty „Rectangle” które będziemy wykorzystywać do centrowania położonych elementów. Spójżcie na obrazek poniżej, przedstawia on sytuacje w której trzymany jest obiekt 1 (trzymane obiekty podświetlają się na czarno). Ciężko jest umieścić go tak aby był na odpowiednim miejscu, co do pixela.
Punkt (0,0) naszego trójkąta jest na obszarze żółtego kwadratu, i to do tego kwadratu nastąpi wyrównanie. Po położeniu obiektu, zostanie on wyrównany do środka tego kwadratu.
To zapewni nam, że ostateczna forma będzie zwarta i będzie tworzyć całość. Potrzebne będzie to do końcowego porównania. Kiedy mamy już gotowe te elementy, odblokujcie element „PrzygotujWzory()”:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
PrzygotujTapete()
' kolekcjaElementow = GenerujKsztalty.GenerujElementyGry()
PrzygotujWzory()
End Sub
Przechodzimy sobie teraz do naszego Modułu „PubliczneElement”
Module PubliczneElement
'Trzworzymy elementy naszej struktury
Public Structure ksztalt
Dim ksztalt As Rectangle
Dim bitmap As Bitmap
Dim wartosc As Integer
Dim kat As Integer
Dim polozenie As Integer()
End Structure
'przechowuje wybrany kształt
Public KsztaltyWzory As New List(Of Integer(,))
'lista wzorów
Sub PrzygotujWzory()
KsztaltyWzory.Add({{12, 0, 4, 3}, {11, 0, 3, 0}, {11, 1, 4, 0}, {12, 2, 2, 3},
{13, 4, 1, 0}, {13, 3, 1, 2}, {1, 0, 0, 3}, {1, 0, 2, 2},
{3, 1, 0, 1}, {3, 2, 0, 6}, {4, 4, 0, 4}, {2, 5, 2, 2}, {2, 2, 5, 1}, {4, 2, 3, 7}})
KsztaltyWzory.Add({{12, 0, 4, 0}, {13, 0, 3, 0}, {13, 1, 2, 0}, {12, 0, 2, 2},
{11, 2, 1, 0}, {11, 3, 0, 0}, {2, 2, 2, 0}, {4, 2, 3, 2},
{3, 3, 2, 2}, {3, 4, 2, 5}, {1, 4, 4, 0}, {1, 4, 0, 1}, {2, 0, 0, 3}, {4, 0, 0, 1}})
KsztaltyWzory.Add({{11, 0, 3, 0}, {11, 1, 2, 0}, {12, 2, 0, 3}, {13, 2, 3, 3},
{12, 0, 4, 3}, {13, 1, 5, 1}, {3, 0, 1, 7}, {1, 0, 0, 2},
{1, 4, 0, 1}, {3, 2, 0, 6}, {2, 2, 2, 3}, {4, 1, 4, 3}, {4, 4, 3, 6}, {2, 5, 2, 2}})
KsztaltyWzory.Add({{11, 1, 2, 0}, {13, 4, 1, 0}, {12, 2, 2, 1}, {13, 2, 1, 3},
{12, 3, 3, 0}, {11, 0, 1, 0}, {2, 5, 2, 2}, {2, 2, 5, 1},
{3, 2, 3, 7}, {1, 0, 4, 0}, {3, 0, 2, 3}, {1, 0, 0, 2}, {4, 2, 0, 5}, {4, 4, 0, 4}})
KsztaltyWzory.Add({{13, 0, 1, 3}, {13, 0, 2, 1}, {12, 1, 3, 2}, {11, 2, 3, 0},
{12, 2, 4, 0}, {11, 4, 3, 0}, {1, 4, 4, 0}, {4, 0, 0, 5},
{3, 0, 4, 0}, {2, 0, 2, 0}, {2, 5, 0, 2}, {1, 2, 0, 1}, {4, 4, 0, 0}, {3, 2, 2, 6}})
KsztaltyWzory.Add({{11, 4, 3, 0}, {12, 4, 4, 0}, {11, 3, 4, 0}, {13, 0, 0, 1},
{13, 0, 0, 2}, {12, 1, 1, 2}, {1, 2, 0, 1}, {2, 1, 2, 1},
{4, 0, 2, 1}, {2, 0, 5, 1}, {4, 0, 4, 5}, {3, 2, 3, 2}, {1, 4, 0, 2}, {3, 4, 1, 1}})
KsztaltyWzory.Add({{11, 3, 0, 0}, {1, 4, 0, 1}, {12, 4, 2, 1}, {11, 3, 2, 0},
{12, 2, 2, 3}, {13, 0, 5, 3}, {13, 4, 3, 0}, {2, 0, 2, 0},
{4, 1, 2, 6}, {1, 2, 4, 1}, {4, 4, 3, 2}, {3, 1, 1, 6}, {2, 0, 0, 3}, {3, 0, 0, 3}})
KsztaltyWzory.Add({{12, 2, 2, 3}, {11, 4, 3, 0}, {11, 1, 0, 0}, {12, 0, 4, 3},
{13, 1, 5, 1}, {13, 0, 2, 2}, {4, 0, 0, 0}, {2, 1, 1, 0},
{4, 3, 4, 7}, {2, 1, 4, 1}, {1, 2, 0, 1}, {3, 2, 2, 6}, {3, 4, 1, 1}, {1, 4, 0, 2}})
KsztaltyWzory.Add({{12, 0, 4, 3}, {12, 4, 4, 0}, {13, 2, 4, 1}, {11, 2, 1, 0},
{13, 2, 5, 3}, {11, 1, 4, 0}, {1, 2, 0, 2}, {1, 2, 2, 0},
{3, 4, 2, 3}, {4, 4, 0, 0}, {2, 5, 0, 2}, {2, 0, 0, 0}, {4, 0, 0, 4}, {3, 0, 2, 5}})
KsztaltyWzory.Add({{11, 1, 0, 0}, {13, 2, 1, 0}, {11, 2, 3, 0}, {13, 5, 2, 0},
{12, 2, 4, 0}, {12, 3, 3, 1}, {1, 4, 4, 0}, {3, 0, 4, 0},
{2, 0, 2, 0}, {2, 1, 1, 0}, {4, 0, 0, 0}, {4, 2, 0, 4}, {3, 3, 1, 0}, {1, 4, 0, 2}})
End Sub
End Module
Struktura to po prostu nasz nowy obiekt składający się ze zmiennych. Tutaj na uwagę zasługuje element tworzący listę wzorów. Każdy wzór, który musimy ułożyć posiada listę elementów, ich położenie (współrzędne) i wartość obrotu w prawo.
Potrzeba aż tylu elementów, ponieważ nasz zbiór będzie również przechowywał potencjalny sposób ułożenia elementów:
Teraz zajmiemy się początkowym ułożeniem elementów, czyli generowaniem kształtów do układania. Odblokujcie:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
PrzygotujTapete()
kolekcjaElementow = GenerujKsztalty.GenerujElementyGry()
PrzygotujWzory()
End Sub
Obiekty będziemy dzielić na dwie grupy, czerwone i turkusowe. Czerwonych jest 6 a turkusowych 8. Turkusowe będą miały wartość od 1-4 a czerwone od 11-13. Aby móc namalować obiekt należy stworzyć dwa elementy, kształt (Rectangle) i obrazek (Bitmap). Wszystko to przygotujemy ręcznie. Każdego elementu jest po dwie sztuki. Gotowe elementy będziemy przechowywać na liście „kolekcjaElementow”.
Public Class GenerujKsztalty
Public Function GenerujElementyGry()
Dim coll As New List(Of ksztalt)
Dim bitmMain As Bitmap
Dim g As Graphics
'kolor ramki
Dim penRed As New Pen(Brushes.Tomato)
Dim penTur As New Pen(Brushes.PaleTurquoise)
'szerokość ramki
penRed.Width = 2
penTur.Width = 2
Dim k As New ksztalt 'struktura
'figury 1
For i As Integer = 0 To 1
'tworzymy nową bitmapę o określonej wielkości
bitmMain = New Bitmap(160, 160)
g = Graphics.FromImage(bitmMain)
'rysujemy wypełniony kształt
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0), New Point(80, 80),
New Point(160, 0), New Point(160, 160), New Point(0, 160)})
'rysujemy ramkę
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(80, 80), New Point(160, 0),
New Point(160, 160), New Point(0, 160)})
'dodajemy bitmapę do struktury
k.bitmap = bitmMain
k.kat = 0 'kąt startowy
'określamy startowe położenie obiektu i jego wielkość
k.ksztalt = New Rectangle(765 + 10 * i, 560, 160, 160)
'numer kształtu
k.wartosc = 1
'dodajemy do listy którą zwróci nasza funkcja
coll.Add(k)
Next
'figury 2
For i As Integer = 0 To 1
bitmMain = New Bitmap(80, 320)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0), New Point(80, 80),
New Point(80, 240), New Point(0, 320)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(80, 80),
New Point(80, 240), New Point(0, 320)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(640 + 10 * i, 420, 80, 320)
k.wartosc = 2
coll.Add(k)
Next
'figury 3
For i As Integer = 0 To 1
bitmMain = New Bitmap(240, 160)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 160), New Point(160, 0),
New Point(240, 80), New Point(160, 160), New Point(0, 160)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 160), New Point(160, 0),
New Point(240, 80), New Point(160, 160), New Point(0, 160)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(830 + 10 * i, 330 + 10 * i, 240, 160)
k.wartosc = 3
coll.Add(k)
Next
'figury 4
For i As Integer = 0 To 1
bitmMain = New Bitmap(160, 240)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0), New Point(160, 0),
New Point(80, 80), New Point(80, 240), New Point(0, 160)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(160, 0), New Point(80, 80),
New Point(80, 240), New Point(0, 160)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(727 + 10 * i, 290 + 10 * i, 160, 240)
k.wartosc = 4
coll.Add(k)
Next
'figury 11
For i As Integer = 0 To 1
bitmMain = New Bitmap(160, 160)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(80, 0), New Point(160, 80),
New Point(80, 160), New Point(0, 80)})
g.DrawPolygon(penRed, New PointF() {New Point(80, 0), New Point(160, 80),
New Point(80, 160), New Point(0, 80)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(243 + i * 20, 580, 160, 160)
k.wartosc = 11
coll.Add(k)
Next
'figury 12
For i As Integer = 0 To 1
bitmMain = New Bitmap(160, 160)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(0, 160), New Point(160, 160), New Point(160, 0)})
g.DrawPolygon(penRed, New PointF() {New Point(0, 160), New Point(160, 160), New Point(160, 0)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(30 + i * 10, 580, 160, 160)
k.wartosc = 12
coll.Add(k)
Next
'figury 13
For i As Integer = 0 To 1
bitmMain = New Bitmap(80, 240)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(0, 80), New Point(80, 0),
New Point(80, 160), New Point(0, 240)})
g.DrawPolygon(penRed, New PointF() {New Point(0, 80), New Point(80, 0),
New Point(80, 160), New Point(0, 240)})
k.bitmap = bitmMain
k.kat = 0
k.ksztalt = New Rectangle(500 + i * 20, 525, 80, 240)
k.wartosc = 13
coll.Add(k)
Next
Return coll
End Function
End Class
Teraz możemy wrócić do kodu Formy1. Mimo tego, że utworzyliśmy kształty, one nie pojawią się na naszej formie, jeśli nie zostaną do niej dodane. Nasza forma, musi mieć aktywne zdarzenie Paint:
Kod tego zdarzenia:
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
For i As Integer = 0 To kolekcjaElementow.Count - 1
e.Graphics.DrawImage(kolekcjaElementow(i).bitmap, kolekcjaElementow(i).ksztalt)
Next
End Sub
Nasza forma ma teraz dodane kształty którymi będziemy poruszać:
Teraz zajmiemy się przesuwaniem obiektów. Interesują nas tutaj trzy zdarzenia:
- MouseMove – śledzi położenie kursora
- MouseDown – moment przyciśnięcia lewego przycisku myszy
- Mouseup – moment puszczenia tego przycisku
Zdarzenie MouseMove będzie działało dwojako, ponieważ gdy lewy przycisk myszy będzie wciśnięty, poruszanie myszą spowoduje przesunięcie obiektu, jeśli nie będziemy trzymać lewego przycisku myszy a będziemy znajdować się nad kształtem, jego stan kursora, ze strzałki zostanie zmieniony na rączkę.
'offset, aby element nie przesówał się do końca strzałki
Dim OffsetXX As Integer = 0
Dim OffsetYY As Integer = 0
Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
'jestWRuchu- opcja jest włączona gdy trzymany jest obiekt
If jestWRuchu = True Then
'pobieramy "Rectangle" obiektu
Dim rectnew As Rectangle = kolekcjaElementow(trzymany).ksztalt
'ustawiamy nowy punkt obiektu
rectnew.Location = New Point(e.X + OffsetXX, e.Y + OffsetYY)
'nadpisujemy obiekt o nowych koordynatach na liście
kolekcjaElementow(trzymany) = New ksztalt With {
.bitmap = kolekcjaElementow(trzymany).bitmap,
.wartosc = kolekcjaElementow(trzymany).wartosc,
.ksztalt = rectnew,
.kat = kolekcjaElementow(trzymany).kat}
Else
'Jeśli nie trzymamy obiektu, a kursor znajduje się nad obiektem,
'zostanie zmieniony jego wygląd na rączkę
Dim nowyKursor As Cursor = Cursors.Default
For d As Integer = 0 To kolekcjaElementow.Count - 1
If (PunktJestNadObiektem(e.X, e.Y, d)) Then
nowyKursor = Cursors.Hand
trzymany = d
End If
Next
If (Me.Cursor <> nowyKursor) Then
Me.Cursor = nowyKursor
End If
End If
Me.Invalidate()
End Sub
'Funkcja zwraca true, jeśli kursor jest nad kształtem
Private Function PunktJestNadObiektem(ByVal x As Integer, ByVal y As Integer, ByVal k As Integer) As Boolean
'Sprawdza nad którym obiektem jest kursor
If ((x < kolekcjaElementow(k).ksztalt.Left) OrElse (y < kolekcjaElementow(k).ksztalt.Top) OrElse
(x >= kolekcjaElementow(k).ksztalt.Right) OrElse (y >= kolekcjaElementow(k).ksztalt.Bottom)) Then
'jeśli nie ma obiektu, zwróci false
Return False
End If
'pobiera pixel kształtu (koordynaty w obiekcie rectangle)
Dim i As Integer = x - kolekcjaElementow(k).ksztalt.X
Dim j As Integer = y - kolekcjaElementow(k).ksztalt.Y
'zwraca true, jeśli wartość alfa koloru jest większa od zera, zero oznacza przezroczystość
Return (kolekcjaElementow(k).bitmap.GetPixel(i, j).A > 0)
End Function
Zdarzenie MaouseMove śledzi położenie kursora, jego koordynaty pobieramy za pomocą punktu wykorzystując „ByVal e As System.Windows.Forms.MouseEventArgs”, położenie określają zmienne (e.X, e.Y). Jeśli nie trzymamy obiektu, wtedy koordynaty są na bieżąco sprawdzane, jeśli element jest trzymany, wtedy tworzony jest nowy kształt (Rectangle) w którym zmieniamy położenie (rectnew.Location = New Point(e.X + OffsetXX, e.Y + OffsetYY)) i nadpisujemy go na liście:
Wygląda to pięknie, i będzie jeszcze piękniej. Zajmiemy się teraz zdarzeniem MouseDown, które jest wywoływane w momencie przyciśnięcia lewego przycisku myszy. Zdarzenie to, określi nam który element jest wybrany, zmieni kolor elementu, podświetli go, tak abyśmy się nie pogubili, i przesunie na koniec kolekcji, przesuwając jednocześnie nasz obiekt do przodu.
Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
'Moment klikniecia na ksztalt
If e.Button = MouseButtons.Left Then
If (PunktJestNadObiektem(e.X, e.Y, trzymany)) Then
OffsetXX = kolekcjaElementow(trzymany).ksztalt.X - e.X
OffsetYY = kolekcjaElementow(trzymany).ksztalt.Y - e.Y
Dim bit As Bitmap = kolekcjaElementow(trzymany).bitmap
'podświetlenie
Dim Xcount As Integer
For Xcount = 0 To bit.Width - 1
Dim Ycount As Integer
For Ycount = 0 To bit.Height - 1
Dim pixelColor As Color = bit.GetPixel(Xcount, Ycount)
If pixelColor = Color.FromArgb(255, 0, 0) Then
bit.SetPixel(Xcount, Ycount, Color.Black)
ElseIf pixelColor = Color.FromArgb(64, 224, 208) Then
bit.SetPixel(Xcount, Ycount, Color.Blue)
End If
Next Ycount
Next Xcount
'nadpisujemy kształt w kolekcji
kolekcjaElementow.Add(New ksztalt With {
.bitmap = bit,
.wartosc = kolekcjaElementow(trzymany).wartosc,
.ksztalt = kolekcjaElementow(trzymany).ksztalt,
.kat = kolekcjaElementow(trzymany).kat})
'jeśteśmy w ruchu
jestWRuchu = True
'przesówamy obiekt do przodu
kolekcjaElementow.RemoveAt(trzymany)
trzymany = kolekcjaElementow.Count - 1
End If
End If
'nadpisze nam grafikę
Me.Invalidate()
End Sub
Jeśli nie zastosujemy offsetu, po wybraniu lewym przyciskiem myszy nasz obiekt zostanie zrównany z punktem kursora:
Musimy więc dopasować tak koordynaty aby kursor myszy znajdował się w miejscu jego ułożenia. teraz po wybraniu lewego przycisku myszy możemy podnosić nasze kształty. Ułożenie kształtów zapewnia zdarzenie MouseUp. Podzielone jest ono na dwie opcje, pierwsza to kliknięcie prawym przyciskiem myszy, spowoduje to obrócenie obiektu, lewy przycisk myszy ułoży obiekt.
Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
'prawy przycisk myszy
'zmiana ustawienia obiektu o 90 stopni
If e.Button = MouseButtons.Right Then
'obrazek trzymanego obiektu
Dim bit As Bitmap = kolekcjaElementow(trzymany).bitmap
'obracamy obrazek o 90 stopni w prawo
bit.RotateFlip(RotateFlipType.Rotate90FlipXY)
Dim kat As Integer = kolekcjaElementow(trzymany).kat
Dim rec As Rectangle = kolekcjaElementow(trzymany).ksztalt
If Not rec.Width = rec.Height Then
Dim w As Integer = rec.Width
Dim h As Integer = rec.Height
rec.Size = New Size(h, w)
kat += 1
'podłużne obiekty
If kolekcjaElementow(trzymany).wartosc = 13 Or kolekcjaElementow(trzymany).wartosc = 2 Then
If (kat Mod 2) = 0 Then
If kolekcjaElementow(trzymany).wartosc = 13 Then
bit.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
kat = kat Mod 4
Else
If (kat Mod 4) = 0 And kolekcjaElementow(trzymany).wartosc < 10 Then
bit.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
kat = kat Mod 8
End If
ElseIf kolekcjaElementow(trzymany).wartosc = 12 Or kolekcjaElementow(trzymany).wartosc = 1 Then
kat += 1
kat = kat Mod 4
End If
'nadpisujemy obiekt na liście
kolekcjaElementow(trzymany) = New ksztalt With {
.bitmap = bit,
.wartosc = kolekcjaElementow(trzymany).wartosc,
.ksztalt = rec,
.kat = kat}
Else
If jestWRuchu = True Then
For i As Integer = 0 To 5
For j As Integer = 0 To 5
'sprawdzamy wszystkie kwadraty, jeśli w jakimś znajduje się nasz kształt,
'wtedy zostanie on dopasowany
If (listaKwadratow(i, j).Location.X <= kolekcjaElementow(trzymany).ksztalt.Location.X And
listaKwadratow(i, j).Location.X + 80 > kolekcjaElementow(trzymany).ksztalt.Location.X) _
And (listaKwadratow(i, j).Location.Y <= kolekcjaElementow(trzymany).ksztalt.Location.Y And
listaKwadratow(i, j).Location.Y + 80 > kolekcjaElementow(trzymany).ksztalt.Location.Y) Then
' Dim pan As New Panel
' pan.Location = New Point(listaKwadratow(i, j).Location.X, listaKwadratow(i, j).Location.Y)
' pan.BorderStyle = BorderStyle.Fixed3D
' pan.Size = New Size(80, 80)
' pan.BackColor = Color.Transparent
' Me.Controls.Add(pan)
Dim rectnew As Rectangle = kolekcjaElementow(trzymany).ksztalt
rectnew.Location = New Point(listaKwadratow(i, j).Location.X + 40,
listaKwadratow(i, j).Location.Y + 40)
Dim bit As Bitmap = kolekcjaElementow(trzymany).bitmap
Dim Xcount As Integer
For Xcount = 0 To bit.Width - 1
Dim Ycount As Integer
For Ycount = 0 To bit.Height - 1
Dim pixelColor As Color = bit.GetPixel(Xcount, Ycount)
If pixelColor = Color.FromArgb(0, 0, 0) Then
bit.SetPixel(Xcount, Ycount, Color.FromArgb(255, 0, 0))
ElseIf pixelColor = Color.FromArgb(0, 0, 255) Then
bit.SetPixel(Xcount, Ycount, Color.FromArgb(64, 224, 208))
End If
Next Ycount
Next Xcount
kolekcjaElementow(trzymany) = New ksztalt With {
.bitmap = bit,
.wartosc = kolekcjaElementow(trzymany).wartosc,
.ksztalt = rectnew,
.kat = kolekcjaElementow(trzymany).kat,
.polozenie = {i, j}}
jestWRuchu = False
End If
Next
Next
'Jeśli nie ułożyłeś elementu na planszy wtdy:
If jestWRuchu = True Then
Dim rectnew As Rectangle = kolekcjaElementow(trzymany).ksztalt
rectnew.Location = New Point(e.X + OffsetXX, e.Y + OffsetYY)
'element wystaje za krawędź formy
If e.X + OffsetXX + rectnew.Width > Me.Width Then
rectnew.Location = New Point(Me.Width - rectnew.Width, rectnew.Location.Y)
End If
If e.Y + OffsetYY + rectnew.Height > Me.Height Then
rectnew.Location = New Point(rectnew.Location.X, Me.Height - rectnew.Height)
End If
If e.X + OffsetXX < 0 Then
rectnew.Location = New Point(0, rectnew.Location.Y)
End If
If e.Y + OffsetYY < 0 Then
rectnew.Location = New Point(rectnew.Location.X, 0)
End If
'zmieniamy kolor na normalny
Dim bit As Bitmap = kolekcjaElementow(trzymany).bitmap
Dim Xcount As Integer
For Xcount = 0 To bit.Width - 1
Dim Ycount As Integer
For Ycount = 0 To bit.Height - 1
Dim pixelColor As Color = bit.GetPixel(Xcount, Ycount)
If pixelColor = Color.FromArgb(0, 0, 0) Then
bit.SetPixel(Xcount, Ycount, Color.FromArgb(255, 0, 0))
ElseIf pixelColor = Color.FromArgb(0, 0, 255) Then
bit.SetPixel(Xcount, Ycount, Color.FromArgb(64, 224, 208))
End If
Next Ycount
Next Xcount
'nadpisujemy kształt
kolekcjaElementow(trzymany) = New ksztalt With {
.bitmap = bit,
.wartosc = kolekcjaElementow(trzymany).wartosc,
.ksztalt = rectnew,
.kat = kolekcjaElementow(trzymany).kat}
jestWRuchu = False
End If
End If
End If
Me.Invalidate()
'sprawdzamy koniec gry
'''''' koniecGry()
End Sub
W zależności od tego jaki kształt wybierzemy, można go obracać dwa lub cztery razy o 90 stopni. Jeśli obrócimy określony kształt dwa razy, wtedy następuje zmiana na jego lustrzane odbicie, ma on wtedy 4 stany:
Ten kształt ma cztery stany, dwa zwykłe i dwa lustrzane
Ten kształt ma cztery stany, bez lustrzanego odbicia
Ten kształt jest symetryczny, więc nie ma żadnego stanu.
Najwięcej stanów mają dwa elementy turkusowe, bo aż 8, cztery zwykłe i cztery lustrzane:
Wartość obrotu jest szalenie istotna, ponieważ wykorzystywana jest ostatecznie do porównania obrazków i określeniu, czy gra się skończyła. Kiedy już określiliśmy nowy obiekt Rectangle i wygenerowaliśmy nową bitmapę, nadpisujemy ją na liście. Przyszedł czas na omówienie lewego klawisza myszy, na początku sprawdzamy czy nie na relacji „nasz obiekt <=> listaKwadratow(i)” jeśli tak jest nasz element będzie odpowiednio dopasowany. Gdyby tego nie było, nasz element nie byłby równo ułożony. Można odblokować element:
pan.Location = New Point(listaKwadratow(i, j).Location.X,
listaKwadratow(i, j).Location.Y)
pan.BorderStyle = BorderStyle.Fixed3D
pan.BackColor = Color.Transparent
pan.Size = New Size(80, 80)
Me.Controls.Add(pan)
Efektem będzie wyświetlenie kwadratu:
To zapewnia nam spójną całość formy. Dodatkowo do struktury dodajemy element .polozenie który będzie potrzebny do sprawdzenia czy gra jest zakończona. Jeśli kwadrat zostanie znaleziony, tak jak na gifie powyżej, wtedy następuje zmiana koloru i nadpisanie obiektu. Jeśli jednak kwadrat nie zostanie znaleziony a element jest w ruchu, oznacza to, że został ułożony poza planszą. Wtedy należy nadać mu koordynaty (e.X, eY). Jeśli element znajduje się poza planszą należy go przesunąć.
Mamy już potrzebne elementy. Możemy przesuwać kształty i układać je na planszy. Zaczynamy grę! Tworzymy uchwyt dla przycisku „Start / Losuj” (button2):
Dim graDziala As Boolean = False 'zmienna okresla stan gry
Dim StopWatch As Diagnostics.Stopwatch
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
PrzygotujTapete() 'resetujemy elementy gry
kolekcjaElementow = GenerujKsztalty.GenerujElementyGry() 'tworzymy listę elementów
'wybieramy wzór
WybranyWzor = GenerujKsztalty.generujWzor(Panel1, ran.Next(0, KsztaltyWzory.Count))
'rysujemy elementy
Me.Invalidate()
'zmieniamy stan gry na działającą
graDziala = True
'tworzymy timer liczący czas gry
StopWatch = New Diagnostics.Stopwatch
Timer1.Start()
Me.StopWatch.Start()
End Sub
'liczy czas ułożenia
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim elapsed As TimeSpan = Me.StopWatch.Elapsed
Label1.Text = String.Format("{0:00}:{1:00}:{2:00}", Math.Floor(elapsed.TotalHours), elapsed.Minutes, elapsed.Seconds)
End Sub
Wracamy do klasy GenerujKsztalty, musimy stworzyć funkcję rysującą wybrany wzór, aby było trudniej, będziemy generować tylko czerwone kształty. Oczywiście bitmapa wygenerowana tą metodą będzie dużo mniejsza. Musimy określić punkty na tej bitmapie na których zaczepimy kształty:
Dim wybrany As Integer 'wybrany wzór, jego indeks
Public Function generujWzor(ByRef pan As Panel, ByVal k As Integer) As Integer(,)
Dim pp(5, 5) As Point
Dim bitmMain As Bitmap
Dim bitmapaWzoru As New Bitmap(240, 240)
Dim g As Graphics
'punkty zaczepienia kształtów
For j As Integer = 0 To 5
For i As Integer = 0 To 5
pp(i, j) = New Point(i * 40, j * 40)
Next
Next
'przeglądamy elementy wzoru, w sumie czternaście kształtów
For i As Integer = 0 To 13
Select Case KsztaltyWzory(k)(i, 0)
'jeśli któryś z kształtów jest czerwony (jego wartość jest 11 lub 12 lub 13)
Case 11
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(40, 0), New Point(80, 40),
New Point(40, 80), New Point(0, 40)})
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(k)(i, 1),
KsztaltyWzory(k)(i, 2)))
Case 12
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(-1, 80), New Point(80, 80),
New Point(80, -1)})
'kształt musi być odpowiednio obrócony
For j As Integer = 0 To KsztaltyWzory(k)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(k)(i, 1),
KsztaltyWzory(k)(i, 2)))
Case 13
bitmMain = New Bitmap(40, 120)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(-1, 40), New Point(40, -1),
New Point(40, 80), New Point(-1, 120)})
'kształt musi być odpowiednio obrócony
For j As Integer = 0 To KsztaltyWzory(k)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
'lustrzane odbicie
If (j Mod 2) = 0 Then
bitmMain.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(k)(i, 1),
KsztaltyWzory(k)(i, 2)))
End Select
Next
'dodajemy grafikę jako tło panelu
pan.BackgroundImage = bitmapaWzoru
wybrany = k
'zwracamy tablicę
Return KsztaltyWzory(k)
End Function
Teraz wzór będzie generowany:
Najtrudniejszy element, czyli „KoniecGry()” zostawimy sobie na koniec. Dodajmy teraz funkcjonalność reszty klawiszy:
'przycisk pokazujący wzór, jednocześnie kopiujący go do Clipboard'a dzięki czemu możemy go
'dodać do listy wzorów
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim str As String = "{"
For i As Integer = 0 To kolekcjaElementow.Count - 1
If kolekcjaElementow(i).polozenie IsNot Nothing Then
str += "{" + kolekcjaElementow(i).wartosc.ToString + "," +
kolekcjaElementow(i).polozenie(0).ToString + "," +
kolekcjaElementow(i).polozenie(1).ToString + "," +
kolekcjaElementow(i).kat.ToString + "},"
End If
Next
str = str.Remove(str.Length - 1)
str += "}"
MsgBox(str)
System.Windows.Forms.Clipboard.SetText(str)
End Sub
'resetuje grę
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
PrzygotujTapete()
graDziala = False
kolekcjaElementow = GenerujKsztalty.GenerujElementyGry()
WybranyWzor = GenerujKsztalty.generujWzor(Panel1, ran.Next(0, KsztaltyWzory.Count))
Timer1.Stop()
Me.StopWatch.Stop()
Me.Invalidate()
End Sub
'przycisk poddania się
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
graDziala = False
GenerujKsztalty.poddajsie(Panel1)
Timer1.Stop()
Me.StopWatch.Stop()
End Sub
Wracamy do klasy „GenerujKsztalty”, w momencie poddania gry, gracz zostanie poinstruowany o sposobie ułożenia elementów:
Jest to bardzo pomocny element, gdyż użytkownik może zarzucić nam, że układanki nie da się ułożyć.
Public Sub poddajsie(ByRef pan As Panel)
Dim pp(5, 5) As Point
Dim bitmMain As Bitmap
Dim bitmapaWzoru As New Bitmap(240, 240)
Dim penRed As New Pen(Brushes.Tomato)
Dim penTur As New Pen(Brushes.PaleTurquoise)
penRed.Width = 2
penTur.Width = 2
Dim g As Graphics
For j As Integer = 0 To 5
For i As Integer = 0 To 5
pp(i, j) = New Point(i * 40, j * 40)
Next
Next
For i As Integer = 0 To 13
Select Case KsztaltyWzory(wybrany)(i, 0)
Case 1
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0),
New Point(40, 40), New Point(80, 0), New Point(80, 80), New Point(0, 80)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(40, 40),
New Point(80, 0), New Point(80, 80), New Point(0, 80)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
Case 2
bitmMain = New Bitmap(40, 160)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0), New Point(40, 40),
New Point(40, 120), New Point(0, 160)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(40, 40), New Point(40, 120),
New Point(0, 160)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
Case 3
bitmMain = New Bitmap(120, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 80), New Point(80, 0),
New Point(120, 40), New Point(80, 80), New Point(0, 80)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 80), New Point(80, 0), New Point(120, 40),
New Point(80, 80), New Point(0, 80)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
If (j Mod 4) = 0 Then
bitmMain.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
Case 4
bitmMain = New Bitmap(80, 120)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Turquoise, New PointF() {New Point(0, 0), New Point(80, 0),
New Point(40, 40), New Point(40, 120), New Point(0, 80)})
g.DrawPolygon(penTur, New PointF() {New Point(0, 0), New Point(80, 0), New Point(40, 40),
New Point(40, 120), New Point(0, 80)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
If (j Mod 4) = 0 Then
bitmMain.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
'elementy czerwone
Case 11
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(40, 0), New Point(80, 40),
New Point(40, 80), New Point(0, 40)})
g.DrawPolygon(penRed, New PointF() {New Point(40, 0), New Point(80, 40),
New Point(40, 80), New Point(0, 40)})
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
Case 12
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(0, 80), New Point(80, 80), New Point(80, 0)})
g.DrawPolygon(penRed, New PointF() {New Point(0, 80), New Point(80, 80), New Point(80, 0)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
Case 13
bitmMain = New Bitmap(40, 120)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(0, 40), New Point(40, 0), New Point(40, 80),
New Point(0, 120)})
g.DrawPolygon(penRed, New PointF() {New Point(0, 40), New Point(40, 0), New Point(40, 80),
New Point(0, 120)})
For j As Integer = 0 To KsztaltyWzory(wybrany)(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
If (j Mod 2) = 0 Then
bitmMain.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(KsztaltyWzory(wybrany)(i, 1),
KsztaltyWzory(wybrany)(i, 2)))
End Select
Next
pan.BackgroundImage = bitmapaWzoru
End Sub
Kod jest trochę długi, ponieważ przy użyciu tablicy wzoru, musimy namalować i ułożyć elementy. Przyszedł czas na ostatni, najtrudniejszy element naszej układanki. Sprawdzenie czy wzór jest taki sam jak to co ułożyliśmy. Na pewno przyszło wam do głowy aby po prostu porównać koordynaty wszystkich elementów i wzoru. Niestety nie będzie tak łatwo. Zobaczcie obrazek poniżej:
Aż trzy elementy na dole mają różne współrzędne. Podczas sprawdzania współrzędnych tak duża różnica elementów jest niedopuszczalna. Lecz użytkownik ułożył obrazek zgodnie ze wzorem. Miałem dużo pomysłów na to jak to zrobić ale jeden okazał się najlepszy. Stworzymy mała bitmapę z czerwonymi elementami. Wracamy do GenerujKsztalty i dodajemy ostatnią funkcję zwracającą bitmapę:
Public Function GenerujPorownanie(ByVal t As Integer(,)) As Bitmap
Dim pp(5, 5) As Point
Dim bitmMain As Bitmap
Dim bitmapaWzoru As New Bitmap(240, 240)
Dim g As Graphics
For j As Integer = 0 To 5
For i As Integer = 0 To 5
pp(i, j) = New Point(i * 40, j * 40)
Next
Next
For i As Integer = 0 To 5
Select Case t(i, 0)
Case 11
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(40, 0), New Point(80, 40),
New Point(40, 80), New Point(0, 40)})
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(t(i, 1), t(i, 2)))
Case 12
bitmMain = New Bitmap(80, 80)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(-1, 80), New Point(80, 80),
New Point(80, -1)})
For j As Integer = 0 To t(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(t(i, 1), t(i, 2)))
Case 13
bitmMain = New Bitmap(40, 120)
g = Graphics.FromImage(bitmMain)
g.FillPolygon(Brushes.Red, New PointF() {New Point(-1, 40), New Point(40, -1),
New Point(40, 80), New Point(-1, 120)})
For j As Integer = 0 To t(i, 3)
If Not j = 0 Then
bitmMain.RotateFlip(RotateFlipType.Rotate90FlipXY)
If (j Mod 2) = 0 Then
bitmMain.RotateFlip(RotateFlipType.RotateNoneFlipX)
End If
End If
Next
Graphics.FromImage(bitmapaWzoru).DrawImage(bitmMain, pp(t(i, 1), t(i, 2)))
End Select
Next
Return bitmapaWzoru
End Function
Nie różni się ona od innych zamieszczonych w tej klasie elementów, teraz w form1 odblokujmy w zdarzeniu MouseUp:
koniecGry()
I dodajmy tą metodę do kodu:
Private Sub koniecGry()
If graDziala = True Then
Dim ListaElementow(6, 4) As Integer
Dim licznik As Integer = 0
'Sprawdza czy wszystkie elementy czerwone są ułożone
For i As Integer = 0 To kolekcjaElementow.Count - 1
If kolekcjaElementow(i).wartosc > 10 Then
If kolekcjaElementow(i).polozenie Is Nothing Then
'jeśli nie wszystkie czerwone elementy są ułożone
'zakończ metodę
Exit Sub
Else
ListaElementow(licznik, 0) = kolekcjaElementow(i).wartosc
ListaElementow(licznik, 1) = kolekcjaElementow(i).polozenie(0)
ListaElementow(licznik, 2) = kolekcjaElementow(i).polozenie(1)
ListaElementow(licznik, 3) = kolekcjaElementow(i).kat
licznik += 1
End If
End If
Next
'generuje dwie bitmapy
'pierwszą za pomocą pobranych wyżej współżędnych elementów i wartości obrotu
'ułożonych elementów
Dim tenObrazek As Bitmap = GenerujKsztalty.GenerujPorownanie(ListaElementow)
Panel3.BackgroundImage = tenObrazek
'drugą bitmapę
'tworzymy na podstawie wzoru
Dim obrazekdoporownania As Bitmap = GenerujKsztalty.GenerujPorownanie(WybranyWzor)
Panel4.BackgroundImage = obrazekdoporownania
'porównujemy pixele tych dwóch bitmap
For i As Integer = 0 To tenObrazek.Width - 1
For j As Integer = 0 To tenObrazek.Height - 1
If Not tenObrazek.GetPixel(i, j) = obrazekdoporownania.GetPixel(i, j) Then
'jeśli coś się nie zgadza, wtedy zakończ metodę
Exit Sub
End If
Next
Next
'jesli czerwone elementy są prawidłowo ułożone
'sprawdzamy czy na planszy nie ma białych pól
'jeśli elementy turkusowe są nieprawidłowo ułożone
'na planszy pozostaną białe pola ponieważ takiego koloru jest plansza
Dim bitmap As Bitmap = New Bitmap(500, 550)
Dim g As Graphics = Graphics.FromImage(bitmap)
Dim bmp As Bitmap = New Bitmap(Me.Width, Me.Height)
'rysujemy kawałek formy do bitmapy
Me.DrawToBitmap(bmp, New Rectangle(0, 0, Me.Width, Me.Height))
'rysuje bmp na bitmap
g.DrawImage(bmp, 0, 0,
New Rectangle(miejsceNamalowaniaKwadratu.X, miejsceNamalowaniaKwadratu.Y, 500, 550),
GraphicsUnit.Pixel)
For i As Integer = 0 To bitmap.Width - 1
For j As Integer = 0 To bitmap.Height - 1
'sprawdza czy bitmapa posiada białe kolory
If bitmap.GetPixel(i, j) = Color.FromArgb(255, 255, 255) Then
'jeśli tak, wtedy zakończ metodę
Exit Sub
End If
Next
Next
'czerwone elementy są ułożone prawidłowo i plansza jest wypełniona kształtami
'KONIEC GRY
Timer1.Stop()
Me.StopWatch.Stop()
MessageBox.Show("Osiągnięto czas:" + vbNewLine + Label1.Text, "Koniec gry!", MessageBoxButtons.OK)
End If
End Sub
Kiedy ułożymy wzór, w prawym dolnym rogu w panelach 3 i 4, pojawi się bitmapa do porównań. Panele te są niepotrzebne więc można je usunąć, ale dodałem je aby pokazać wam jak to działa:
Dobra, gra gotowa, teraz należy powymyślać więcej wzorów. Tutaj zdam się na was. Jeśli macie jakieś ciekawe wzory, napiszcie, przydadzą się. Pozdrawiam
Projekt do pobrania: Tangram visualMonsters.cba.pl






















