Dzisiaj pokażę wam jak stworzyć, bardzo dobrze wam znaną grę w piłkarzyki. Na pewno każdy z was w momencie nudy na lekcjach skorzystał z okazji pogrania w taką prostą i sympatyczną grę.
Gra do pobrania tutaj: Pilkarzyki 1.2
Prezentacja gry i kodu źródłowego:
My zrobimy sobie trochę okrojoną wersję, ale najważniejsze elementy gry zostaną zachowane. Forma do gry nie będzie miała za dużo elementów, gdyż będą one generowane automatycznie w czasie trwania gry:
| Rodzaj elementu | Nazwa elementu | ustawienia |
|---|---|---|
| Form | Form1 | Name: Form1 Text: Piłkarzyki VisualMonsters.pl Size: 654; 468 |
| Panel | Panel1 | Name: Panel1 Size: 613; 407 Location: 12; 12 BackColor: SeaGreen Anchor: Top, Bottom, Left, Right |
| PictureBox | Panel_glowny | Name: Panel_glowny Size: 100; 50 Location: 58; 0 BackColor: SeaGreen |
Tak jak pisałem wcześniej, wszelkie elementy będą generowane na bieżąco, więc wystarczą nam tylko trzy elementy. Głównym elementem będzie PictureBox, to na nim będzie odbywała się rozgrywka, a panel pod nim to tylko estetyczne tło.
Public Class Form1
'wielkość planszy
Dim wysokosc As Integer = 7
Dim szerokosc As Integer = 11
'zmienna przechowuje aktualnie wybrany panel
Dim panelAktualnieWybrany As Panel
'zmienna przechowująca grafikę gry
Dim BitmapaBoiska As Bitmap
Dim GrafikaBoiska As Graphics
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'ustawiamy wielkość i pozycję pola do gry
Panel_glowny.Size = New Size(szerokosc * 49 + 50, wysokosc * 49 + 50)
Panel_glowny.Location = New Point((Panel1.Width - Panel_glowny.Width) / 2, (Panel1.Height - Panel_glowny.Height) / 2)
'tworzymy bitmapę i generujemy na niej grafikę
BitmapaBoiska = New Bitmap(Panel_glowny.Width, Panel_glowny.Height)
GrafikaBoiska = Graphics.FromImage(BitmapaBoiska)
'generuje grafikę boiska
'' generujLinieBoiska()
'generuje aktywne elementy gry (punkty na planszy do klikania
'' generujPaneleGlowne()
'wybiera środek planszy jako punkty startowy
'' panelAktualnieWybrany = listaLokalizacji(Math.Ceiling((szerokosc - 1) / 2))(Math.Ceiling((wysokosc) / 2))
'uaktywnia punkty do których możemy przejść/podać piłkę
'' odblokujPanele(panelAktualnieWybrany)
'dodaje panele bramek
'' DodajBramki()
Dim start As New System.Drawing.SolidBrush(System.Drawing.Color.Black) ' kolor punktu startowego
'' GrafikaBoiska.FillEllipse(start, New Rectangle(panelAktualnieWybrany.Location.X + 5, panelAktualnieWybrany.Location.Y + 5, 10, 10)) 'dodaje grafikę punktu startowego
'nadaje tło naszemu pictureboxowi (naszą grafikę)
Panel_glowny.Image = BitmapaBoiska
End Sub
End Class
Kod jest chyba zrozumiały, najpierw ustawiamy wielkość PictureBoxa i jego pozycję, aby była na środku, następnie generujemy grafikę i elementy klikalne na planszy. Zaczniemy od generowania siatki boiska, odblokuj element:
'generuje grafikę boiska
generujLinieBoiska()
Elementy boiska rysować będziemy za pomocą:
GrafikaBoiska.DrawLine("kolor","punkt startowy","punkt końcowy") - rysuje linie
GrafikaBoiska.FillEllipse("kolor", New Rectangle("położenie X", "położenie Y", "szerokość", "wysokość")) -rysuje wypełnione koło
Kod tego elementu wygląda tak:
#Region "Generuje grafikę boiska"
Private Sub generujLinieBoiska()
'śreodek boiska
Dim srodekBoiska_naWysokosc As Integer = Math.Floor((wysokosc) / 2)
Dim srodekBoiska_naSzerokosc As Integer = Math.Ceiling((szerokosc) / 2)
'Linie boiska
Dim CienkaLinia As Pen = New Pen(Color.FromArgb(191, 218, 229), 1) 'cienka linia
Dim GrubaLinia As Pen = New Pen(Color.White, 3) 'gruba linia
'generuje tło boiska
Dim KolorBoiska As New System.Drawing.SolidBrush(System.Drawing.Color.MediumSeaGreen)
GrafikaBoiska.FillRectangle(KolorBoiska, New Rectangle(0, 0, BitmapaBoiska.Width, BitmapaBoiska.Height))
'generuje linie boiska
For i As Integer = 0 To szerokosc + 1
For j As Integer = 0 To wysokosc + 1
GrafikaBoiska.DrawLine(CienkaLinia, 0, i * 49, Panel_glowny.Width, i * 49)
GrafikaBoiska.DrawLine(CienkaLinia, i * 49, 0, i * 49, Panel_glowny.Height)
Next
Next
'generuje linie autu
GrafikaBoiska.DrawLine(GrubaLinia, 49, 0, Panel_glowny.Width - 49, 0)
GrafikaBoiska.DrawLine(GrubaLinia, 49, (wysokosc + 1) * 49, Panel_glowny.Width - 49, (wysokosc + 1) * 49)
GrafikaBoiska.DrawLine(GrubaLinia, 49, 0, 49, srodekBoiska_naWysokosc * 49)
GrafikaBoiska.DrawLine(GrubaLinia, Panel_glowny.Width - 49, 0, Panel_glowny.Width - 49, srodekBoiska_naWysokosc * 49)
GrafikaBoiska.DrawLine(GrubaLinia, 49, (wysokosc + 1 - srodekBoiska_naWysokosc) * 49, 49, (wysokosc + 1) * 49)
GrafikaBoiska.DrawLine(GrubaLinia, Panel_glowny.Width - 49, (wysokosc + 1 - srodekBoiska_naWysokosc) * 49, Panel_glowny.Width - 49, (wysokosc + 1) * 49)
GrafikaBoiska.DrawLine(GrubaLinia, 0, srodekBoiska_naWysokosc * 49, 49, srodekBoiska_naWysokosc * 49)
GrafikaBoiska.DrawLine(GrubaLinia, 0, (srodekBoiska_naWysokosc + 2) * 49, 49, (srodekBoiska_naWysokosc + 2) * 49)
GrafikaBoiska.DrawLine(GrubaLinia, Panel_glowny.Width - 49, srodekBoiska_naWysokosc * 49, Panel_glowny.Width, srodekBoiska_naWysokosc * 49)
GrafikaBoiska.DrawLine(GrubaLinia, Panel_glowny.Width - 49, (srodekBoiska_naWysokosc + 2) * 49, Panel_glowny.Width, (srodekBoiska_naWysokosc + 2) * 49)
GrafikaBoiska.DrawLine(GrubaLinia, srodekBoiska_naSzerokosc * 49, 0, srodekBoiska_naSzerokosc * 49, (wysokosc + 1) * 49)
'generuje punkty na boisu
Dim pola As New System.Drawing.SolidBrush(Color.FromArgb(150, Color.White))
Dim aut As New System.Drawing.SolidBrush(System.Drawing.Color.White)
For i As Integer = 1 To szerokosc
For j As Integer = 0 To wysokosc + 1
If i = 1 Or i = szerokosc Or j = 0 Or j = (wysokosc + 1) Then
If j = Math.Ceiling(wysokosc / 2) Then
GrafikaBoiska.FillEllipse(pola, New Rectangle(i * 49 - 5, j * 49 - 5, 10, 10))
Else
GrafikaBoiska.FillEllipse(aut, New Rectangle(i * 49 - 5, j * 49 - 5, 10, 10))
End If
Else
GrafikaBoiska.FillEllipse(pola, New Rectangle(i * 49 - 5, j * 49 - 5, 10, 10))
End If
Next
Next
'generuje czerwone punkty bramek z obu stron
Dim bramka As New System.Drawing.SolidBrush(System.Drawing.Color.Red)
GrafikaBoiska.FillEllipse(bramka, New Rectangle(0 - 5, (srodekBoiska_naWysokosc + 1) * 49 - 5, 10, 10))
GrafikaBoiska.FillEllipse(bramka, New Rectangle((szerokosc + 1) * 49 - 5, (srodekBoiska_naWysokosc + 1) * 49 - 5, 10, 10))
End Sub
#End Region
Jest to czyste rysowanie, ja to robiłem tak, że wpisywałem kod, odpalałem program i patrzyłem, gdzie co jak się pojawiało :]. Po uruchomieniu widać już pola jak na kartce w kratkę:
Teraz to już trochę przypomina piłkarzyki. Możecie poeksperymentować i pozmieniać kolory, dodać koła boiska jakieś pola karne, aby uprzyjemnić ten widok. Teraz dodamy sobie aktywne elementy planszy, aby to zrobić, musimy je trochę podzielić:
-panele przy bramkach (trzy, które umożliwiają strzał na bramkę (na żółto))
-panele autów (te na krańcach boiska (na zielono))
-punkty boiska (na czerwono)
Po dodaniu kolorów do naszych paneli ja otrzymałem taki efekt:
Do punktów boiska będą należały wszystkie panele, a panele w wybranych grupach będą miały swoje specjalne właściwości, przyda to się komuś, kto będzie chciał rozbudować grę. Kod do tego elementu prezentuje poniżej:
#Region "Generuje punkty na planszy"
'przechowuje listę wszystkich pól
Dim listaLokalizacji As New List(Of List(Of Panel))
'przechowuje listę tylko autów
Dim listaLokalizacjiaSpecjalnych As New List(Of Panel)
'przechowuje panele specjalne przy bramce
Dim miejscaSpecjalnePrzyPramce_lewa As New List(Of Panel)
Dim miejscaSpecjalnePrzyPramce_prawa As New List(Of Panel)
Private Sub generujPaneleGlowne()
For i As Integer = 1 To szerokosc
Dim listapaneli As New List(Of Panel)
For j As Integer = 0 To wysokosc + 1
Dim panelPodstawowy As New Panel
With panelPodstawowy
.Location = New Point(i * 49 - 10, j * 49 - 10)
.Size = New Size(20, 20)
.BackColor = Color.Transparent
.Name = "panL_" + i.ToString + j.ToString
.Cursor = Cursors.Hand
'' AddHandler .Click, AddressOf pan_Click
End With
If i = 1 Or i = szerokosc Or j = 0 Or j = (wysokosc + 1) Then
If j = Math.Ceiling(wysokosc / 2) Then
listapaneli.Add(panelPodstawowy) 'dodaje pojedyńczy panel przy bramce (jasny zielony kolor na obrazku w tutorialu)
Else
'dodaje panele autów (zielony kolor na obrazku w tutorialu)
If (i = 1 And j = 0) Or (i = 1 And j = (wysokosc + 1)) Or (i = szerokosc And j = 0) Or (i = szerokosc And j = (wysokosc + 1)) Then
panelPodstawowy.Visible = False
panelPodstawowy.Enabled = False
'jeśli panel znajduje się na rogu planszy to nie dodajemy go do listy
End If
listaLokalizacjiaSpecjalnych.Add(panelPodstawowy)
listapaneli.Add(panelPodstawowy)
End If
Else
listapaneli.Add(panelPodstawowy) 'dodaje wszystkie panele (czerwony kolor na obrazku w tutorialu)
End If
'dodaje miejsca przy bramce (żółty kolor na obrazku w tutorialu)
If i = 1 Or i = szerokosc Or j = 0 Or j = (wysokosc + 1) Then
If j = Math.Ceiling(wysokosc / 2) Or j = Math.Ceiling(wysokosc / 2) - 1 Or j = Math.Ceiling(wysokosc / 2) + 1 Then
If i = 1 Then
miejscaSpecjalnePrzyPramce_lewa.Add(panelPodstawowy)
Else
miejscaSpecjalnePrzyPramce_prawa.Add(panelPodstawowy)
End If
End If
End If
Panel_glowny.Controls.Add(panelPodstawowy) ' Umieszcza elemeny na planszy
Next
listaLokalizacji.Add(listapaneli)
Next
End Sub
#End Region
Można teraz aktywować element w Form_Load:
'wybiera środek planszy jako punkty startowy
panelAktualnieWybrany = listaLokalizacji(Math.Ceiling((szerokosc - 1) / 2))(Math.Ceiling((wysokosc) / 2))
(...)
GrafikaBoiska.FillEllipse(start, New Rectangle(panelAktualnieWybrany.Location.X + 5, panelAktualnieWybrany.Location.Y + 5, 10, 10)) 'dodaje grafikę punktu startowego
Wyznaczy nam to panel środka boiska i doda do gry piłkę (czarną kropkę).
Panele bramek dodamy sobie osobno to z powodu blokady, którą utworzymy, jeśli zbliżymy się wystarczająco blisko bramki, pole w bramce zostanie aktywowane i będziemy mogli strzelić gola. Odblokuj z Form_Load
'dodaje panele bramek
DodajBramki()
Kod który doda panele bramek to:
#Region "Dodaj panele bramek"
Dim bramka_1 As New Panel
Dim bramka_2 As New Panel
Private Sub DodajBramki()
Dim srodek As Integer = Math.Floor((wysokosc) / 2)
With bramka_1
.Location = New Point(0 - 10, (srodek + 1) * 49 - 10)
.Size = New Size(20, 20)
.BackColor = Color.Transparent
.Name = "gol1"
.Cursor = Cursors.Hand
.Visible = False
AddHandler .Click, AddressOf Bramka_Click
End With
With bramka_2
.Location = New Point((szerokosc + 1) * 49 - 10, (srodek + 1) * 49 - 10)
.Size = New Size(20, 20)
.BackColor = Color.Transparent
.Name = "gol2"
.Cursor = Cursors.Hand
.Visible = False
AddHandler .Click, AddressOf Bramka_Click
End With
Panel_glowny.Controls.Add(bramka_1)
Panel_glowny.Controls.Add(bramka_2)
End Sub
Public Sub Bramka_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Panel_glowny.Enabled = False 'blokuje panel główny gry
'' rysujlinie(DirectCast(sender, Panel)) 'rysuje linie strzału
MsgBox("Wygrałeś!!") ' informacj ao wygranej
End Sub
#End Region
Bramki to te panele podświetlone na żółto
Mamy bramki, mamy pola, mamy piłkę więc czas zacząć grę. Odblokuj wszędzie opcję:
AddHandler .Click, AddressOf pan_Click
I odblokuj metodę:
rysujlinie(DirectCast(sender, Panel))
Nasza metoda pan_click będzie wyglądała tak:
Public Sub pan_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
'' odblokujPanele(DirectCast(sender, Panel))
DirectCast(sender, Panel).Visible = False
rysujlinie(DirectCast(sender, Panel))
End Sub
Metoda rysująca linie jest dosyć skomplikowana:
Dim listaLini As New List(Of Tuple(Of Panel, Panel))
Dim zliczaj As Integer
Private Sub rysujlinie(ByVal pane As Panel)
BitmapaBoiska = New Bitmap(Panel_glowny.Width, Panel_glowny.Height)
GrafikaBoiska = Graphics.FromImage(BitmapaBoiska)
panelAktualnieWybrany.Visible = False
generujLinieBoiska()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Odblokowuje bramkę, jeśli piłka znajduje się w jej okolicy.
If miejscaSpecjalnePrzyPramce_prawa.Contains(pane) Then
bramka_2.Visible = True
Else
bramka_2.Visible = False
End If
If miejscaSpecjalnePrzyPramce_lewa.Contains(pane) Then
bramka_1.Visible = True
Else
bramka_1.Visible = False
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If listaLokalizacjiaSpecjalnych.Contains(pane) Then
'blouje elementy specjalne, gdy piłka znajduje się na aucie, niektóre elementy są blokowane
Dim mojindeks As Integer = listaLokalizacjiaSpecjalnych.IndexOf(pane)
If Not mojindeks - 2 < 0 Then
listaLokalizacjiaSpecjalnych(mojindeks - 2).Visible = False
End If
listaLokalizacjiaSpecjalnych(mojindeks + 2).Visible = False
listaLokalizacjiaSpecjalnych(mojindeks - 1).Visible = False
listaLokalizacjiaSpecjalnych(mojindeks + 1).Visible = False
zliczaj -= 2
End If
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
listaLini.Add(Tuple.Create(panelAktualnieWybrany, pane))
' Blokuje panele powiązane (czyli te linie co już są dodane)
For i As Integer = 0 To listaLini.Count - 1
If listaLini(i).Item1.Name = pane.Name Or listaLini(i).Item2.Name = pane.Name Then
listaLini(i).Item2.Visible = False
listaLini(i).Item1.Visible = False
zliczaj -= 1
End If
Next
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim myPen As Pen = New Pen(Color.Black, 2) ' kolor lini już dodanych
'rysuje dodane już linie
For i As Integer = 0 To listaLini.Count - 1
GrafikaBoiska.DrawLine(myPen, listaLini(i).Item1.Location.X + 10, listaLini(i).Item1.Location.Y + 10, listaLini(i).Item2.Location.X + 10, listaLini(i).Item2.Location.Y + 10)
Next
GrafikaBoiska.DrawLine(myPen, panelAktualnieWybrany.Location.X + 10, panelAktualnieWybrany.Location.Y + 10, pane.Location.X + 10, pane.Location.Y + 10)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'rysuje piłkę
GrafikaBoiska.FillEllipse(New System.Drawing.SolidBrush(Color.Gray), New Rectangle(pane.Location.X + 5, pane.Location.Y + 5, 10, 10))
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Panel_glowny.Image = BitmapaBoiska
panelAktualnieWybrany = pane
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
If zliczaj <= 1 Then
MessageBox.Show("Pat, przegrałeś!!", " Pat !!")
Panel_glowny.Enabled = False
End If
End Sub
Najpierw, generujemy grafikę i blokujemy panel, w którym aktualnie się znajdujemy. Następnie dodajemy grafikę boiska. Sprawdzamy, czy gracz znajduje się blisko bramki i odpowiednią bramkę odblokowuje. Kolejnym etapem jest lokalizacja specjalna, która ma dodatkowe ograniczenia (nie można się poruszać wzdłuż linii autu, ale można się odbijać od linii (przydatne, gdy podzielimy grę na dwóch graczy)). Kolejny etap to dodanie poprowadzonej przez nas linii do listy i blokada wybranych już paneli (poprowadzonych linii), dodanie poprowadzonych już linii do grafiki i linii aktualnie wykonanej. Na samym końcu dodajemy piłkę i zmieniamy grafikę boiska na aktualną. Efekt:
Gra nie ma jeszcze swoich ograniczeń, co powoduje wiele błędów, jednym z nich jest dostępność wszystkich pól, więc linie można robić, jak się żywnie podoba. Nasze ograniczenie siedzi w metodzie:
odblokujPanele(DirectCast(sender, Panel))
Która ogranicza zasięg dostępnych pól, zmniejsza miganie planszy i pozwala na wprowadzenie zasad gry w życie.
Private Sub odblokujPanele(ByRef WybranyPanel As Panel)
Dim pozycjax As Integer = 0
Dim pozycjay As Integer = 0
zliczaj = 0
'pobiera aktualną pozycję naszego panelu
For i As Integer = 0 To listaLokalizacji.Count - 1
For j As Integer = 0 To listaLokalizacji(i).Count - 1
If listaLokalizacji(i)(j).Name = WybranyPanel.Name Then
pozycjax = i
pozycjay = j
End If
Next
Next
'odblokowuje pobliskie panele, następnie metoda rysujlinie- wprowadza ograniczenia
For i As Integer = 0 To listaLokalizacji.Count - 1
For j As Integer = 0 To listaLokalizacji(i).Count - 1
If i >= pozycjax - 1 And i <= pozycjax + 1 Then
If j >= pozycjay - 1 And j <= pozycjay + 1 Then
listaLokalizacji(i)(j).Visible = True
zliczaj += 1
Else
listaLokalizacji(i)(j).Visible = False
End If
Else
listaLokalizacji(i)(j).Visible = False
End If
Next
Next
End Sub
Jak zauważyliście metoda odblokujPanele, jest przed metodą rysujlinie, spowodowane jest to tym, że pierwsza metoda blokuje wszystkie panele i odblokowuje wszystkie panele +1 i -1, a następnie metoda rysujlinie wprowadza ograniczenia. Dwie metody połączone umożliwiają grę :]
W taką grę można sobie pograć z kolegą lub pójść o krok dalej i stworzyć AI, które będzie grało z nami. Wszystko jest w dostępne w programie, aby bez problemu dodać podział na tury z uwzględnieniem obijania się od ścian i od linii. Zostawiam to wam do zrobienia, jeśli będziecie mieli problem ze stworzeniem takiego podziału, to piszcie.
Pełen kod dostępny jest tutaj: Pilkarzyki_visualmonsters.cba.pl (2017-08-18)
kod źródłowy: kod_zrodlowy_pilkarzyki (2017-08-17)









