WPF窗口扫雷案例详解

游戏功能

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();
        }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值