游戏功能
1、正常扫雷功能,游戏计时,
2、两种模式:①点击开始游戏直接开始普通模式,过一关游戏雷数增加,行和列增加;
②菜单栏选择初级难度、中级难度和高级难度;
3、右键点击插旗功能
4、游戏失败后点击重新开始刷新地图重新开始
5、通关后点击下一关进入下一关
各位请看图↓↓↓
游戏界面设计,包含菜单区域以及游戏区域和背景等等
<Window x:Class="练习.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:练习"
mc:Ignorable="d"
Title="扫雷" Height="600" Width="600" Icon="img/logo.ico" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30">
</RowDefinition>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="65"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Menu Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" >
<MenuItem Width="60" Height="30" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<MenuItem.Icon>
<Image Source="img/Sysico.ico"></Image>
</MenuItem.Icon>
<MenuItem.Header>
<Label Content="菜单" Margin="-10,0,0,0"></Label>
</MenuItem.Header>
<MenuItem Header="等级" Margin="0,0,0,0">
<MenuItem.Icon>
<Image Source="img/CustomerOrder.ico"></Image>
</MenuItem.Icon>
<MenuItem Name="first" Header="初级" Margin="0,0,0,0"></MenuItem>
<MenuItem Name="second" Header="中级" Margin="0,0,0,0"></MenuItem>
<MenuItem Name="third" Header="高级" Margin="0,0,0,0"></MenuItem>
</MenuItem>
<MenuItem x:Name="whoOne" Header="排行">
</MenuItem>
<MenuItem Header="设置" Margin="0,0,0,0">
<MenuItem Header="背景颜色">
<MenuItem Name="ocean" Header="海底"></MenuItem>
<MenuItem Name="rock" Header="石头地"></MenuItem>
</MenuItem>
<MenuItem.Icon>
<Image Source="img/mrp.ico"></Image>
</MenuItem.Icon>
</MenuItem>
<MenuItem Name="goOut" Header="退出" Margin="0,0,0,0">
<MenuItem.Icon>
<Image Source="img/exit.ico"></Image>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
<Border Grid.Row="1" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="3">
<Border.Background>
<ImageBrush x:Name="bgimg" ImageSource="img/bg.jpg" Stretch="Fill"></ImageBrush>
</Border.Background>
</Border>
<Grid x:Name="GameBG" Grid.Row="2" Grid.Column="1" Margin="35,0,35,35" Height="369" VerticalAlignment="Bottom">
<Grid.Background>
<ImageBrush ImageSource="img/main.png"></ImageBrush>
</Grid.Background>
<Button x:Name="start" Content="开始游戏" HorizontalAlignment="Left" Margin="114,133,0,0" VerticalAlignment="Top" Width="178" Height="83"/>
</Grid>
<StackPanel Grid.Row="1" Grid.Column="1">
<StackPanel.Background>
<ImageBrush ImageSource="img/menu2.png"></ImageBrush>
</StackPanel.Background>
<Label Name="numboom" Content="" Width="50" Height="50" Margin="-180,30,10,10" FontSize="26"/>
<Label Content="雷数:" Width="60" Height="50" FontSize="22" Margin="-290,-70,0,0"/>
<Label Content="计时:" FontSize="22" Width="60" Height="50" Margin="100,-70,0,0"/>
<Label Name="time" Content="Label" FontSize="22" Width="70" Height="50" Margin="230,-70,0,0"/>
</StackPanel>
</Grid>
</Window>
在游戏区域创建网格线,每一个网格代表一个地砖
//初始化游戏区域网格线
private void seeMap(int rows )
{
for (int i = 0; i < rows; i++)
{
//在游戏区域实例化行
RowDefinition row = new RowDefinition();
//row.Height = new GridLength(40);
//将创建的行添加进游戏区域
GameBG.RowDefinitions.Add(row);
//在游戏区域实例化列
ColumnDefinition colum = new ColumnDefinition();
//colum.Width = new GridLength(40);
//将创建的列添加进游戏区域
GameBG.ColumnDefinitions.Add(colum);
}
//设置网格线在游戏区域中可见
GameBG.ShowGridLines = true;
}
实现右键点击插红旗功能
//设置鼠标右键点击图片事件
private void MainWindow_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
//通过sensender来判断点击的是谁
Image img = sender as Image;
//将图片路径改变为旗帜
img.Source = new BitmapImage(new Uri("/../../img/qizi.gif", UriKind.Relative));
}
实现点击左键点击功能
//设置鼠标左键点击图片事件
private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//通过sender获取到点的是哪个图片
Image img=sender as Image;
//将获取到的图片的tag值赋给新建的index
int[] index = img.Tag as int[];
if (!IsBoom(index[0],index[1]))
{
//判断点击的如果不是雷而是空白,则向四周扩散,遇到数字停止
//相邻的方块中最少存在3个雷(四个角),最多存在8个雷
//若用(i,j)代表当前点击的位置,
//则四周为(i-1,j-1)(i-1,j)(i-1,j+1)(i,j-1)(i,j+1)(i+1,j-1)(i+1,j)(i+1,j+1)
CountMine(index[0],index[1],img);
//定义一个变量来接收剩余的雷数
int left = 0;
//遍历数组,判断剩余的砖是否翻开
for (int i=0;i<bomOrgo.GetLength(0);i++)
{
for (int j=0;j<bomOrgo.GetLength(1);j++)
{
//判断该位置是否是false,如果是说明该位置未翻开
if (bomOrgo[i,j]==false)
{
left++;
}
}
}
//判断剩下的是不是都为雷,如果未翻开的数量等于雷数则游戏胜利
if (left == boom)
{
//如果只剩地雷,则翻开所有的地雷
for (int i=0;i<maps.GetLength(0);i++)
{
for (int j=0;j<maps.GetLength(1);j++)
{
if (maps[i, j] == 1)
{
images[i, j].Source = new BitmapImage(new Uri("/../../img/lei.gif", UriKind.Relative));
}
}
}
timer.Stop();
try
{
FileStream file = new FileStream("../../file/chuji.txt", FileMode.Append, FileAccess.Write);
StreamWriter writer = new StreamWriter(file);
string fenshu = r.ToString();
//string fenshu = time.Content.ToString();
writer.WriteLine(fenshu+";");
writer.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
MessageBoxResult t=MessageBox.Show("恭喜通关","",MessageBoxButton.OK);
if (t==MessageBoxResult.OK)
{
MessageBoxResult s = MessageBox.Show("下一关", "退出", MessageBoxButton.YesNo);
if (s==MessageBoxResult.Yes)
{
r = 0;
time.Content = r + "s";
timer.Start();
//重新刷新游戏必须清空游戏区域已有东西
GameBG.RowDefinitions.Clear();
GameBG.ColumnDefinitions.Clear();
GameBG.Children.Clear();
//每次通过雷数加1,地砖行数列数分别加一
rows++;
boom++;
seeMap(rows);
seeGame(rows,boom);
}
else
{
this.Close();
}
}
}
}
else
{
//如果点击的位置是雷,那么图片改为雷
images[index[0], index[1]].Source = new BitmapImage(new Uri("/../../img/lei.gif", UriKind.Relative));
for (int i = 0; i < maps.GetLength(0); i++)
{
for (int j = 0; j < maps.GetLength(1); j++)
{
if (maps[i, j] == 1)
{
images[i, j].Source = new BitmapImage(new Uri("/../../img/lei.gif", UriKind.Relative));
}
}
}
MessageBoxResult z=MessageBox.Show("bom bom bom你死了","",MessageBoxButton.OK);
if (z==MessageBoxResult.OK)
{
//点击确定后刷新地图重新开始
FileStream fileStream = new FileStream("../../file/chuji.txt",FileMode.Append, FileAccess.Write);
StreamWriter ww = new StreamWriter(fileStream);
ww.Write(0+"\r\n");
r = 0;
time.Content = r + "s";
GameBG.Children.Clear();
rows=10;
boom = 10;
seeGame(rows,boom);
}
}
}
定义一个方法来判断点击的位置是否是雷
//定义一个方法来判断点中的是否是雷
bool IsBoom(int i,int j)
{
//判断是否超出游戏范围,如果超出返回false
if (i<0||j<0||i>=maps.GetLength(0)||j>=maps.GetLength(1))
{
return false;
}
else
{
//判断是否是雷,如果是返回true
if (maps[i,j]==1)
{
return true;
}
else
{
return false;
}
}
}
定义一个方法,实现如果不是雷周围空白地砖自动揭开功能;
方法逻辑:判断点击的如果不是雷而是空白,则向四周扩散,遇到数字停止
//相邻的方块中最少存在3个雷(四个角),最多存在8个雷
//若用(i,j)代表当前点击的位置,
//则四周为(i-1,j-1)(i-1,j)(i-1,j+1)(i,j-1)(i,j+1)(i+1,j-1)(i+1,j)(i+1,j+1)
void CountMine(int i,int j,Image img)
{
//判断当前位置是否判断过,如果判断过则跳出---作用防止反复判断自己造成死循环
if (bomOrgo[i,j]==true)
{
return;
}
//将当前位置设置为true
bomOrgo[i,j] = true;
//创建一个变量来接收地雷数
int count = 0;
//判断当前位置四周的八个方向是否为雷,如果是则count++
if (IsBoom(i - 1, j - 1))
{
count++;
}
if (IsBoom(i-1,j))
{
count++;
}
if (IsBoom(i - 1, j+1))
{
count++;
}
if (IsBoom(i, j-1))
{
count++;
}
if (IsBoom(i , j+1))
{
count++;
}
if (IsBoom(i +1, j-1))
{
count++;
}
if (IsBoom(i + 1, j))
{
count++;
}
if (IsBoom(i + 1, j+1))
{
count++;
}
//递归思想:判断如果当前位置的8个方向都没有雷,则再以八个方向为中心重复调用自己这个方法往外判断
if (count==0)
{
GameBG.Children.Remove(img);
//外部if保证数组不超出索引
if (i>0)
{
CountMine(i - 1, j,images[i-1,j]);
if (j>0)
{
CountMine(i-1,j-1, images[i - 1, j-1]);
}
}
if (i<maps.GetLength(0)-1)
{
CountMine(i + 1, j,images[i + 1, j]);
}
if (i>0&&j<maps.GetLength(1)-1)
{
CountMine(i - 1, j + 1, images[i - 1, j+1]);
}
if (j<maps.GetLength(1)-1)
{
CountMine(i , j+1, images[i, j+1]);
}
if (j>0)
{
CountMine(i, j - 1, images[i , j-1]);
}
if (i < maps.GetLength(1)-1&&j>0)
{
CountMine(i + 1, j - 1, images[i + 1, j-1]);
}
if (i < maps.GetLength(0)-1&& j < maps.GetLength(1)-1)
{
CountMine(i + 1, j+1, images[i + 1, j+1]);
}
}
else
{
//移除该处图片
GameBG.Children.Remove(img);
//实例化label
Label lb = new Label();
lb.Content = count.ToString();
//将label设置网格的相应位置处
Grid.SetRow(lb, i);
Grid.SetColumn(lb, j);
lb.FontSize = 24;
//设置label水平居中
lb.HorizontalContentAlignment = HorizontalAlignment.Center;
//设置label竖直居中
lb.VerticalContentAlignment = VerticalAlignment.Center;
GameBG.Children.Add(lb);
}
}
实现菜单栏的初级、中级、高级模式
//高级模式
private void Third_Click(object sender, RoutedEventArgs e)
{
r = 0;
time.Content = r + "s";
GameBG.RowDefinitions.Clear();
GameBG.ColumnDefinitions.Clear();
GameBG.Children.Clear();
//高级定义雷数为30
rows = 10;
boom = 30;
seeMap(rows);
seeGame(rows,boom);
}
//中级模式
private void Second_Click(object sender, RoutedEventArgs e)
{
GameBG.RowDefinitions.Clear();
GameBG.ColumnDefinitions.Clear();
GameBG.Children.Clear();
r = 0;
time.Content = r + "s";
//中级定义雷数为20个
rows = 10;
boom = 20;
seeMap(rows);
seeGame(rows,boom);
}
//初级模式
private void First_Click(object sender, RoutedEventArgs e)
{
//清除网格线;如果不线清除原本的网格线和新创建的网格线会冲突
GameBG.RowDefinitions.Clear();
GameBG.ColumnDefinitions.Clear();
//清除游戏区域中的元素
GameBG.Children.Clear();
//将计时器变为0
r = 0;
time.Content = r + "s";
//定义实参传进方法中
rows = 10;
boom = 10;
//调用方法创建网格线,创建游戏区域中的元素
seeMap(rows);
seeGame(rows,boom);
}
实现菜单栏的点击退出和更换地图功能
//更换石头地地图
private void Rock_Click(object sender, RoutedEventArgs e)
{
bgimg.ImageSource = new BitmapImage(new Uri("../../img/bg.jpg", UriKind.Relative));
}
//更换海底地图
private void Ocean_Click(object sender, RoutedEventArgs e)
{
bgimg.ImageSource = new BitmapImage(new Uri("../../img/bg1.jpg",UriKind.Relative));
}
//退出点击事件
private void GoOut_Click(object sender, RoutedEventArgs e)
{
this.Close();
}