|
Tak se mi to podařilo nějak okomentovat, snad tedy funkčnost bude z kódu jasná. (bohužel toho komentování je tam více, než samotného kódu). Jinak to neberte jako poučení, že tak se to má dělat, ale spíše jako námět do diskuse, že takto to taky lze řešit (ještě jednou připomínám, že jsem taky začátečník a programátorský embryo). Samozřejmě tam není spousta věcí jako ošetření některých činností uživatele, spuštění nové hry, ukončení, vyhodnocování atd. - neměl jsem v úmyslu programovat si pexeso (a dokazovat si, jak už mi ta hlava neslouží), jenom jsem zkoušel řešit Vámi nastolený problém a hledal jsem, co je na něm tak komplikovaného. Ale k tomu kódu:
Public Class Form1
#Region "Deklarace proměnných"
Private Const rozmerObr As Integer = 100 ' velikost jednoho obrázku (předpoládám čtvercový obrázek)
Private Const pocetSloupcu As Integer = 8 ' požadovaný počet sloupců a řádků pexesa
Private Const mezera As Integer = 10 ' mezera mezi obrázky
Private obrazky As New ImageList ' ImageList - zásobárna pro naštení obrázků
Private PocetObrazku As Integer ' pomocná proměnná pro počet obrázků (dvojic)
Private pan As New Panel ' panel na který budu umisťovat Pictureboxy (abych si usnadnil jejich procházení a nepletly se mi mezi nimi ostatní Controly)
Private pic(1) As PictureBox ' pole dvou pomocných pictureboxů, které budu vybírat
Private otoceno As Integer = 0 ' čítač otočených karet
Private zpracovani As Boolean = False ' pomocný přepínač, aby se zamezilo kliknutí na další kartu v průběhu zpracovávání předchozích
Private nahodne As New Random ' generátor náhodných čísel (použitý pro míchání)
#End Region
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' spočítám počet potřebných obrázků (hodnotu potřebuji vícekrát, proto tato pomocná proměnná)
PocetObrazku = (pocetSloupcu ^ 2) / 2
' nastavení velikosti obrázků ukládaných do ImageListu
obrazky.ImageSize = New Drawing.Size(rozmerObr, rozmerObr)
' načtení pozadí
' na první pozici imagelistu (index "0") načtu pozadí karet Pexesa
' v projektu mám podadresář data a v něm obrázek s tímto pozadím s názvem pozadi.jpg
obrazky.Images.Add(Image.FromFile("data\pozadi.jpg"))
' načtení kolekce obrázků
' jelikož jsem líný a nechtělo se mi vymýšlet jména obrázků, udělal jsem si pod výše jmenovaný adresář
' "data" další podadresář "kolekce", do něj jsem nalil potřebný počet obrázků ve formátu .jpg
' a aniž se starám o jejich názvy, všechny je projdu a načtu do svého ImageListu
' Velice jednoduše by se takto daly řešit různé kolekce obrázků (vyberete si odpovídající
' adresář). Jediné, co nemám ošetřeno je, že musíte mít v adresáři minimálně tolik obrázků,
' kolik jich potřebujete do hry (v mém případě 8x8/2=32 obrázků)
For Each path As String In IO.Directory.GetFiles("data\kolekce", "*.jpg")
obrazky.Images.Add(Image.FromFile(path))
Next
Randomize()
' na plochu si "rozdám karty
rozdej()
' zamíchám obrázky na ploše
zamichej()
' nechtělo se mi hrát s počítadlem, tak si to boduju v titulku formuláře:
Me.Text = 0
End Sub
' vytvořím na formuláři základní hrací plán - vytvořím vlastní PictureBoxy (rozdám karty)
Private Sub rozdej()
' nejprve nadefinuju panel "pan", který bude kontejnerem pro mé PictureBoxy:
' levý horní roh mé hrací plochy na formuláři
pan.Left = 10
pan.Top = 25
' rozměr panelu (aby se do něj vešlo požadované množství obrázků nastavené velikosti
pan.Width = rozmerObr * pocetSloupcu + mezera * (pocetSloupcu - 1)
pan.Height = pan.Width
pan.BorderStyle = BorderStyle.None
' panel "pan" přidám na plochu mého formuláře Form1
Me.Controls.Add(pan)
' nyní do panelu nasázím na požadovaná místa požadované PictureBoxy:
For i As Integer = 0 To pocetSloupcu - 1 ' počítadlo řádků
For j As Integer = 0 To pocetSloupcu - 1 ' počítadlo sloupců
Dim img As New PictureBox ' nový PictureBox
img.Width = rozmerObr ' šířka PictureBoxu
img.Height = rozmerObr ' výška PictureBoxu
img.BorderStyle = BorderStyle.FixedSingle ' PictureBox obtažen tenkou linkou
img.SizeMode = PictureBoxSizeMode.StretchImage ' způsob vykreslování obrázků na PictureBox (zaplní celou plochu)
AddHandler img.Click, AddressOf kliknul ' pro pictureBox nastavím handler pro ošetření události "Click" - bude volána metoda "kliknul"
img.Left = j * (rozmerObr + mezera) ' vypočítám souřadnice levého horního rohu PictureBoxu (vztaženo k mému panelu Pan)
img.Top = i * (rozmerObr + mezera)
Me.pan.Controls.Add(img) ' přidám právě nadefinovaný PictureBox do kolekce Controls mého panelu "Pan"
Application.DoEvents() ' nemusí být, ale kdybych měl "moc" složitých kartiček, tak aby to celé v průběhu rozdávání nezamrzlo
Next
Next
End Sub
' provede vlastní zamíchání obrázků na hrací ploše
' mohlo by být součástí předchozího, ale předpokládám vícenásobné použití
' (třeba před novou hrou)
' současně "otočím" všechny karty rubem navrch
Private Sub zamichej()
' pomocné pole s počtem členů rovnajícím se celkovému počtu karet
Dim michani(PocetObrazku * 2 - 1) As Integer
' pomocné pole naplním čísly od 1 do "počtu obrázků" tak, aby každé z čísel bylo v daném poli 2x
' (stejně, jako každý obrázek se mezi kartami vyskytuje 2x)
' pouze upozornění - plním čísly od 1 do (v mém případě) 32, ale pole "michani" má indexy od 0 do 31
For i As Integer = 1 To PocetObrazku
michani((i - 1) * 2) = i
michani((i - 1) * 2 + 1) = i
Next
' takto naplněné pole seřadím "náhodně", tedy všechny prvky zůstanou, pouze je zpřeházím
Array.Sort(michani, AddressOf razeni)
' vytvořím si pomocný čítač pro procházení polem michani (správně na to existuje nějaký ukazatel, ale nad tím jsem nepřemýšlel)
Dim citac As Integer = 0
' tady využiju skutečnosti, že všechny PictureBoxy mám v panelu "Pan" a kromě jich tam nic nemám
' pokud tedy budu postupně procházet celou kolekcí Controls tohoto panelu
' pohodlně projdu všemi Pictureboxy
For Each pctbox As PictureBox In Me.pan.Controls
pctbox.Image = obrazky.Images(0) ' v Pictureboxu zobrazím obrázek z mého ImageListu s indexem "0" (tj. pozadí karty)
pctbox.Tag = michani(citac) ' do vlastnosti ".tag" každého Pictureboxu přiřadím hodnotu z pomocného pole "michani" s indexem (citac)
citac += 1 ' zvýším hodnotu čítače, abych pro příští PictureBox přiřadil do .TAGu následující číslo z pole "michani"
Next
End Sub
' pomocná funkce, která mi zapříčiní, že mi Výše použitá metoda "sort" seřadí pole náhodně
Private Function razeni(ByVal x As Integer, ByVal y As Integer) As Integer
If x = y Then
Return 0
Else
Return 2 * CInt(nahodne.Next(0, 2)) - 1
End If
End Function
' vlastní výkonná metoda, která se spustí ve chvíli, kdy uživatel klikne na libovolný z PictureBoxů
Private Sub kliknul(ByVal sender As Object, ByVal e As System.EventArgs)
' pokud probíhá zpracovávání předchozího kliknutí, vyskočíme z metody
' zamezíme tak konfliktům v případě splašeného uživatele
If zpracovani Then Exit Sub
' nastavíme příznak zpracovávání, abychom dále nebyli rušení nedočkavými hráči (viz výše)
zpracovani = True
' v proměnné "sender" máme konkrétní informaci, z kterého "pictureBoxu" volání metody přišlo
' jediným problémem je, že tato proměnná je obecného typu "object"
' abychom s ní mohli pracovat jako s PictureBoxem, přetypujeme ji právě na PictureBox
' a současně si odkaz na ni přiřadíme do naší pomocné proměnné pic na pozici "otoceno"
' pokud tedy není vybrána ještě žádná karta, přiřadíme si to do proměnní pic(0),
' pokud je již karta vybrána, do pic(1)
pic(otoceno) = CType(sender, PictureBox)
' s právě zaznamenaným PictureBoxem uděláme :
With pic(otoceno)
.Enabled = False ' znepřístupníme ho, aby na něj nemohl uživatel při příštím pokusu kliknout
.Image = obrazky.Images(CInt(.Tag)) ' zobrazíme na něm obrázek z našeho ImageListu z pozice, která se rovná číslu uloženému ve vlastnosti .tag našeho PictureBoxu
End With
' zvýšíme čítač otočených karet o 1
otoceno += 1
If otoceno > 1 Then vyhodnoceni() ' pokud nám nyní čítač ukazuje číslo větší než 1 znamená to, že již máme otočeny 2 karty a přejdeme na jejich vyhodnocení
' vypneme příznak zpracování, čímž umožníme uživateli další výběr
zpracovani = False
End Sub
' a vlastní metoda vyhodnocení otočených karet
' v tuto chvíli máme v proměnné pic(0) odkaz na pictureBox, který byl vybrán jako první
' a v pic(1) odkaz na picturebox, který byl vybrán jako druhy
Private Sub vyhodnoceni()
' zkontrolujeme číslo ve vlastnostech .tag obou pictureBoxů
If pic(0).Tag = pic(1).Tag Then
' zásah
' čísla se shodují, hráč se strefil - tady provedeme co se nám zlíbí
' já nechávám karty na místě, protože u nich zůstává .enabled na false
' nehrozí, že by mohl uživatel náš program zblbnout dalším klikáním na ně
' je možno, samozřejmě, obě karty schovat (tím, že pro obě nastavíme pic(0).hide=true a totéž pro pic(1)
' asi by se v praxi přičetla nějaká hodnota na počítadlo úspěšných zásahů,
' mě se nic takového nechtělo dělat, tek si jen počítám body v záhlaví formuláře
Me.Text = CInt(Me.Text) + 2
Else
' uživatel se nestrefil
' před další činností chvíli počkáme, aby uživatel viděl, co to otočil za kartu
' přestávku tvořím na několik úseků, aby to uživateli celé nezamrzlo (a mohl třeba posouvat s formulářem)
For i As Integer = 0 To 100
Threading.Thread.Sleep(10)
Application.DoEvents()
Next
' oběma pictureboxům nastavím zpátky původní obrázek pozadí
' a současně je zpátky zpřístupním pro další konání
pic(0).Image = obrazky.Images(0)
pic(0).Enabled = True
pic(1).Image = obrazky.Images(0)
pic(1).Enabled = True
' uberu uživateli "trestný bod"
Me.Text = CInt(Me.Text) - 1
End If
' nakonec vyčistím své dva pomocné pictureboxy ...
pic(0) = Nothing
pic(1) = Nothing
' ... a nastavím počet otočených karet na 0
otoceno = 0
End Sub
End Class
Je toho, bohužel, "o pár deka víc", ale snad vám alespoň něco z toho přijde podnětné. A nebojte se napsat, co mám blbě, co by bylo lepší udělat jinak - taky se učím a každá rada je přínosná
|