2012-11-27 5 views
3

avec l'objectif d'apprendre C#, XAML et surtout MVVM J'ai commencé à programmer le jeu Démineur. La première version que j'ai faite était sans la partie MVVM, où j'ai créé et ajouté les boutons avec du code C# au lieu de le faire en XAML via la méthode MVVM. Maintenant, j'essaie d'appliquer le pattern MVVM dans le jeu.Créer dynamiquement une Playboard pour le jeu Démineur

J'ai fait un propre contrôle utilisateur qui contient un bouton représentant une partie de champ de mines. Ce contrôle dispose également d'un ViewModel et d'une classe Model pour stocker certaines données d'état et gérer certaines commandes. Dans un projet de test, je crée 4 de ces contrôles utilisateur et j'essaie de les placer dans une grille où les boutons forment un carré de 2 par 2 boutons. Dans le code derrière, les boutons sont placés dans un objet ObservableCollection. Je suppose que les boutons sont répertoriés et indexés comme dans cet objet:

Button1 
Button2 
Button3 
Button4 

mais dans la grille de présentation je veux les boutons à afficher comme

Button1 | Button2 
--------+-------- 
Button3 | Button4 

La question est: comment puis-je faire dynamiquement? Parce que dans mon projet de test, j'ai testé avec 4 boutons, mais dans le projet que je veux utiliser, le nombre de boutons peut être différent en fonction de la difficulté du jeu que le joueur a choisi.

Et une deuxième question est comment je peux comprendre ce que les neigbhours sont d'un bouton. Donc, si la grille est de 4 par 5 contenant 20 boutons. Et par exemple je choisis le bouton 8 qui a comme boutons voisins les numéros 2, 3, 4, 7, 9, 12, 13 et 14. Comment puis-je atteindre ces boutons voisins quand les boutons sont listés?

J'espère que mes questions sont assez claires.

Merci d'avance!

+0

Utilisez la grille uniforme et calculer neigbours cellulaires en ajoutant des champs xpos, ypos à la cellule, puis les querieng LINQ sur les enfants uniformes – FLCL

Répondre

3

Vous pouvez afficher votre collection à l'aide d'un ItemsControl ayant ItemsPanel défini sur Grid ou UniformGrid. J'ai quelques ItemsControl exemples here qui peuvent vous aider, car je ne trouve pas les exemples de MDSN très utiles.

Un UniformGrid serait plus facile si vous pouvez lier vos Rows et Columns propriétés à une propriété dans votre ViewModel, mais qui nécessite toutes vos cellules soient de la même taille, et je ne me souviens pas si les propriétés Rows et Columns sont DependencyProperties qui participent au système de liaison ou non.

<ItemsControl ItemsSource="{Binding MyCollection}"> 
    <!-- ItemsPanelTemplate --> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Columns="{Binding ColumnCount}" 
         Rows="{Binding RowCount}" /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 

Si cela ne fonctionne pas pour vous, vous pouvez utiliser un Grid comme ItemsPanel et définir les liaisons Grid.Row et Grid.Column dans le ItemContainerStyle.

Cela nécessitera que vous ayez des propriétés sur chacun de vos objets de cellule dans le ObservableCollection pour dire dans quelle rangée/colonne cette cellule se trouve, cependant je suppose que vous en aurez besoin pour déterminer des éléments comme des cellules adjacentes dans votre commande click.

En outre, il n'y a aucun moyen intégré pour lier le nombre de lignes/colonnes dans votre Grid, donc je tendance à utiliser une custom attached properties qui construira dynamiquement RowDefinitions et ColumnDefinitions de la grille en fonction d'une valeur limite.

Ainsi, votre résultat final si vous utilisez une grille chercherais probablement quelque chose comme ceci:

<ItemsControl ItemsSource="{Binding Cells}"> 
    <!-- ItemsPanelTemplate --> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <!-- This is assuming you use the attached properties linked above --> 
      <Grid local:GridHelpers.RowCount="{Binding Height}" 
        local:GridHelpers.ColumnCount="{Binding Width}" /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 

    <!-- ItemContainerStyle --> 
    <ItemsControl.ItemContainerStyle> 
     <Style> 
      <Setter Property="Grid.Column" 
        Value="{Binding ColumnIndex}" /> 
      <Setter Property="Grid.Row" 
        Value="{Binding RowIndex}" /> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
</ItemsControl> 

avec un modèle/ViewModel regardant quelque chose comme ça

public class GameViewModel 
{ 
    // These should be full properties w/ property change notification 
    // but leaving that out for simplicity right now 
    public int Height; 
    public int Width; 
    public ObservableCollection<CellModel> Cells; 
} 

public class CellModel 
{ 
    // Same thing, full properties w/ property change notification 
    public int ColumnIndex; 
    public int RowIndex; 
    public bool IsVisible; 
    public bool IsMine; 
    public int NumberAdjacentMines; 
} 
+0

Merci pour cette excellente réponse! Je vais essayer si je l'ai fait fonctionner dans mon projet de test. – Cornelis

+0

Très instructif! +1! –

+0

C'était sûrement. Cela m'a aidé à résoudre mon problème. Encore merci! :) – Cornelis

-1

Du haut de ma tête:

List<Button> myButtons = new List<Button>(); 
Button myFirstButton = new Button(/*make first button*/); 
myButtons.Add(myFirstButton); 

void addButtonX() 
{//add new button along x axis 
    Button tempButt = new Button();   
    Button lastButt = myButtons[myButtons.count - 1]; 
    tempButt.posX = lastButt.posX + lastButt.sizeX; 
    tempButt.posY = lastButt.posY; 
    //other code for buttons 
    myButtons.Add(tempButt); 
} 
void addButtonY() 
{//add new button along y axis 
    Button tempButt = new Button(); 
    Button lastButt = myButtons[myButtons.count - 1]; 
    tempButt.posX = lastButt.posX; 
    tempButt.posY = lastButt.posY + lastButt.sizeY; 
    //other code for buttons 
    myButtons.Add(tempButt); 
} 

Pour garder une trace des boutons autour, vous devez savoir combien de boutons large de la grille est, par exemple, si la grille est de 20 boutons large, les boutons seront comme ceci:

[B-20-1][B-20][B-20+1] 
[B-1] [B] [B+1] 
[B+20-1][B+20][B+20+1] 

Où B = bouton cliqué.

Bien sûr, vous devrez vérifier qu'aucune valeur ne sort de la grille (B-20-1 n'est pas inférieur à 0, B + 20 + 1 n'est pas supérieur au nombre de boutons par exemple.), mais c'est assez facile à faire.

+0

-1 Première: Pas une bonne solution pour la création (l'utilisation de for imbriqué est beaucoup mieux!) et bien sûr le code ne fonctionne pas avec wpf! En outre, ce n'est pas une bonne solution pour trouver les boutons à côté d'un autre bouton. –

+0

Vous pouvez utiliser des fors imbriqués, c'est pourquoi addButtonX et addButtonY sont des fonctions. Ce n'est pas censé être un code exhaustif, juste un squelette de la façon de l'accomplir. Quant à savoir quels boutons sont adjacents, qu'est-ce qui ne va pas? – gaynorvader

+0

Si vous utilisez des fors imbriqués, vous n'avez pas besoin de deux méthodes. C'est juste du code dupliqué. Regardez la réponse de la femme, il explique beaucoup mieux comment archiver ce que le propriétaire de la question veut. Et bien sûr, elle a des exemples de travail et utilise les fonctionnalités intégrées de WPF pour la tâche donnée. –

1

Récemment, je résolu le démineur la logique du jeu, pour une sorte de concours de développement logiciel. Je pense que le principal problème de son jeu est de trouver les mines adjacentes et les cellules vides adjacentes autour d'un objet. Dans les deux cas, nous devons considérer qu'au maximum chaque cellule (élément) peut être entourée de huit éléments (cellules). Si l'on considère une grille de 4x4 (matrice) une cellule C définie par un X, Y coordonnées, il sera entouré par les cellules suivantes:

C1 (X-1,Y-1) 
C2 (X,Y-1) 
C3 (X+1,Y-1) 
C4 (X-1,Y) 
C5 (X+1,Y) 
C6 (X-1,Y+1) 
C7 (X,Y+1) 
C8 (X+1,Y+1) 

En d'autres termes, nous pouvons trouver les cellules adjacentes d'un élément en traduisant un point sur les axes x et y. J'ai développé un ensemble de classes en divisant la présentation du jeu (front-end) par la logique du jeu (back-end).
En utilisant cette stratégie, vous pouvez l'utiliser avec un environnement .Net différent: nous ne sommes pas "verrouillés" autour des éléments ou des composants de l'interface utilisateur.
Vous pouvez télécharger mon projet ici:
https://github.com/alchimya/csharp-minesweeper-sdk

Questions connexes