Piłkarzyki – prosta gra

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ę.

pilkarzykiico

 

 

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:

pilkarzyki1

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ę:

pilkarzyki2

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:

pilkarzyki3

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ę).

pilkarzyki4

 

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

pilkarzyki5

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:

pilkarzyki6

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ę :]

pilkarzyki7

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)

 

Permalink do tego artykułu: https://visualmonsters.cba.pl/pilkarzyki-prosta-gra/

Dodaj komentarz

Twój adres email nie będzie publikowany.