目标是学习C#,XAML,尤其是MVVM,我开始编写扫雷游戏。我创建的第一个版本没有MVVM部分,我创建并添加了带有C#代码的按钮,而不是通过MVVM方式在XAML中进行。现在我尝试将MVVM模式应用到游戏中。
我制作了一个自己的用户控件,其中包含一个代表雷区部分的按钮。此控件还具有ViewModel和Model Class,用于存储某些状态数据并处理某些命令。在测试项目中,我创建了4个自己的用户控件,并尝试将它们放在一个网格中,按钮形成一个2×2按钮的正方形。在后面的代码中,按钮放在ObservableCollection对象中。我假设在这个对象中列出的按钮和索引如下:
Button1
Button2
Button3
Button4
但在演示网格中我希望按钮显示为
Button1 | Button2
--------+--------
Button3 | Button4
问题是:我该如何动态地做到这一点?在我的测试项目中我使用4个按钮进行测试,但在项目中我想使用它,按钮的数量可能会有所不同,具体取决于玩家选择的游戏难度。
第二个问题是我如何弄清楚按钮的neigbhours是什么。因此,如果网格是4乘5包含20个按钮。例如,我选择按钮8,它具有相邻按钮编号2,3,4,7,9,12,13和14.当列出按钮时,如何到达那些邻居按钮?
我希望我的问题足够清楚。
提前谢谢!
答案 0 :(得分:4)
您可以使用ItemsPanel
设置为Grid
或UniformGrid
的{{3}}来展示您的收藏集。我有一些ItemsControl
示例ItemsControl可能对您有所帮助,因为我没有发现MDSN的示例非常有用。
如果您可以将UniformGrid
和Rows
属性绑定到Columns
中的媒体资源,那么ViewModel
最简单,但这需要您的所有单元格大小相同,我不记得属性Rows
和Columns
是否是参与绑定系统的DependencyProperties。
<ItemsControl ItemsSource="{Binding MyCollection}">
<!-- ItemsPanelTemplate -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding ColumnCount}"
Rows="{Binding RowCount}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
如果这对您不起作用,您可以使用Grid
作为ItemsPanel
,并在Grid.Row
中设置Grid.Column
和ItemContainerStyle
绑定。
这将要求您在ObservableCollection
中的每个单元格对象上都有属性来说明该单元格所在的行/列,但我怀疑您无论如何都需要这些属性来确定相邻单元格中的内容。点击命令。
此外,没有内置的方法可以绑定Grid
中的行数/列数,因此我倾向于使用一些here来动态构建网格RowDefinitions
和ColumnDefinitions
基于约束值。
因此,如果您使用网格,最终结果可能如下所示:
<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>
模型/ ViewModel看起来像这样
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;
}
答案 1 :(得分:1)
最近,我解决了扫雷游戏逻辑,进行了一场软件开发竞赛。 我认为他的游戏的主要问题是找到相邻的地雷和物品周围的相邻空单元。 在这两种情况下,我们必须考虑到最多每个单元格(项目)可以被八个项目(单元格)包围。 如果我们考虑一个4x4网格(矩阵)由X,Y坐标定义的单元格C,它将被以下单元格包围:
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)
换句话说,我们可以通过平移x和y轴上的点来找到项目的相邻单元格。
我通过游戏逻辑(后端)分割游戏的呈现(前端)来开发一个类集。
实际上,通过使用此策略,您可以在不同的.Net环境中使用它:我们不会围绕UI元素或组件“锁定”。
你可以在这里下载我的项目:
https://github.com/alchimya/csharp-minesweeper-sdk
答案 2 :(得分:-1)
脱离我的头顶:
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);
}
要跟踪周围的按钮,您需要知道网格的宽度是多少,例如,如果网格宽度为20个按钮,则按钮将如下所示:
[B-20-1][B-20][B-20+1]
[B-1] [B] [B+1]
[B+20-1][B+20][B+20+1]
其中B =点击按钮。
当然,您必须检查没有值离开网格(B-20-1不小于0,B + 20 + 1不大于按钮数量。)但是这很容易做到。