Dzisiaj zrobimy sobie program do układania puzzli, ale aby to zrobić musimy mieć puzzle. Nie będziemy robić programu do dzielenia obrazka na puzzle, gdyż byłoby to bardzo skomplikowane. Dużo łatwiej i estetyczniej jest wyciąć sobie je samemu przy użyciu Inkscape i Gimpa. Aby to zrobić, należy oczywiście zainstalować oba programy i dodać do nich rozszerzenia:
Inkscape: https://github.com/Neon22/inkscape-jigsaw
Gimp: https://github.com/devolonter/gimp-cut-to-pieces
Nie będę się tutaj rozwijał w temacie, wszystko co i jak prezentuje na filmie poniżej:
Działanie programu który będziemy robić prezentuje na tym filmie:
Program który ja przygotowałem prezentuje poniżej:
Puzzelek 1.0
Kiedy potniemy już sobie puzzle, przyszedł czas na utworzenie Formy do naszego projektu:
Rodzaj elementu | Nazwa elementu | Ustawienia |
---|---|---|
Form | Form1 | Name: Form1 Text: Puzzle VisualMonsters.cba.pl Size: 642; 475 WindowState: Maximized BackColor: White BackgroungImageLayout: CenterDubleBuffer: True |
Panel | Panel1 | Name: Panel1 Anchor: Bottom, Right Size: 187; 52 BorderStyle: FixedSingle |
TrackBar | TrackBar1 | Name: TrackBar1 Dock: Fill Maximum: 100 Value: 10 |
Należy teraz umieścić nasze puzzle w programie (jeśli nie chciało wam się robić puzzli, możecie pobrać je tutaj: iron-man, statek, South Park). Robimy to tak jak na gifie poniżej:
Program, nie będzie miał bardzo skomplikowanych ustawień, tak więc obracanie puzzli czy zmiana ich rozmiaru pozostawiam wam. Nie będziemy się też za bardzo skupiać nad komplikowaniem tego projektu. Tutorial ma za zadanie nauczyć użytkownika manipulować elementami graficznymi. Zaczynamy od dodania elementów puzzli z zasobów projektu i od deklaracji zmiennych:
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 |
Public Class Form1 Public OffsetX As New List(Of Integer) Public OffsetY As New List(Of Integer) Public WszystkiePuzzle As New List(Of Bitmap) Public LokalizacjaPuzzla As New List(Of Rectangle) Private Trzymany As Integer = 0 Public TrzymanyIndex As New List(Of Boolean) Public TrzymanyIndexPrecyzyjny As New List(Of Integer) 'wykorzystamy go do precyzyjnego dopasowania elementów Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'Me.BackgroundImage = ZmienKrycie(My.Resources.sp, 0.1) Dim ran As New Random 'przeszukujemy specjalną lokalizację naszego projektu, w poszukiwaniu obrazków For Each ResourceFile As DictionaryEntry In My.Resources.ResourceManager.GetResourceSet(Globalization.CultureInfo.CurrentCulture, True, True).OfType(Of Object)() 'jeśli natrafimy na obrazek If TypeOf (ResourceFile.Value) Is Image Then 'nie jest on obrazkiem złożonym sp.bmp (tym podglądowym) If Not ResourceFile.Key.ToString.Contains("sp") Then Dim imaeege As Image = ResourceFile.Value Dim bm_source As New Bitmap(imaeege) 'uzupełniamy listę o tą bitmapę WszystkiePuzzle.Add(bm_source) 'ustawiamy położenie startowe puzzli 'każdy puzel zostanie rozsypany losowo OffsetX.Add(ran.Next(0, Me.Width - 2 * bm_source.Width)) OffsetY.Add(ran.Next(0, Me.Height - 2 * bm_source.Height)) 'nie trzymamy jeszcze żadnych puzli, więc listę wypełniamy 'False' TrzymanyIndex.Add(False) End If End If Next 'Nie chcemy aby wielkość formy była mniejsza niż nasz obrazek, dlatego dodamy sobie takie ograniczenie Me.MinimumSize = New Size(My.Resources.sp.Width + 50, My.Resources.sp.Height + 50) 'Tworzymy figury o określonej lokalizacji (X,Y) i wielkości obrazka For i As Integer = 0 To WszystkiePuzzle.Count - 1 LokalizacjaPuzzla.Add(New Rectangle(OffsetX(i), OffsetY(i), WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height)) Next End Sub Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint 'Tworzy grafikę na formie głównej, wywoływany jest gdy zmianie ulega jakiś element For i As Integer = 0 To WszystkiePuzzle.Count - 1 If TrzymanyIndexPrecyzyjny.Contains(i) Then e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(50, 255, 0, 0)), LokalizacjaPuzzla(i)) End If e.Graphics.DrawImage(WszystkiePuzzle(i), LokalizacjaPuzzla(i)) Next End Sub End Class |
Oczywiście efektem będzie wyświetlenie puzzli na naszej formie, zajmiemy się teraz etapem ogólnego przesuwania elementów. Będzie się ona składał z trzech zdarzeń:
-
MouseMove
– to zdarzenie monitoruje nam na bieżąco położenie kursora nad formą, jeśli natrafi na nasz obiekt (co ważne funkcja KursorJestNadObiektem zwróci true, a zwróci tylko wtedy gry pixel, nad którym znajduje się kursor, nie jest przezroczysty) wtedy pobiera jego index i zmienia kursor na łapkę:Oczywiście w chwili złapania obiektu, zdarzenie MouseMove odpowiada również za zmianę lokalizacji obiektu, ale metoda ta nie jest skomplikowana i polega na zmianie parametrów w liście LokalizacjaPuzzla.
-
MouseDown
– Ustawia Offset, który jest wykorzystywany w przesuwaniu elementu/ów. Dział ten podzieliłem na trzy części.
- Pierwszy to przesuwanie tylko jednego elementu odbywa się to za pomocą lewego przycisku myszy:
- Drugi to przesuwanie wskazanego elementu i elementów z nim graniczących:
- Trzeci etap to przesuwanie wszystkich stykających się ze sobą elementów:
-
MouseUp
– etap końcowy zmienia opcje TrzymanyIndex na false, dla trzymanych obiektów sprawdza, czy elementy nie zostały przesunięte poza układany obszar (dzięki niemu nie zgubimy naszych puzzli :P):
Wiemy jak to będzie działać, pełen kod wygląda tak:
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 142 |
'Pubiera index elementu nad którym znajduje się kursor i zmienia położenie elementu jeśli jest trzymany Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove For i As Integer = 0 To WszystkiePuzzle.Count - 1 If TrzymanyIndex(i) = True Then LokalizacjaPuzzla(i) = New Rectangle(e.X + OffsetX(i), e.Y + OffsetY(i), WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height) Me.Invalidate() 'powoduje ponowne malowanie obiektów Else Dim new_cursor As Cursor = Cursors.Default For d As Integer = 0 To WszystkiePuzzle.Count - 1 If (KursorJestNadObiektem(e.X, e.Y, d)) Then new_cursor = Cursors.Hand 'ustawia index obiektu nad którym jest kursor Trzymany = d End If Next If (Me.Cursor <> new_cursor) Then Me.Cursor = new_cursor End If End If Next End Sub Private Function KursorJestNadObiektem(ByVal x As Integer, ByVal y As Integer, ByVal k As Integer) As Boolean If ((x < LokalizacjaPuzzla(k).Left) OrElse (y < LokalizacjaPuzzla(k).Top) OrElse (x >= LokalizacjaPuzzla(k).Right) _ OrElse (y >= LokalizacjaPuzzla(k).Bottom)) _ Then Return False Dim i As Integer = x - LokalizacjaPuzzla(k).X Dim j As Integer = y - LokalizacjaPuzzla(k).Y Return (WszystkiePuzzle(k).GetPixel(i, j).A > 0) End Function Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown TrzymanyIndexPrecyzyjny.Clear() Panel1.Enabled = False 'Warunek sprawdza który klawisz myszy jest trzymany If e.Button = MouseButtons.Left Then 'Trzymanie jednego elementu 'Funkcja sprawdza czy kursor myszy nadal jest nad obiektem If (KursorJestNadObiektem(e.X, e.Y, Trzymany)) Then TrzymanyIndex(Trzymany) = True 'elementy wykorzystywane do zmiany położenia puzzla OffsetX(Trzymany) = LokalizacjaPuzzla(Trzymany).X - e.X OffsetY(Trzymany) = LokalizacjaPuzzla(Trzymany).Y - e.Y 'lista wykorzystywana na późniejszym etapie do precyzyjnego ustawienia położenia TrzymanyIndexPrecyzyjny.Add(Trzymany) End If Else 'trzymanie wielu elementów Dim listaPolaczonych As New List(Of Integer) 'przechowuje elementy wielu połączonych puzzli 'Funkcja sprawdza czy kursor myszy nadal jest nad obiektem If (KursorJestNadObiektem(e.X, e.Y, Trzymany)) Then 'dodaje pierwszy index trzymanego obiektu TrzymanyIndex(Trzymany) = True 'elementy wykorzystywane do zmiany położenia puzzla OffsetX(Trzymany) = LokalizacjaPuzzla(Trzymany).X - e.X OffsetY(Trzymany) = LokalizacjaPuzzla(Trzymany).Y - e.Y ' dwie listy indexów, jedna wykorzystywana do przenoszenia bardzo wielu połączonych puzzli listaPolaczonych.Add(Trzymany) TrzymanyIndexPrecyzyjny.Add(Trzymany) For Each el As Rectangle In LokalizacjaPuzzla 'Warunek sprawdza czy w obrębie puzla znajdują się inne puzle które można by przesunąć (z dokładnością 5%) If (el.Location.X >= (LokalizacjaPuzzla(Trzymany).Location.X - 0.05 * LokalizacjaPuzzla(Trzymany).Width) And el.Location.X <= (LokalizacjaPuzzla(Trzymany).Location.X + LokalizacjaPuzzla(Trzymany).Width + 0.05 * LokalizacjaPuzzla(Trzymany).Width) Or el.Location.X + el.Width >= (LokalizacjaPuzzla(Trzymany).Location.X - 0.05 * LokalizacjaPuzzla(Trzymany).Width) And el.Location.X <= (LokalizacjaPuzzla(Trzymany).Location.X + LokalizacjaPuzzla(Trzymany).Width + 0.05 * LokalizacjaPuzzla(Trzymany).Width)) And (el.Location.Y >= (LokalizacjaPuzzla(Trzymany).Location.Y - 0.05 * LokalizacjaPuzzla(Trzymany).Height) And el.Location.Y <= (LokalizacjaPuzzla(Trzymany).Location.Y + LokalizacjaPuzzla(Trzymany).Height + 0.05 * LokalizacjaPuzzla(Trzymany).Height) Or el.Location.Y + el.Height >= (LokalizacjaPuzzla(Trzymany).Location.Y - 0.05 * LokalizacjaPuzzla(Trzymany).Height) And el.Location.Y <= (LokalizacjaPuzzla(Trzymany).Location.Y + LokalizacjaPuzzla(Trzymany).Height + 0.05 * LokalizacjaPuzzla(Trzymany).Height)) Then 'Jeśli znajdują się tam jakieś puzzle wtedy dodajemy ich indexy do list aby była możliwość 'wyróżnienia ich w następnych krokach If Not TrzymanyIndexPrecyzyjny.Contains(LokalizacjaPuzzla.IndexOf(el)) Then TrzymanyIndexPrecyzyjny.Add(LokalizacjaPuzzla.IndexOf(el)) TrzymanyIndex(LokalizacjaPuzzla.IndexOf(el)) = True 'ustawiamy offset OffsetX(LokalizacjaPuzzla.IndexOf(el)) = LokalizacjaPuzzla(LokalizacjaPuzzla.IndexOf(el)).X - e.X OffsetY(LokalizacjaPuzzla.IndexOf(el)) = LokalizacjaPuzzla(LokalizacjaPuzzla.IndexOf(el)).Y - e.Y End If End If Next 'Jeśli przytrzymamy Ctrl na klawiaturze, podczas trzymania lewego przycisku myszy 'będziemy mogli przesunąć nietylko elementy zawierające się w obrębie jednego puzzla, 'będziemy mogli przesunąć wszystkie puzzle do siebie przylegające If My.Computer.Keyboard.CtrlKeyDown Then 'pętla strawdza warunek dla wszystkich elementów z listy dodatkowej, jeśli do elementów na liście należą inne elementy na liście się nie znajdującej, wtedy dodawane są do listy Do Dim przerwijPetle As Boolean = True 'warunek kończący pętle For i As Integer = 0 To TrzymanyIndex.Count - 1 If TrzymanyIndex(i) = True Then If Not listaPolaczonych.Contains(i) Then listaPolaczonych.Add(i) przerwijPetle = False For Each el As Rectangle In LokalizacjaPuzzla If (el.Location.X >= (LokalizacjaPuzzla(i).Location.X - 0.05 * LokalizacjaPuzzla(i).Width) And el.Location.X <= (LokalizacjaPuzzla(i).Location.X + LokalizacjaPuzzla(i).Width + 0.05 * LokalizacjaPuzzla(i).Width) Or el.Location.X + el.Width >= (LokalizacjaPuzzla(i).Location.X - 0.05 * LokalizacjaPuzzla(i).Width) And el.Location.X <= (LokalizacjaPuzzla(i).Location.X + LokalizacjaPuzzla(i).Width + 0.05 * LokalizacjaPuzzla(i).Width)) And (el.Location.Y >= (LokalizacjaPuzzla(i).Location.Y - 0.05 * LokalizacjaPuzzla(i).Height) And el.Location.Y <= (LokalizacjaPuzzla(i).Location.Y + LokalizacjaPuzzla(i).Height + 0.05 * LokalizacjaPuzzla(i).Height) Or el.Location.Y + el.Height >= (LokalizacjaPuzzla(i).Location.Y - 0.05 * LokalizacjaPuzzla(i).Height) And el.Location.Y <= (LokalizacjaPuzzla(i).Location.Y + LokalizacjaPuzzla(i).Height + 0.05 * LokalizacjaPuzzla(i).Height)) Then If Not TrzymanyIndexPrecyzyjny.Contains(LokalizacjaPuzzla.IndexOf(el)) Then TrzymanyIndexPrecyzyjny.Add(LokalizacjaPuzzla.IndexOf(el)) TrzymanyIndex(LokalizacjaPuzzla.IndexOf(el)) = True OffsetX(LokalizacjaPuzzla.IndexOf(el)) = LokalizacjaPuzzla(LokalizacjaPuzzla.IndexOf(el)).X - e.X OffsetY(LokalizacjaPuzzla.IndexOf(el)) = LokalizacjaPuzzla(LokalizacjaPuzzla.IndexOf(el)).Y - e.Y End If End If Next End If End If Next 'pętla kończy się gdy nie ma już co dodać If przerwijPetle = True Then Exit Do End If Loop End If End If End If End Sub 'Upuszczenie puzla Private Sub Form1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp Panel1.Enabled = True For i As Integer = 0 To WszystkiePuzzle.Count - 1 'Nie chcemy aby nasze puzzle wylądowały poza obszarem gry, dlatego wprowadzimy sobie dodatkowe ustawienia If LokalizacjaPuzzla(i).Location.X + WszystkiePuzzle(i).Width > Me.Width Then LokalizacjaPuzzla(i) = New Rectangle(Me.Width - WszystkiePuzzle(i).Width, LokalizacjaPuzzla(i).Location.Y, WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height) End If If LokalizacjaPuzzla(i).Location.Y + WszystkiePuzzle(i).Height > Me.Height Then LokalizacjaPuzzla(i) = New Rectangle(LokalizacjaPuzzla(i).Location.X, Me.Height - WszystkiePuzzle(i).Height, WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height) End If If LokalizacjaPuzzla(i).Location.X < 0 Then LokalizacjaPuzzla(i) = New Rectangle(0, LokalizacjaPuzzla(i).Location.Y, WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height) End If If LokalizacjaPuzzla(i).Location.Y < 0 Then LokalizacjaPuzzla(i) = New Rectangle(LokalizacjaPuzzla(i).Location.X, 0, WszystkiePuzzle(i).Width, WszystkiePuzzle(i).Height) End If TrzymanyIndex(i) = False Next TrzymanyIndexPrecyzyjny.Clear() Me.Invalidate() End Sub |
Ostatnim etapem jest doprecyzowanie elementów. Często jest tak, że dopasowanie elementów do siebie za pomocą myszy, może nam sprawić dość duży kłopot. Spróbujcie ruszyć tak myszą, aby przesunąć ją o 1px w lewo bądź w prawo. Ciężkie zadanie, więc wprowadziłem taką oto metodę. Gdy element lub elementy są trzymane, ich index dodawany jest do listy „TrzymanyIndexPrecyzyjny”, który pozwoli lokalizacji tych elementów o 1px zgodnie z przyciśniętym klawiszem strzałki:
Kod do tego elementu jest bardzo prosty:
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 |
'Aby ułatwić użytkownikowi kontrolę położenia puzla dodamy sobie możliwość jego dokładnej kontroli 'za pośrednictwem klawiszsy strzałek na klawiaturze Private Sub main_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown Select Case e.KeyCode Case Keys.Up For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 Dim moveX As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X Dim movey As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y - 1 LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(moveX, movey, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Width, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Height) Next Case Keys.Left For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 Dim moveX As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X - 1 Dim movey As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(moveX, movey, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Width, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Height) Next Case Keys.Right For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 Dim moveX As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X + 1 Dim movey As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(moveX, movey, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Width, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Height) Next Case Keys.Down For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 Dim moveX As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X Dim movey As Integer = LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y + 1 LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(moveX, movey, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Width, WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)).Height) Next End Select Me.Invalidate() End Sub |
Pozostał ostatni element, kiedy układamy puzzle mamy na pudełku docelowy składany obrazek. Musimy wiedzieć, co układamy, tak samo będzie i w naszym przypadku. Opcja zablokowana w Form_Load i TrackBar będą nam kontrolować przezroczystość obrazka docelowego tak, aby podpowiedz, nie była oczywista i nie zasłaniała nam naszych puzzli:
Odblokuj w Form_Load:
1 |
Me.BackgroundImage = ZmienKrycie(My.Resources.sp, 0.1) |
Kod kontrolujący krycie tła:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Private Sub TrackBar1_Scroll(sender As Object, e As EventArgs) Handles TrackBar1.Scroll Me.BackgroundImage = ZmienKrycie(My.Resources.sp, TrackBar1.Value / 100) End Sub Public Shared Function ZmienKrycie(ByVal img As Image, ByVal Krycie As Single) As Bitmap Dim bmp As New Bitmap(img.Width, img.Height) Dim graphics__1 As Graphics = Graphics.FromImage(bmp) Dim colormatrix As New ColorMatrix colormatrix.Matrix33 = Krycie Dim imgAttribute As New ImageAttributes imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.[Default], ColorAdjustType.Bitmap) If Krycie = 1 Then graphics__1.FillRectangle(New SolidBrush(Color.Red), 0, 0, img.Width, img.Height) Else graphics__1.DrawImage(img, New Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute) End If graphics__1.Dispose() Return bmp End Function |
Efekt prezentuje poniżej:
Zauważyć można, że gdy krycie jest równe 1, wtedy tło robi się całe czerwone, jest to zabieg celowy pomagający stwierdzić czy elementy puzzli są dobrze dopasowane (można go usunąć, jeśli uznacie, że jest niepotrzebny lub zmienić mu kolor z czerwonego na czarny, lub biały).
Jeśli chodzi o aplikacje, to jest gotowa do działania. Do pobrania:
Pełen projekt: Puzzle_VisualMonsters.cba.pl.zip
Sam kod źródłowy: Puzzle VisualMonsters.cba.pl.txt
Podpowiedzi:
Obracanie puzzli o określony kąt
Jeśli jesteście zainteresowani rozwojem tej aplikacji, na pewno wpadniecie na pomysł, aby obrócić puzzle o jakiś losowy kąt. Nie jest to takie proste, ponieważ będziemy musieli przerzucić się z „Rectangli” na listę punktów dokładniej czterech, które będą określały położenie obróconego elementu i dodać nową listę integer (Private KatNachylenia As New List(Of Integer)) którą, wypełnimy na początku albo wartością 0 lub losową z przedziału od 0 do 360. Jeśli chcecie sprawdzić, w jaki to działa sposób, zmieńcie metodę Form1_Paint:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint 'Tworzy grafikę na formie głównej, wywoływany jest gdy zmianie ulega jakiś element For i As Integer = 0 To WszystkiePuzzle.Count - 1 Dim ang As Integer = KatNachylenia(i) Dim W As Integer = WszystkiePuzzle(i).Width Dim H As Integer = WszystkiePuzzle(i).Height Dim m As Matrix = New Matrix m.RotateAt(ang, New Point(LokalizacjaPuzzla(i).Location.X, LokalizacjaPuzzla(i).Location.Y)) e.Graphics.Transform = m e.Graphics.DrawImage(WszystkiePuzzle(i), LokalizacjaPuzzla(i)) If TrzymanyIndexPrecyzyjny.Contains(i) Then e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(50, 255, 0, 0)), LokalizacjaPuzzla(i)) End If Next End Sub |
Należy też dodać jakiś bodziec, który będzie zmieniał kąt nachylenia naszego obrazka, w moim wypadku jest to scroll na myszce:
1 2 3 4 5 6 7 8 9 10 11 12 |
Private Sub Form1_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel If e.Delta > 0 Then For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 KatNachylenia(TrzymanyIndexPrecyzyjny(i)) = (KatNachylenia(TrzymanyIndexPrecyzyjny(i)) + 1) Mod 360 Next Else For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 KatNachylenia(TrzymanyIndexPrecyzyjny(i)) = (KatNachylenia(TrzymanyIndexPrecyzyjny(i)) - 1) Next End If Me.Invalidate() End Sub |
Wygląda to bardzo dobrze:
Niestety trzeba bardzo się namęczyć, aby dopracować ten element, ponieważ należy zastąpić „Rectangle” tablicą punktów. Łatwiejszą metodą jest obrót tylko o 90 stopni, taką metodę możemy w całości zamontować w zdarzeniu MouseWheel:
Ja w swoim programie wykorzystałem właśnie tę metodę, ponieważ jest łatwa do zaimplementowania i nie wymaga dużo klikania.
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 |
Dim obrot As Boolean = False Private Sub Form1_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel If e.Delta > 0 Then For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 If obrot = False Then Dim Obraz As New Bitmap(WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i))) Dim p As Point = New Point(LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X, LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y) LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(p.X, p.Y, Obraz.Height, Obraz.Width) Obraz.RotateFlip(RotateFlipType.Rotate90FlipY) WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)) = Obraz obrot = True Else Dim Obraz As New Bitmap(WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i))) Dim p As Point = New Point(LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X, LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y) LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(p.X, p.Y, Obraz.Height, Obraz.Width) Obraz.RotateFlip(RotateFlipType.Rotate90FlipX) WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)) = Obraz obrot = False End If Next Else For i As Integer = 0 To TrzymanyIndexPrecyzyjny.Count - 1 If obrot = False Then Dim Obraz As New Bitmap(WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i))) Dim p As Point = New Point(LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X, LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y) LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(p.X, p.Y, Obraz.Height, Obraz.Width) Obraz.RotateFlip(RotateFlipType.Rotate90FlipX) WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)) = Obraz obrot = True Else Dim Obraz As New Bitmap(WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i))) Dim p As Point = New Point(LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.X, LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)).Location.Y) LokalizacjaPuzzla(TrzymanyIndexPrecyzyjny(i)) = New Rectangle(p.X, p.Y, Obraz.Height, Obraz.Width) Obraz.RotateFlip(RotateFlipType.Rotate90FlipY) WszystkiePuzzle(TrzymanyIndexPrecyzyjny(i)) = Obraz obrot = False End If Next End If Me.Invalidate() End Sub |
Jeśli macie jakieś pomysły lub pytania, pytajcie a może coś dodamy do tutoriala