Neuron – prosta gra logiczna

Chciałbym dzisiaj zaprezentować bardzo prostą i ciekawą grę. Rozwija ona pamięć i spostrzegawczość, zasady gry są bardzo proste. Gra składa się z planszy podzielonej na kwadraty, każdy kwadrat może być błędny lub poprawny. Należy zapamiętać, gdzie ułożone są poprawne kwadraciki i je wszystkie odsłonić. Gra do przetestowania dostępna do pobrania:

neuron

 

 

 

gra do przetestowania =>  neuron_visualmonsters-cba-pl

 

Projekt z tutoriala poniżej dostępny tutaj => neuron_visualmonsters-cba-pl

 

Tylko kod programu =>  neuron_visualmonsters-cba-pl

 

Obrazki użyte w projekcie => obrazekblad

 

 

 

Nasza gra będzie trochę mniej złożona, zaczynamy od dodania elementów do głównej formy gry:

neuron3

Rodzaj elementu Nazwa elementu ustawienia
Form Form1 Name: Form1
Text: Neuron VisualMonsters.cba.pl
Size: 499; 594
Panel Panel_glowny Name: Panel_glowny
Size: 459; 472
Location: 12; 12
BackColor: White
Anchor: Top, Bottom, Left, Right
Label Label1 Name: Label1
Text: Pozostało do odkrycia :
Location: 12; 498
Label Label2 Name: Label2
Text: 0/0
Location: 137; 498
Label Label3 Name: Label3
Text: Punkty:
Location: 271; 498
Label Label4 Name: Label4
Text: 0
Location: 320; 498

 

 

 

 

 

Główny silnik gry uruchamiał będzie się wraz z jej startem w Form_load, to on będzie generował planszę i dodawał główne elementy do listy. To w nim będzie zawarty poziom trudności i ilość punktów, jakie będzie można zdobyć, więc jego zrozumienie jest najważniejsze.

Public Class Form1

    Dim kolorTla As Color = Color.Transparent 'kolor tła gry
    Dim obrazekBledu As Bitmap = My.Resources.blad
    Dim Obrazek As Bitmap = My.Resources.obrazek
    Dim ListaKwadratow As New List(Of Panel) 'Lista, przechowuje wygenerowane kwadraciki
    Dim punktyDoZdobycia As Integer 'Określa ilość punktów jaką można zdobyć
    Dim iloscelementowUsuwanych As Integer 'Zasady gry wymagają aby razem z błędnym kwadratem znikały kwadraty odsłonięte


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'Określamy wielkość planszy do gry
        Dim wielkoscPlanszy As Integer = 3
        'Tworzy przezroczysty kolor dla obrazka (usuwa biały kolor)
        Obrazek.MakeTransparent(Color.White)
        obrazekBledu.MakeTransparent(Color.White)
        'Tworzy panel w którym będą zawieszone nasze małe kwadraty
        Dim panel_gry As New Panel
        'Wielkość naszego małego kwadratu, szerokość i wysokość
        Dim wielkoscKwadratu As Integer = 50

        'Pętla dobiera wielkość kwadratów jeśli nie mieszczą się na planszy gry
        If 50 * wielkoscPlanszy + 5 > Panel_glowny.Width Then
            wielkoscKwadratu = (Panel_glowny.Width - 5) / wielkoscPlanszy
        End If
        If wielkoscKwadratu * wielkoscPlanszy + 5 > Panel_glowny.Height Then
            wielkoscKwadratu = (Panel_glowny.Height - 5) / wielkoscPlanszy
        End If

        'Generuje wielkość i lokalizację głównego panelu zawierającego małe kwadraty
        panel_gry.Size = New Size(wielkoscPlanszy * wielkoscKwadratu + 1, wielkoscPlanszy * wielkoscKwadratu + 1)
        panel_gry.Location = New Point((Panel_glowny.Width - panel_gry.Width) / 2, (Panel_glowny.Height - panel_gry.Height) / 2)

        'Generuje zestaw małych kwadratów i wyświetla go na planszy
        For k As Integer = 0 To wielkoscPlanszy - 1
            For d As Integer = 0 To wielkoscPlanszy - 1
                Dim panelPodstawowy As New Panel
                With panelPodstawowy
                    .Location = New Point(1 + k * wielkoscKwadratu, 1 + d * wielkoscKwadratu)
                    .BackColor = kolorTla
                    .BackgroundImageLayout = ImageLayout.Stretch
                    .Cursor = Cursors.Hand
                    .Size = New Size(wielkoscKwadratu, wielkoscKwadratu)
                    .BorderStyle = BorderStyle.FixedSingle
                End With
                ''       AddHandler panelPodstawowy.Click, AddressOf pan_Click
                ListaKwadratow.Add(panelPodstawowy)
                panel_gry.Controls.Add(panelPodstawowy)
            Next
        Next
        Panel_glowny.Controls.Add(panel_gry)

        'Określamy, ile można zdobyć maksymalnie punktów
        punktyDoZdobycia = wielkoscPlanszy * 10
        Label4.Text = punktyDoZdobycia

        'Losuje nasze obrazki
        ''     losowanieZnaczkow(Math.Floor((wielkoscPlanszy ^ 2) / 2))

        'Jeśli klikniemy na zły kwadracik, razem z nim zniknie 'iloscelementowUsuwanych' znaczków odkrytych
        iloscelementowUsuwanych = 2
        'Blokuje możliwość kliknięcia na kwadracik w momencie wykonywania instrukcji
        kontrolerKlikniecia = True
    End Sub
End Class

Program najpierw sprawdza, czy wybrany rozmiar kwadratów połączona z wielkością gry zmieści się w głównym oknie gry, bez sensu byłaby gra, w której nie widać większości pól. Jeśli plansza nie mieści się w głównym oknie, wielkość kwadracików zostanie zmieniona. Nie ważne czy kwadraciki nie zmieszczą się na szerokość, czy na wysokość, pętla ta dopasuje tak nasze kwadraciki, że będą się mieścić:

        'Pętla dobiera wielkość kwadratów jeśli nie mieszczą się na planszy gry
        If 50 * wielkoscPlanszy + 5 > Panel_glowny.Width Then
            wielkoscKwadratu = (Panel_glowny.Width - 5) / wielkoscPlanszy
        End If
        If wielkoscKwadratu * wielkoscPlanszy + 5 > Panel_glowny.Height Then
            wielkoscKwadratu = (Panel_glowny.Height - 5) / wielkoscPlanszy
        End If

Wizualnie wygląda to tak:

neuron4

Formuła, nie jest bardzo skomplikowany, reszta elementów opisana jest w kodzie, a ciekawsze rzeczy będę jeszcze tłumaczył. Odblokowujemy teraz kolejny element generujący tym razem losowy dobór obrazków błędnych i poprawnych:

        'Losuje nasze obrazki
        losowanieZnaczkow(Math.Floor((wielkoscPlanszy ^ 2) / 2))

Określamy w nim ile ma się znajdować poprawnych obrazków.

    Dim ran As New Random
    Dim listaboolean As New List(Of Boolean)

    Private Sub losowanieZnaczkow(ByVal iloscPoprawnychPol As Integer)
        For i As Integer = 0 To ListaKwadratow.Count - 1
            listaboolean.Add(False)
        Next
        Dim iloscznaczkow As Integer = 0
        'Pętla uruchamiana jest do momętu wybrania odpowiedniej liczby 
        'losowych elementów bez powtórzeń (iloscznaczkow)
        Do
            Dim mojawylosowanawartosc = ran.Next(0, listaboolean.Count)
            If listaboolean(mojawylosowanawartosc) = False Then
                listaboolean(mojawylosowanawartosc) = True
                iloscznaczkow += 1
            End If
            If iloscznaczkow = iloscPoprawnychPol Then
                Exit Do
            End If
        Loop
        'Wyświetla ilość wybranych elementów
        Label2.Text = "0/" + iloscPoprawnychPol.ToString
    End Sub

Lista, która została stworzona na początku (listaboolean), przechowuje tylko informacje true/false kod wybiera nam losowo „iloscPoprawnychPol” i kończy pętle gdy „iloscznaczkow = iloscPoprawnychPol” najpierw lista wypełniana jest elementami false, a następnie losowo bez powtórzeń losujemy liczby i zmieniamy wybrane elementy listy na True. Na końcu wyświetlamy, ile jest pól do odkrycia w label2. Odblokujemy  teraz:

 AddHandler panelPodstawowy.Click, AddressOf pan_Click

W pętli tworzącej kwadraty. Doda ona do każdego naszego kwadratu formułę uruchamianą po jego kliknięciu. Ta formuła to:

    Dim panelWybrany As Panel
    Private WithEvents Timer1 As New Timer With {.Interval = 200}
    Private WithEvents Timer2 As New Timer With {.Interval = 1000}
    Dim kontrolerKlikniecia As Boolean = False
    Dim listaZlapanychObrazkow As New List(Of Panel)

    Public Sub pan_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If kontrolerKlikniecia = True Then 'blokuje grę, jeśli kwadraty są odsłonięte
            'rozpoczyna grę
            If Not Timer2.Enabled = True Then
                Timer2.Start()
            End If
            panelWybrany = DirectCast(sender, Panel) 'przechowuje wybrany przez nas panel w zmiennej

            Dim indeX As Integer = ListaKwadratow.IndexOf(DirectCast(sender, Panel)) 'wyszukuje indeks panelu w liście

            'Jeśli w liście "listaboolean" pod indeksem naszego kwadratu kruje się true (nasz poprawny obrazek) wtedy
            If listaboolean(indeX) = True Then 'Obrazek poprawny
                'wyświetla obrazek
                DirectCast(sender, Panel).BackColor = Color.FromArgb(30, Color.LimeGreen)
                DirectCast(sender, Panel).BackgroundImage = Obrazek
                DirectCast(sender, Panel).Enabled = False
                'dodaje nasz panel do listy odkrytych paneli
                listaZlapanychObrazkow.Add(DirectCast(sender, Panel))
                'wyświetla ilość zdobytych punktów
                Label2.Text = listaZlapanychObrazkow.Count.ToString + "/" + Math.Floor(ListaKwadratow.Count / 2).ToString

                'Kończy grę, jeśli odkryliśmy już wszystkie obrazki
                If listaZlapanychObrazkow.Count = Math.Floor(ListaKwadratow.Count / 2) Then
                    For i As Integer = 0 To ListaKwadratow.Count - 1
                        ListaKwadratow(i).Enabled = False
                        ListaKwadratow(i).BackColor = Color.FromArgb(100, Color.LimeGreen)
                        If listaboolean(i) = True Then
                            ListaKwadratow(i).BackgroundImage = Obrazek
                        Else
                            ListaKwadratow(i).BackgroundImage = obrazekBledu
                        End If
                        kontrolerKlikniecia = False
                        Timer2.Stop()
                    Next
                Else
                    kontrolerKlikniecia = True
                End If
            Else 'obrazek niepoprawny
                DirectCast(sender, Panel).BackColor = Color.FromArgb(30, Color.Red)
                DirectCast(sender, Panel).BackgroundImage = obrazekBledu
                kontrolerKlikniecia = False
                Timer1.Start()
            End If
        End If
    End Sub

Timer1 posłużą nam do wydłużenia czasu wyświetlania elementów, aby użytkownik mógł zdążyć, zapamiętać gdzie leży niepoprawny obrazek i które obrazki znikneły. Jeśli go nie użyjemy, to po kliknięciu nie pojawi się obrazek. Dlatego użyjemy zmiennej „KontrolerKlikniecia” która będzie blokowała możliwość kliknięcia, na czas działania Timera1 (użytkownik mógłby, kliknąć kilka pól co by spowodowało błąd gry). Timer2 będzie zmniejszał ilość punktów do zdobycia. Po kliknięciu, na kwadracik formuła sprawdza jego położenie w liście „ListaKwadratow” a następnie w „listaboolean” sprawdza, czy na określonym indeksie jest True, czy False. Jeśli True, wtedy doda nasz kwadrat do listy „ListaZlapanychObrazkow” i będziemy mogli go ukryć na późniejszym etapie gry. Jeśli obrazek jest poprawny, pętla pokażę, ile jest odkrytych obrazków i sprawdzi czy to już koniec gry. Jeśli to koniec gry, plansza zostanie odkryta czas zatrzymany a blokada włączona. Pętla:

            'rozpoczyna grę
            If Not Timer2.Enabled = True Then
                Timer2.Start()
            End If

Sprawdza, czy Timer2 jest włączony. Jeśli nie to go uruchamia (oficjale rozpoczęcie gry), to on będzie liczył nam punkty. Nasza form, ma już aktywne kwadraty:

neuron5

Uwaga, jeśli trafimy na czerwony krzyżyk, to gra się nam zablokuje, więc się nie przestraszcie. Zajmiemy się teraz Timerem2, tak jak było już mówione, zlicza on nam punkty. Jego szybkość ustawiona jest na jedną sekundę. W każdej sekundzie ilość punktów do zdobycia będzie maleć o jeden. Ilość punktów do zdobycia powinna być zależna od poziomu rozgrywki.

    Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
        'zmniejsza punkty do zdobycia o jeden
        punktyDoZdobycia -= 1
        'wyświetla te punkty w labelu na formie
        Label4.Text = punktyDoZdobycia.ToString
        'kończy grę, jeśli nie ma już żadnych punktów do zdobycia
        If punktyDoZdobycia <= 0 Then
            'pętla odkrywa wszystkie pola, podświetlając je na czerwono
            For i As Integer = 0 To ListaKwadratow.Count - 1
                If listaboolean(i) = True Then
                    ListaKwadratow(i).BackgroundImage = Obrazek
                Else
                    ListaKwadratow(i).BackgroundImage = obrazekBledu
                End If
                ListaKwadratow(i).BackColor = Color.FromArgb(255, Color.Tomato)
            Next
            'blokuje plansze
            kontrolerKlikniecia = False
            'wyłącza timer
            Timer2.Stop()
        End If
    End Sub

Oczywiście czas zmniejszania ilości punktów można zmienić tutaj:

    Private WithEvents Timer2 As New Timer With {.Interval = 1000}

Wielkość Intervalu na poziomie 1000 oznacza jedną sekundę (instrukcja wykonywana jest co sekundę). Ostatnim elementem gry jest Timer1:

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        'zatrzymuje timer
        Timer1.Stop()
        'usówa obrazek z klikniętego panelu 
        panelWybrany.BackgroundImage = Nothing
        panelWybrany.BackColor = kolorTla
        'jeśli ilość elementów w złapanym obrazku jest większa od ilości elementów do usunięcia  
        If listaZlapanychObrazkow.Count > iloscelementowUsuwanych Then
            Dim ilosc As Integer = 0
            For i As Integer = 0 To iloscelementowUsuwanych - 1
                'Wybierze losowy element
                Dim randomWybor As Integer = ran.Next(0, listaZlapanychObrazkow.Count)
                'usunie jego obrazek
                listaZlapanychObrazkow(randomWybor).BackgroundImage = Nothing
                listaZlapanychObrazkow(randomWybor).BackColor = kolorTla
                'usunie go z listy złapanych obrazków
                listaZlapanychObrazkow.RemoveAt(randomWybor)
            Next
        Else
            'Jeśli obrazków jest mniej to usunie je wszystkie
            If Not listaZlapanychObrazkow.Count = 0 Then 'chyba, że lista jest pusta i nie ma co usuwać
                For i As Integer = listaZlapanychObrazkow.Count - 1 To 0 Step -1
                    'usuwa jego obrazek
                    listaZlapanychObrazkow(i).BackgroundImage = Nothing
                    listaZlapanychObrazkow(i).BackColor = kolorTla
                    'wywala z listy
                    listaZlapanychObrazkow.RemoveAt(i)
                Next
            End If
        End If
        'aktualizuje ilość elementów do wyszukania
        Label2.Text = listaZlapanychObrazkow.Count.ToString + "/" + Math.Floor(ListaKwadratow.Count / 2).ToString
        'odblokowuje kliknięcie
        kontrolerKlikniecia = True
    End Sub

Dlaczego zatrzymałem timer zaraz po jego uruchomieniu, otóż nasza formuła najpierw poczeka 200 milisekund a następnie, wykona instrukcje w sobie zawartą. Jeśli zwiększymy wartość w:

    Private WithEvents Timer1 As New Timer With {.Interval = 200}

do 500 wtedy program odsłoni obrazek, poczeka pół sekundy, a następnie wykona instrukcje. Na kolejnym etapie najpierw nasza formuła musi kliknięty obrazek zasłonić, użytkownik już wie, co się pod naszym panelem kryje, gdyż daliśmy mu, pół sekundy na zobaczenie krzyżyka i można go już zasłonić. Następna pętla zasłania dodatkowo odkryte kwadraty (tak jak w zasadach gry). Tutaj następuje dylemat, ponieważ mamy dwie sytuacje, pierwsza to taka, że złapanych obrazków jest więcej niż obrazków do zasłonięcia, a druga to obrazków złapanych jest mniej. W pierwszej sytuacji program losowo wybiera obrazki do zasłonięcia i usuwa je z listy, a w drugiej zasłania wszystkie odsłonięte elementy.  To by było na tyle, jak by były jakieś pytania, to proszę pisać.

neuron6

 

 

 

 

Permalink do tego artykułu: https://visualmonsters.cba.pl/neuron-prosta-logiczna/

Dodaj komentarz

Twój adres email nie będzie publikowany.