Fragen zu Memory-Spiel in VB.NET

  • VB.NET

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Fragen zu Memory-Spiel in VB.NET

    Moin,

    ich code derzeit ein kleines Memory-Spiel in VB.NET, das durch Nutzer erweitert werden kann. Der Nutzer kann seine eigenen Kartenstapel laden;

    Es werden u.a. die Karten Karte_01.jpg bis Karte_17.jpg aus einem Ordner geladen. Zunächst sind die insgesamt 34 Karten (Paare) natürlich "verdeckt", das heißt, die auf dem Bildschirm verteilten PictureBoxes (ja, wahrscheinlich als Control eine richtig schlechte Variante, kenne mich mit diesem GDI+ aber nicht aus, passt also vorläufig) haben als Image eine verdeckte Karte.

    Das Interface (GUI) und Grafiken sind schon vorhanden, natürlich nicht fertig.

    Erste Hürde (Stapel bilden):


    Die 17 Karten.jpgs sollen per Random den insgesamt 34 Karten (PictureBox) zugewiesen werden, dabei muss natürlich beachtet werden, dass jedes einzelne Karten.jpg zweimal zugewiesen werden muss (= 34 Karten) und nicht doppelt und die fertigen Paare vom Programm schließlich ermittelt werden. Tja ...

    Zweite Hürde (Spielzüge ermitteln):

    Der Spieler kann maximal zwei Karten aufdecken, bei jedem Klick auf eine PictureBox wird z.B. der Public Integer Spielzuege um 1 erhöht. Erreicht dieser den Wert 2, wird ein weiterer Public Integer Versuche (für die Statistik) um 1 erhöht, die Karten wieder zugedeckt und Spielzuege zurückgesetzt. Ließe sich dies mit einem Timer realisieren oder bräuchte man dafür 'ne eigene Function, von welchen ich auch keinen Plan habe? If-Abfrage bei jedem einzelnen Klick (MouseClick) aufs Spielfeld (Form1)?


    Dritte Hürde (Ermitteln, ob Paar richtig ist und Spielende):

    Wurden zwei Karten aufgedeckt, muss ermittelt werden, ob ein passendes Paar, aus Schritt 1. ermittelt, gefunden wurde. Wenn ja, werden die Karten vom Spielfeld genommen und dem Integer Punktestand 1 hinzugefügt. Hat dieser den Wert 17 erreicht, ist das Spiel zu Ende und es kann aus den Versuchen ermittelt werden ob "gut" gespielt wurde. Der Spieler könnte sich aber auch einen eigenen Schwierigkeitsgrad setzen, z.B., dass er maximal 20 Versuche hat. Das dürfte nicht allzu schwierig sein, Voraussetzung ist jedoch die Realisierung von Schritt 1 und 2.

    Vierte Hürde (K.I):


    Das lass' ich erstmal bleiben, es soll aber auch gegen den Computer gespielt werden können. Der deckt, eigentlich genau wie der menschliche Spieler, Karten zufällig auf und merkt sich, je nach Schwierigkeitsgrad, eine gewisse Anzahl an Karten die schon einmal aufgedeckt wurden. Bei zwei gleichen, die schon einmal aufgedeckt wurden, steigt die Wahrscheinlichkeit mit zunehmenden Schwierigkeitsgrad, dass der Computer diese nimmt.

    Also, ich bräuchte vor allen Dingen bei Schritt 1 (und Schritt 2) ein paar Tipps, bin völliger Anfänger, was das anbelangt. :D

    Das derzeitige "Spiel" *LINK ENTFERNT*. Wollt ihr auch den Quellcode haben? :D

    Gruß

    Edit by der_Kurt:
    Keine EXE-Files außerhalb des Showrooms

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „der_Kurt“ ()

    Hi MrBlade,
    an deiner Stelle würde ich mein Konzept noch einmal überdenken, vorallem weil du es ja auch dynamisch statt statisch haben willst.
    Zeichne die Felder mit GDI und male mit .DrawImage() die Kartenbilder.
    Dazu kannst du dir zuerst eine List(of Rectangle) machen, wo Position und Größe der Felder festgehalten werden.
    Zusätzlich solltest du dein Projekt objektorientiert lösen. Das ist oft viel einfacher.
    Ich nehme mal an, dass du zurzeit die Kartenzuweisung zu den Pictureboxen fest im Code hast. Ich würde dir empfehlen mit einem XML-Searilizer zu arbeiten.
    [VB.NET] Tutorial über das Speichern und Laden von XML-Dateien
    Damit kannst du z.B ganz einfach dein Feld "laden" und wenn du dann automatisch eine Methode "FeldMischen()" einbaust, klappt das ganze wunderbar.
    Wenn jetzt jede Klasse "Karte" eine Property "FeldPlatz" hat und den Gegenspieler kennst, scheint es ganz einfach zu sein.
    Mein Vorschlag an dich.
    Zerlege dein Problem zunächst in Teilprobleme und setzte es dann zusammen. Vorher solltest du Paint öffnen, und ein Konzept aufmalen, welches du uns hier einmal zeigst.

    Edit: Die Skitze sollte so wie im Anhang sein. (die ist natürlich nur hingeklatscht und nicht sonderlich durchdacht)
    Bilder
    • sozb.png

      20,1 kB, 1.431×801, 231 mal angesehen
    Hi,

    Danke für deine Antwort.

    Okay, dann schau' ich mir mal das GDI an. Allerdings müssten .png-Dateien mit transparentem Hintergrund "gezeichnet" werden, die zugleich auch Felder sind, nicht irgendwelche, geometrischen Formen. ?(
    Damit kannst du z.B ganz einfach dein Feld "laden" und wenn du dann
    automatisch eine Methode "FeldMischen()" einbaust, klappt das ganze
    wunderbar.

    Wenn jetzt jede Klasse "Karte" eine Property "FeldPlatz" hat und den Gegenspieler kennst, scheint es ganz einfach zu sein.

    Mein Vorschlag an dich.
    Das schaue ich mir mal an. Aber wo liegt der Unterschied zwischen der Auslagerung in eine .xml-Datei und "im Code" selbst?

    Gruß
    Es ist strukturierter.

    Edit:
    Der Inhalt des XML's kann beschreibend geändert werden, Vorteil,
    der Code muss sein Quellcode nicht desweiteren überarbeitet bekommen.
    Mfg.eniking1998

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „enIking1998“ ()

    Okay, aber kann man's nicht einfach in eine Public Function packen? Ich sehe derzeit für mein Vorhaben keinen direkten Vorteil im Serialisieren.

    Noch eine konkretere Frage zur Umsetzung:

    Wie kann ich eine Zufallszahl von 1 bis 17 generieren lassen, die zweimal (= 34) vorkommt und die Datei Karte_Zufallszahl.png zufällig in PictureBoxes 1 bis 35 laden?

    Gruß
    Schau dir die Random-Klasse an. msdn.microsoft.com/de-de/library/vstudio/system.random.aspx
    Hier ein Beispiel.

    VB.NET-Quellcode

    1. Dim places As New List(Of Integer)
    2. Dim rnd As New Random()
    3. For i As Integer = 0 To 5
    4. Dim x As Integer = rnd.Next(0, 17)
    5. If Not places.Contains(x) Then
    6. places.Add(x)
    7. MessageBox.Show(x.ToString())
    8. End If
    9. Next

    Damit du keine doppelten Zahlen hast, musst du überprüfen, ob es diese Zahl schon gibt.
    So, du hattest mich per PN nach einem Vorschlag gefragt. Hier ist mal was mit GDI, also ohne Pictureboxen. Das Konzept ist eigentlich schon fast fertig. Musst du halt nur selber noch verfeinern und anpassen.

    Kartenpaar

    VB.NET-Quellcode

    1. Public Class Kartenpaar
    2. Public Property kOne As Karte
    3. Public Property kTwo As Karte
    4. Public Sub New(ByVal kO As Karte, ByVal kT As Karte)
    5. kOne = kO
    6. kTwo = kT
    7. End Sub
    8. Public Class Karte
    9. Public Property Image As Image
    10. Public Property Place As Integer
    11. End Class
    12. End Class
    Spielfeldcontrol

    VB.NET-Quellcode

    1. ''' <summary>Control, welches zum Anzeigen der Spielkarten ist</summary>
    2. Public Class Spielfeld
    3. Inherits Control
    4. ''' <summary>Die Felder (noch nicht 34)</summary>
    5. Public Property Fields As New List(Of Rectangle)
    6. Public ActualRect As Rectangle
    7. Public ClickedRect As Rectangle
    8. Public Sub New()
    9. Me.BackColor = Color.White
    10. Me.DoubleBuffered = True
    11. For i As Integer = 0 To 600 Step 100
    12. For n As Integer = 0 To 500 Step 100
    13. Fields.Add(New Rectangle(i, n, 80, 80))
    14. Next
    15. Next
    16. End Sub
    17. ''' <summary> Methode zum zeichnen</summary>
    18. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    19. MyBase.OnPaint(e)
    20. e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    21. 'Für jedes Feld
    22. For Each r As Rectangle In Fields
    23. 'Wenn die Mauspostion im aktuellen ist
    24. If r = ActualRect Then
    25. 'Wenn das Aktuelle geklickt wurde
    26. If ActualRect = ClickedRect Then
    27. '"Karte umdrehen"
    28. e.Graphics.DrawImage(My.Resources.Karte_1, New Point(r.X, r.Y))
    29. 'Rand zeichnen
    30. e.Graphics.DrawRectangle(Pens.Black, r)
    31. Else
    32. 'Sonst den Hover-Effekt
    33. e.Graphics.DrawImage(My.Resources.Card_Back_Hover, New Point(ActualRect.X, ActualRect.Y))
    34. End If
    35. Else
    36. 'Wenn gar nichts, einfach das Bild zeichnen
    37. e.Graphics.DrawImage(My.Resources.Card_Back___Kopie, New Point(r.X, r.Y))
    38. End If
    39. Next
    40. End Sub
    41. Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
    42. MyBase.OnMouseDown(e)
    43. ClickedRect = GetRectangle(e.Location)
    44. If Not ClickedRect = Nothing Then
    45. ' MessageBox.Show("Bild würde angezeigt werden")
    46. Me.Invalidate()
    47. End If
    48. End Sub
    49. Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
    50. MyBase.OnMouseMove(e)
    51. ActualRect = GetRectangle(e.Location)
    52. If Not ActualRect = Nothing Then
    53. Me.Invalidate()
    54. End If
    55. End Sub
    56. ''' <summary>Methode zum Herausfinden des aktuellen Felds</summary>
    57. Public Function GetRectangle(ByVal e As Point) As Rectangle
    58. Dim loc As Point = e
    59. Dim match = From c As Rectangle In Fields
    60. Where c.X < loc.X
    61. Where c.Y < loc.Y
    62. Where c.Width + c.X > loc.X
    63. Where c.Height + c.Y > loc.Y
    64. Select c
    65. If match.Count > 0 Then
    66. Return match(0)
    67. End If
    68. Return Nothing
    69. End Function
    70. End Class
    Bilder
    • k1.png

      66,25 kB, 309×347, 200 mal angesehen
    • k2.png

      54,18 kB, 316×250, 167 mal angesehen
    Danke, LaMiy, für deine Mühe; eigentlich wollte ich nur, dass du meinen bisherigen Code kommentierst und mir nichts Fertiges präsentierst, weil dies nun nicht länger von mir stammt. Aber ich kann ja zumindest was Abschauen. :thumbup:

    Gruß

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Mr.Blade“ ()

    Mr.Blade schrieb:

    kann ja zumindest was Abschauen
    Das war jetzt nicht viel Arbeit und ist wie gesagt nur der Ansatz. Es passiert ja noch nicht mehr als verdeckte Karten anzeigen.
    Das Wichtige ist jetzt, dass du die Modellierung deiner eigenen Karten (die müssen nach dem Schema auf 80x80 zugeschnitten werden, oder du verstehst den Code und änderst ihn :b ) gut hinbekommst.
    Wichtig ist, dass du den Code einfach verstehst. Wie man die Tastendrücke zuordnet etc... (Übrigens kannst du statt des LINQ-Ausrucks zur Bestimmung des Feld einfach Rectangle.IntersectsWith()) (oder ohne das With, bin mir nicht sicher) benutzten.
    Ja, hab' die Größe im Code schon angepasst, 80x80 wäre definitiv zu klein.

    Eine Frage:

    VB.NET-Quellcode

    1. Public Class Karte
    2. Public Property Image As Image
    3. Public Property Place As Integer
    4. End Class


    Was genau sagt Property aus?
    Property = Eigenschaft
    Einer Eigenschaft kann ein Wert zugewiesen werden.
    Also in dem Fall die Property Image...

    Als Beispiel:

    VB.NET-Quellcode

    1. PictureBox1.Image = Image.FromFile(Pfad)


    Der Eigenschaft Image von der PB wird hier der Wert zugewiesen.

    @LaMiy
    Oh, sorry! :D Danke.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    msdn.microsoft.com/en-us/library/e8ae41a4.aspx
    msdn.microsoft.com/en-us/library/vstudio/bc3dtbky.aspx
    msdn.microsoft.com/de-DE/library/65zdfbdt(v=vs.71).aspx

    @Trade
    Ja das ist richtig, aber PicureBox.Image erwartet ein Image, und keinen String.
    So würde das aussehen. PictureBox.Image = Image.FromFile(...) (oder PictureBox1.ImageLocation)
    Okay, Danke. Sorry für die Fragen, ist aber Neuland für mich. :thumbup:

    VB.NET-Quellcode

    1. Public Class Spielfeld
    2. Inherits Control


    Bedeutet vermutlich, dass in der Klasse Spielfeld "Elemente" von der Klasse Control übernommen \ geerbt (übersetzt) werden. Aber wo wird diese Klasse Control weiter definiert? Oder bedeutet das, dass Eigenschaften etc. von Windows Controls verwendet werden können?
    Das bedeutet, dass alles, also die Properties etc. davon geerbt wird und du das somit weiterverwenden kannst.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ja, Buch, dazu habe ich hier schon einen großen Fred eröffnet ... :D

    Danke für die Links und die kurze Erklärung.

    Mir wurde das Buch von Klaus Löffelmann zu VB.NET empfohlen, kostet aber stolze 50€, Online zwar kostenlos erhältlich, lese aber lieber abseits des LCD. Ich warte auf die neue Version oder kaufe mir in der Zwischenzeit etwas Günstigeres.

    Das Problem ist, dass mir Beispiel und Assoziationen zu einigen Begrifflichkeiten fehlen, wann verwende ich was etc. Krieg' ich aber schon hin mit der Zeit. :thumbup:

    Gruß
    Das Buch ist wirklich gut :)
    Am Anfang reicht aber auch das:
    microsoft.com/germany/msdn/akt…008DasEntwicklerbuch.aspx

    Ist sogar kostenlos.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Mr.Blade schrieb:

    Das Problem ist, dass mir Beispiel und Assoziationen zu einigen Begrifflichkeiten fehlen
    Da ist MSDN und der Objektbrowser dein Freund. (Ich google einfach immer so "WebClient msdn" und bekomme so die gewünschte Erklärung)
    msdn.microsoft.com/de-de
    Bilder
    • ojk.png

      121,57 kB, 1.505×758, 161 mal angesehen
    nanu - schon erledigt?

    Weil ich sehe das große Problem, dass garkein Datenmodell besteht, was die Logik eines Memory-Spiels abbildet.
    Also vom Kartenstapel ist schoma die Rede gewesen, immerhin. Für die Logik könnteman das sehr vereinfachen, wennman erstmal ein Zahlen-Memory programmieren täte, da brauch man sich über GDI nicht soo viele Gedanken machen.
    Zu Not schmeißt man Zufalls-Zahlen in eine Listbox, und ein Item anklicken bedeutet "reingeguckt".

    Aber was ist mit der Tatsache, dasses mehrere Spieler gibt, und die wechseln sich ab? Und wenn einer einen Treffer hatte, darf er nochmal?
    Und zum Spieler gehört ja auch der Stapel Treffer-Karten, den er besitzt.
    Und die Karten auffm Tisch werden ja entsprechend weniger 8|