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).
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 78 79 80 81 82 83 84 85 86 87 88 89 90 |
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”:
1 |
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:
1 2 3 4 5 6 7 8 9 10 11 |
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()”:
1 2 3 4 5 |
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”
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 |
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:
1 2 3 4 5 |
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”.
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
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:
1 2 3 4 5 |
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ę.
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 |
'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.
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 |
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.
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
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:
1 2 3 4 5 6 |
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):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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:
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 |
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:
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 |
'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ć.
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
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ę:
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 |
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:
1 |
koniecGry() |
I dodajmy tą metodę do kodu:
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 |
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