WPF Schiebepuzzle

    • Beta
    • Open Source

    Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von Nofear23m.

      Die Versionnummer habe ich noch nicht angepasst da die Version noch nicht Released, aber auf deinen Screenshot ist eben der neue Footer mit "Powered by Sascha Patschka - Idea by flori2212".
      Und der AboutDialog ist auch schon drinnen.

      Grüße
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Hallo @NoIde

      So, nun den Code aktualisiert. So wie es es meintest funktioniert das mit dem mischen viel besser. Sehr gute Idee.
      Vieleicht kannst du das ja mal probieren. Danke im Voraus.

      Je nach Level muss nun ein gewisser Prozenzsatz an Steinen "nicht korrekt" sein.

      Level 1 = 30%
      Level 2 = 40%
      Level 3 = 50%
      Level 4 = 60%
      Level 5 = 70%
      Level 6 = 80%

      Grüße
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Nabend,

      das sieht schon deutlich besser aus. :thumbup: Es scheint sich aber ein Bug eingeschlichen zu haben. Bei jedem 2. klick wird das Spiel zurück gesetzt aber nicht gemischt.

      Edit: @Nofear23m
      Hab den Fehler gefunden. In der Sub CreateField scheint nur Status?.RefreshStatus(AllButtons.ToList) gefehlt zu haben(nachdem die Buttons hinzugefügt wurden).
      Cloud Computer? Nein Danke! Das ist nur ein weiterer Schritt zur totalen Überwachung.
      „Wer die Freiheit aufgibt, um Sicherheit zu gewinnen, wird am Ende beides verlieren.“
      Benjamin Franklin

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

      Das fürs ausprobieren und den BugReport.

      Da hast völlig recht. Habe den Fehler korrigiert. Danke dir!
      Also kann man das mit dem Mischen so mache denke ich, jetzt mischt er glaube ich brav.

      Grüße
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Hallo Sascha,
      ich finde das Spiel richtig gut gelungen.
      Das schaut optisch schon ziemlich gut aus :thumbsup:
      Ich würde es gerne nachbauen in der Hoffnung das mit
      dem WPF und der MVVM einigermaßen zu verstehen.
      Natürlich nur wenn du nichts dagegen hast.
      Womit hast du angefangen oder wie geht man da am
      einfachsten vor? :)

      Amro schrieb:

      Womit hast du angefangen oder wie geht man da am
      einfachsten vor?

      Man macht meiner Meinung nach immer das Model zuerst. Die View - und dann das ViewModel.

      Ich gehe immer so vor das ich das Model mache. Ich weis welche Daten ich habe oder benötige also mache ich mir "flache" Modelklassen. Oder auch POCO-Klassen genannt.
      POCO = PlainOldClassObjects

      Dann mach ich mir eine Skizze von meinen Views. Man kann die Views auch schon mal in XAML machen ohne das Binding zu "vollziehen". Anhand dieser weis ich ca. wie mein ViewModel aussehen muss. Also welche Properties und welche Commands ich benötige. Wenn ich das VM soweit habe mache ich das Binding im View und sehe ob alles funzt wie ich das will.

      Wenn du das Spiel "nachbauen" willst empfehle ich aber am Anfang immer (wenn man richtiges MVVM machen will) das man die Projekte trennt. Also nicht so wie ich es bei dem Spiel gemacht habe sondern in verschiedene Projekte innerhalb der Projektmappe unterteilt. so kann man nicht "unabsichtlich" etwas aus der View im ViewModel verwenden.

      Also folgende Projekte in der Projektmappe:

      App (WPF Desktopanwendung)
      View (WPF Benutzersteuelementenbibliothek)
      Model (Klassenbibliothek)
      ViewModel (Klassenbibliothek)

      Das ViewModel hat einen Verweis auf das Model
      Die View hat einen Verweis auf das ViewModel
      Die App hat einen Verweis auf alle Projekte.

      Und wenn du wo nicht weiter weist oder wo "hängst" fragst du einfach.

      Grüße
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Nachdem ich mir endlich vs2017 installiert hab, kann ich nu auch wieder mitspielen.
      Ich hab mir das Schiebepuzzle mal vorgeknöpft, und die Designzeit-Unterstützung verbessert.
      Das liegt mir ja sehr am Herzen, dass man in Wpf Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor anwendet, so gut es geht.
      Ansonsten ist Xaml ja eine gammelige Sprache - also was man sich da alles an "String-Smells" aus der Nase ziehen muss, um ein Binding zu formulieren ist ja eine Zumutung - in Zeiten von BackgroundCompiler und Intellisense.
      Aber wie gesagt: richtig angefasst kann man die meisten Bindings designen statt hinzukrückeln, und dann sieht man sogar direkt obs passt - nicht erst beim Testlauf.
      Damit hat Wpf sogar wieder einen Vorzug gegenüber etwa dem Binding-Designing in WinForms.

      War mit dem Schiebepuzzle nicht so einfach das zu gewährleisten, weil die Bilder per relativen Datei-Pfaden angesprochen werden, und die unterscheiden sich zwischen Lauf- und Designzeit.
      Lösung war, mindestens ein Bild in die Resourcen zu nehmen und über Uri anzusprechen.
      Konzeptionell glatter wäre natürlich, von vornherein alle Bilder als Resource aufzunehmen - Dateipfade in Code werden häufig problematisch, zB wenn man ein InstallationsPacket basteln will.



      MVVM
      Boshafterweise kann ich mir nicht verkneifen, drauf hinzuweisen, dass MVVM hier gradezu irreführend implementiert ist. Imo dürfte das NoFears eigenem Verständnis widersprechen.
      Weil was macht ein Schiebepuzzle aus, was ist also zu modellieren?

      Man hat im Quadrat angeordnete Spielsteine, und einer fehlt.
      Ein Spielzug bewegt nun einen angrenzenden Stein auf das freie Feld.

      Bzw eine sinnvolles alternatives Model wäre: Man hat quadratisch angeordnete Spielsteine, und einer davon ist "Placeholder".
      Ein Spielzug tauscht nun einen angrenzenden Stein mit dem PlaceHolder.

      Das hätte sich eiglich im Model-Ordner abgebildet finden müssen - stattdessen finde ich dort Settings und Sounds (ob es da richtig angesiedelt ist, bin ich unentschlossen).

      Das tatsächliche SpielModell ist im Viewmodel implementiert, die Steine sind leicht aufzufinden, aber ihre Anordnung ist recht versteckt:
      Nämlich in GamePlay gibt es eine ObservableCollection(Of PlayStone).
      Also es gibt gar keine quadratische Anordnung, sondern nur eine lineare Liste, deren Elemente dann aber im View im UniformGrid quadratisch angeordnet präsentiert werden.
      Ansonsten wie in Model2: Ein Spielzug tauscht einen Stein mit dem PlaceHolder - allerdings mit listiger Logik, die bestimmt, welche Steine als am PlaceHolder angrenzend aufzufassen sind.



      Mit diesem Viewmodel bin ich ganzngar einverstanden, es ist echt schlau, statt einer quadrat-Matrix eine Liste herzunehmen, weil das UniformGrid zur Anzeige ist schon unverschämt praktisch.
      Ich hab allerdings drastisch kürzen können, sodass ich das Implementierungs-Konzept nu in 2 übersichtlichen Listings vorstellen kann:

      VB.NET-Quellcode

      1. Public MustInherit Class PlayStone
      2. Public Sub New(number As Integer)
      3. _Number = number
      4. End Sub
      5. Public ReadOnly Property Number() As Integer
      6. End Class 'PlayButton
      7. Public Class Placeholder : Inherits PlayStone
      8. Public Sub New()
      9. MyBase.New(-1)
      10. End Sub
      11. End Class 'Placeholder
      12. Public Class NumberedPlayButton : Inherits PlayStone
      13. Public Sub New(number As Integer)
      14. MyBase.New(number)
      15. End Sub
      16. End Class 'NumberedPlayButton
      17. Public Class ImagePlayButton : Inherits PlayStone
      18. Public Sub New(number As Integer, image As BitmapImage)
      19. MyBase.New(number)
      20. _Image = image
      21. End Sub
      22. Public ReadOnly Property Image() As BitmapImage
      23. End Class 'ImagePlayButton
      Also "PlayButton" gibts sogar in 2 Varianten, nämlich eine davon stellt ein Image bereit. So kann das Schiebepuzzle entweder als Zahlenpuzzle oder als Bild-Puzzle gespielt werden.
      Wollte man hier trennen zw. Model und Viewmodel, so würde Playstone sicherlich ins Model wandern, die anderen sind Viewmodels.
      (Aber für "reines" MVVM gibts glaub ein "Gesetz", dass Viewmodel nicht von Model erben darf - es würde also wieder deutlich komplizierter, wollte man sich dem unterwerfen)

      VB.NET-Quellcode

      1. Public Class GamePlay : Inherits ViewModelBase
      2. Private ReadOnly _soundCollector As New SoundCollector
      3. Public WithEvents GameSettings As New GamePlaySettingsVm
      4. Public ReadOnly Property AllButtons() As New ObservableCollection(Of PlayStone)
      5. Public ReadOnly Property Status() As New GameStatus
      6. Public Property MoveButtonCommand() As New RelayCommand(AddressOf MoveButtonCommand_Execute)
      7. Public Property MixStonesCommand() As New RelayCommand(AddressOf MixStonesCommand_Execute)
      8. Private _currentImage As BitmapImage
      9. Public Property CurrentImage As BitmapImage
      10. Get
      11. Return _currentImage
      12. End Get
      13. Set(value As BitmapImage)
      14. _currentImage = value
      15. RaisePropertyChanged()
      16. End Set
      17. End Property
      18. '...
      GamePlay enthält v.a. die genannte Auflistung der Spielsteine, und zur Interaktion die die beiden Commands zum Mischen und zum Ziehen eines Steins.



      BindingPicking, Xaml-Vorschau
      Das annere was ich gemacht hab - was mir ja am wichtigsten ist - ist die Bereitstellung von DesignTime-Daten, sodass Binding-Picking anwendbar ist, und Xaml nu eine Vorschau bietet von dem, was man verbunden hat:
      . . .
      Beachte: Um mal die eine, mal die annere Ansicht im Xaml sehen zu können, muss man inne Settings-Klasse den GameType entsprechend setzen.
      (Und beachte auch das einfachere UniformGrid-Binding im rechten Bild)

      Jo, guckts euch mal an, und insbesondere das BindingPicking ausprobieren.
      Ein Wermutstropfen dabei ist, dass die InterAction.EventTrigger kein BindingPicking unterstützen - das können nur klassische Commands.
      Für Binding-Picking-Unterstützung wäre daher günstiger gewesen, die ImageButtons ebenso wie die NumberButtons über Button-Controls abzufackeln - mit einem ControlTemplate ausgestattet.
      Aber weiss ich nicht, was das wieder für annere Nachteile nachgezogen hätte.

      Auch täte mich interessieren, ob die TestDaten-Bereitstellung der BitmapSources die Designer-Vorschau messbar verzögert.
      Weil da sind zur Designzeit aufwendige Operationen nötig, um das Bild zu "zerstückeln".
      Was man normalerweise tunlichst vermeiden soll, bei Designtime-TestDaten - aber geht hier erstmal nicht anders.
      Dateien

      Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Hallo @ErfinderDesRades

      Danke für den detailierten Input und die Arbeit welche du dir angetan hast. Weis ich zu schätzen.
      Vorab möchte ich sagen das dieses "Spiel" mal schnell so nebenbei entstanden ist. Deshalb auch nicht die Trennung der M-V-VM Struktur in einzelne Projekte und fehlendem Refactoring.
      Ich weis, schande über mich, aber ich wollte einfach mal so ein kleines Minispiel nebenbei erstellen.

      ErfinderDesRades schrieb:

      Das liegt mir ja sehr am Herzen, dass man in Wpf Grundlagen - MVVM: "Binding-Picking" im Xaml-Editor anwendet, so gut es geht.

      Mir auch, jedoch nur bei "komplizierteren" ViewModels. Es ist richtig das ich hier in die Beispieldaten fehlen. Bindingpicking allerding funzt (genauso wie Intellisense) ohne Probleme möchte ich nur anmerken da ja der "DesignTime-Datenkontext gesetzt wurde. d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type={x:Type viewModel:GamePlay}}"
      Es fehlen lediglich die Beispieldaten und die habe ich echt selten enthalten da ich diese schlichtweg meisst nicht benötige. OK, ich gebe ehrlich zu das ich meisst einfach zu faul bin Designdaten zu erstellen. 8o

      ErfinderDesRades schrieb:

      Konzeptionell glatter wäre natürlich, von vornherein alle Bilder als Resource aufzunehmen - Dateipfade in Code werden häufig problematisch, zB wenn man ein InstallationsPacket basteln will.

      War absicht, ich möchte das man jederzeit eigene Bilder verwenden kann indem man diese einfach in der Ordner kopiert.

      ErfinderDesRades schrieb:

      Das hätte sich eiglich im Model-Ordner abgebildet finden müssen

      Da gebe ich dir schon irgendwie recht. Ist aber eben wieder aus dem Grund der "Faulheit" passiert. Warum?
      Bei echtem MVVM soll ja die View keinen Verweis auf das Model haben. das Model sollten immer reine POCO Klassen sein. Ich hätte also um die "Stones" noch ein StonesViewModel benötigt. Wollte ich mir sparen und das ich nicht vorhatte in Verbindung mit "Stones" etwas zu speichern oder zu laden (z.b. über Serialisierung) fand ich es nicht für notwendig da "Stones" in diesem Moment wieder nur die View und die Spiellogik betreffen und sohin im ViewModel eigentlich am richtig Platz sind. Oder? Aber ich gebe dir recht, man hätte die Stones ruig in die Models verschieben können aber wie gesagt, da es dort gar nicht benötigt wird wäre es unnötige Arbeit.

      ErfinderDesRades schrieb:

      allerdings mit listiger Logik

      Gebe ich dir wieder recht. Auf ganze Linie. ;)
      Für die "Logik" wollte ich wirklich keine Zeit investieren, muss aber auch sagen das ich da echt nicht gut bin. Da weis ich das du hier weit mehr Verständniss für hast als ich. Ich bin in sowas echt nicht gut. Gebe ich zu.

      ErfinderDesRades schrieb:

      Wollte man hier trennen zw. Model und Viewmodel, so würde Playstone sicherlich ins Model wandern, die anderen sind Viewmodels.
      (Aber für "reines" MVVM gibts glaub das "Gesetz", dass Viewmodel nicht von Model erben darf - es würde also komplizierter)

      Das meinte ich mit dem Kommentar im vorigen Zitat.

      ErfinderDesRades schrieb:

      Mit diesem Viewmodel bin ich ganzngar einverstanden, es ist echt schlau, statt einer quadrat-Matrix eine Liste herzunehmen, weil das UniformGrid ist schon unverschämt praktisch.

      Danke. Ja. Einfach und gut lesbar. Kenn mich mit Matrix auch nicht wirklich aus :D Hehe.
      Ich wollte mit dem Spielchen ja auch auf den Thread wo die Frage mit dem UniformGrid eben aufkahm eingehen. Um das gings mir ja eigentlich. :|


      Im Moment habe ich leider ein anderes Projekt mit Zeitdruck am laufen, aber sobald ich das habe sehe ich mir die Solution von dir sehr gerne an, bin schon gespannt drauf - aber da will ich mir Zeit nehmen.
      Danke für das Teilen deiner Meinung, ich schätze diese sehr.

      Schöne Grüße und schönes Wochenende
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

      Jo, nach all meim Gemecker (des is angeboren) könnte ich eiglich auch mal aufzählen was ich toll finde an dem Ding:
      Besonders beeindruckend, dass du das "so eben schnell mal" aus dem Ärmel geschüttelt hast.
      Allein schon die Design-Idee, mit SpielStatus, Spielfeld, optional als Bild-Puzzle, und wenn ja mit Bild-Vorschau - k.A., ob mir das jemals eingefallen wäre.
      Dassis so genial, das merkt man garnet mehr, dass das genial ist.
      Oder die Bitmap-BitmapSource-Konvertierung - wobei ich vermute, das ist nicht neu aussm Ärmel, sondern kommt aus einer Schublade.
      Und bitte als Kompliment auffassen, wenn ich von "listige Logik" rede.
      Betrifft Mischen, Zug machen, Nachbarn finden - finde ich alles sehr schlau gemacht, da hätte ich schon feste Ärmel schütteln müssen, um vergleichbares rauszubekommen.

      Aber muss ich ja garnet rausschütteln, ich brauch Gegebenes ja nur bemeckern.
      Ich weiss selbst, das ist viel einfacher, auch wenn ich als "Proof of Mecker" auch Teile um-implementiere.
      Hallo Eckard

      ErfinderDesRades schrieb:

      wobei ich vermute, das ist nicht neu aussm Ärmel, sondern kommt aus einer Schublade

      Jaja, ist aus einem "Helper" rauskopiert.

      ErfinderDesRades schrieb:

      Und bitte als Kompliment auffassen, wenn ich von "listige Logik" rede.

      Achso, ok.

      Aber nochmal: Ich finde in deinem ganzen Text jetzt keinerlei Kritik, habe es auch nicht so aufgefasst. Du hast einige super Dinge aufgezählt welche besser gingen und/oder du anders machen würdest. Und selbst wenn, Kritik ist gut! Oft weis man gar nicht das man wo einen Fehler macht oder etwas besser machen könnte, ich finde Kritik sofern Konstruktiv (und das ist bei dir fast immer der Fall) höchst wichtig.

      Und danke für die überaus netten Worte. :rolleyes:

      Grüße
      Sascha
      If _work = worktype.hard Then Me.Drink(Coffee)
      Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

      ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##