WPF桌面应用实例(二):写一个扫雷游戏

之前一直想自己写一个扫雷游戏,但是感觉用Unity又有点大材小用了,所有搁置下来,最近发现用WPF来做不是刚刚好嘛,这种小游戏,用WPF做起来真的得心应手。话不多说,我们开始:

首先是页面布局,扫雷的界面是很多个小格子,统计了一下,是16*30,总共480个格子,这么多的数量的格子,我们不能直接在XAML界面上直接写了,只能在cs后台动态生成,计划是要布局两层格子,总共960个,然后格子外层我们要一个边框,边框上面,需要6个文本,用来显示计时器,游戏成功文本,游戏失败文本,剩余地雷数量

以下是MainWindow.xaml代码:

<Window x:Class="SaoLei.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:SaoLei"
        mc:Ignorable="d"
        Title="MainWindow" Height="700" Width="1100">
    <Grid>
        <!--最上面的文本-->
        <TextBlock Height="48" Width="120"  FontSize="35"  Text="计时器:" Margin="100,30,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <TextBlock Name="TimerText" Height="48" Width="120"  FontSize="35"  Text="000s" Margin="220,30,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="Red"/>
        <TextBlock Height="48" Width="150"  FontSize="35"  Text="剩余地雷:" Margin="720,30,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <TextBlock Name="MinesCounter" Height="48" Width="80"  FontSize="35"  Text="00" Margin="880,30,5,0" HorizontalAlignment="Left" VerticalAlignment="Top" Foreground="Red"/>
        <TextBlock Name="WinText" Height="48" Width="150"  FontSize="35"  Text="排雷成功" Margin="-20,30,5,0" HorizontalAlignment="Center" VerticalAlignment="Top" Foreground="LightGreen" Visibility="Hidden"/>
        <TextBlock Name="FailText" Height="48" Width="150"  FontSize="35"  Text="排雷失败" Margin="-20,30,5,0" HorizontalAlignment="Center" VerticalAlignment="Top" Foreground="Red" Visibility="Hidden"/>
        <!--外边框-->
        <StackPanel>
            <Border x:Name="GridBorder" Height="500" Width="920" CornerRadius="5" BorderThickness="5,5,5,5" BorderBrush="SteelBlue" Padding="5" HorizontalAlignment="Center"  Margin="36,90"  />
        </StackPanel>
        <!--底层,用textblock表示数字和地雷(*是地雷)-->
        <UniformGrid Name="DeepGrid" Rows="16" Columns="30" Height="480" Width="900" HorizontalAlignment="Center" Margin="50,65,50,52">
            <Button Name="Deep0" Width="28" Height="28" Background="AliceBlue" Content="1" Foreground="Blue" FontWeight="Bold" FontSize="22"  />
        </UniformGrid>
        <!--上层,供用户点击的按钮-->
        <UniformGrid Name="TopGrid" Rows="16" Columns="30" Height="480" Width="900" HorizontalAlignment="Center" Margin="50,65,50,52"/>
    </Grid>
</Window>

其中Deep0是我用来测随机数的按钮,大家可忽略

然后我们看后台的逻辑处理,我们的思路是,开始状态先根据指定地雷数量,创建底层的格子,用集合存储,格子有三种状态,地雷,数字,空格,我们首先根据给定的地雷数量n,生成99个随机且不相等的数,范围在0~479之间,然后根据格子索引给地雷格子赋值,遍历每一个格子,根据周围地雷的数量显示对应的数字,没有则显示空格。

然后我们看上层格子的逻辑,点击一个上层格子,我们会根据底下格子状态来判断,如果底下为数字,隐藏自身,底下为地雷,游戏结束,底下为空格,我们用方法将周围的8格都隐藏掉,然后隐藏自身。在这个过程中,因为周围的8格同样可能存在空格,如果存在,那我们用这个索引去调用这个方法自身,用递归的思想让周围的空白格都清除掉。

以下是后台代码MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Windows.Threading;

namespace SaoLei
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
       
        private const int GRID_NUM = 480;//游戏格子数
        private const int GRID_ROWS = 16;//格子行数
        private const int GRID_COLS = 30;//格子列数
        private const int RANDOM_MINES_NUM = 99;//地雷数量

        private List<Button> deepGridButton = new List<Button>();//存储底层按钮的集合
        private List<Button> topGridButton = new List<Button>();//存储上层按钮的集合

        private DispatcherTimer timer = null;//计时器
        private enum TimeState {//计时器的三种状态
            Start,
            Pause,
            End
        }
        TimeState timeState = TimeState.End;//初始时间状态
        private TimeSpan timeSpan = new TimeSpan(0, 0, 0, 0, 0);
        private string str = "";

        public MainWindow()
        {
            InitializeComponent();
            Title = "扫雷";
            Panel.SetZIndex(GridBorder,1);//设置边框的层级在其他控价之上
            deepGridButton.Insert(0,Deep0);
            //计时器初始化
            timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 0, 1);
            timer.Tick += OnTimer;
            timer.IsEnabled = true;
            timer.Start();

            MinesCounter.Text = RANDOM_MINES_NUM.ToString();//剩余地雷数初始化
            CreateDeepMinesAndNums(RANDOM_MINES_NUM);
            CreateTopGridButton(GRID_NUM);
            Deep0.Click += Num0_Click;
        }

        //时间回调方法
        private void OnTimer(object sender, EventArgs e)
        {
            switch (timeState) {
                case TimeState.Start: timeSpan += new TimeSpan(0,0,0,1);break;
                case TimeState.Pause: { }break;
                case TimeState.End: timeSpan = new TimeSpan();break;
            }
            TimerText.Text= (timeSpan.Hours * 3600 + timeSpan.Minutes * 60 + timeSpan.Seconds).ToString();
        }
        
        private void Num0_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(str);//显示地雷的索引
        }

        Dictionary<string, int> DeepButtonIndexDict = new Dictionary<string, int>();//存储底层按钮名字索引的字典

        //创建底层的地雷和数字
        private void CreateDeepMinesAndNums(int n) {
            //生成指定个随机不相等的数
            List<int> randomList = new List<int>();
            for (int i = 0; i < n; i++)
            {
                tryAgain:
                Random ra = new Random();
                int num = ra.Next(0, GRID_NUM);
                if (randomList.Count!=0&& randomList.Contains(num))
                    goto tryAgain;
                else
                    randomList.Insert(i,num);
            }
            //创建底层按钮
            for (int i = 1; i < GRID_NUM; i++)
            {
                Button btn = new Button();
                btn.Name = "Deep" + i.ToString();
                btn.Width = 28;
                btn.Height = 28;
                btn.FontSize = 22;
                btn.FontWeight = FontWeights.Bold;
                btn.Background = Brushes.AliceBlue;
                if (randomList.Contains(i))
                    btn.Content = "雷";
                btn.MouseDown += DeepButtonBothClick;
                deepGridButton.Insert(i, btn);
                DeepButtonIndexDict.Add(btn.Name,i);
                DeepGrid.Children.Add(btn);
            }
            //随机数集合排序
            int temp;
            for (int i = 0; i < n-1; i++)
            {
                for (int j = i+1; j < n; j++)
                {
                    if (randomList[i] > randomList[j]){
                        temp = randomList[i];
                        randomList[i] = randomList[j];
                        randomList[j] = temp;
                    }
                }
            }
            for (int i = 0; i < n; i++)
            {
                str += randomList[i].ToString() + "...";
            }
            //对生成的数字再次处理
            for (int i = 0; i < GRID_NUM; i++)
            {
                if(!randomList.Contains(i))
                deepGridButton[i].Content = CreateNumBaseOnMinesAround(i, randomList);
                if (deepGridButton[i].Content.ToString() == "0")
                    deepGridButton[i].Content = "";
                //处理数字颜色
                switch (deepGridButton[i].Content.ToString()) {
                    case "1":deepGridButton[i].Foreground = Brushes.DeepSkyBlue;break;
                    case "2":deepGridButton[i].Foreground = Brushes.Green;break;
                    case "3":deepGridButton[i].Foreground = Brushes.OrangeRed;break;
                    case "4":deepGridButton[i].Foreground = Brushes.DarkBlue;break;
                    case "5":deepGridButton[i].Foreground = Brushes.DarkRed;break;
                    case "6":deepGridButton[i].Foreground = Brushes.LightSeaGreen;break;
                    default:{ }break;
                }
            }
         }

        //底层按钮左右键同时按下,触发清除事件
        private void DeepButtonBothClick(Object sender, MouseButtonEventArgs e) {
            var btn = sender as Button;
            int n = DeepButtonIndexDict[btn.Name];
            //判断鼠标左右键同时按下的状态
            if (e.LeftButton == MouseButtonState.Pressed && e.RightButton == MouseButtonState.Pressed) {
                if (deepGridButton[n].Content.ToString() == "")
                    return;
                int minesCount = int.Parse(deepGridButton[n].Content.ToString());//按下的按钮的数字
                int flagCount = 0;
                //格子周围8格的索引
                int[] indexArr = { n - GRID_COLS - 1, n - GRID_COLS, n - GRID_COLS + 1, n - 1, n + 1, n + GRID_COLS - 1, n + GRID_COLS, n + GRID_COLS + 1 };
                for (int i = 0; i < indexArr.Length; i++)
                {
                    //最左边的格子,单独判断,排除左边三个格子索引
                    if (n % 30 == 0)
                    {
                        indexArr[0] = -1;
                        indexArr[3] = -1;
                        indexArr[5] = -1;
                    }
                    //右边的格子
                    if (n % 30 == 29)
                    {
                        indexArr[2] = -1;
                        indexArr[4] = -1;
                        indexArr[7] = -1;
                    }
                    if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM)//筛掉范围之外的格子
                        if (topGridButton[indexArr[i]].Content.ToString() == "旗")
                            flagCount++;
                }
                if (flagCount == minesCount)
                    Clean8GridWithIndex(n);
            }
        }

        //根据周围的地雷数生成数字
        private string CreateNumBaseOnMinesAround(int n,List<int> randList) {
            int count = 0;
            //格子周围8格的索引
            int[] indexArr = { n - GRID_COLS - 1, n - GRID_COLS, n - GRID_COLS + 1, n - 1, n + 1, n + GRID_COLS - 1, n + GRID_COLS, n + GRID_COLS + 1 };
            for (int i = 0; i < indexArr.Length; i++)
            {
                //最左边的格子,单独判断,排除左边三个格子索引
                if (n% 30 == 0)
                {
                    indexArr[0] = -1;
                    indexArr[3] = -1;
                    indexArr[5] = -1;
                }
                //右边的格子
                if (n % 30 == 29)
                {
                    indexArr[2] = -1;
                    indexArr[4] = -1;
                    indexArr[7] = -1;
                }
                if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM)//筛掉范围之外的格子
                    if (randList.Contains(indexArr[i]))
                        count++;
            }
            return count.ToString();
        }

        Dictionary<string, int> TopButtonIndexDict = new Dictionary<string, int>();//存储上层按钮名字索引的字典

        //创建上层按钮格子
        private void CreateTopGridButton(int n) {
            for (int i = 0; i < n; i++)
            {
                Button btn = new Button();
                btn.Name = "Top" + i.ToString();
                btn.Height = 28;
                btn.Width = 28;
                btn.FontSize = 22;
                btn.Content = "";
                btn.Background = Brushes.LightBlue;
                btn.Foreground = Brushes.Red;
                btn.FontWeight = FontWeights.Bold;
                btn.Click += Btn_MouseLeftButtonDown;
                btn.MouseDown += Btn_MouseRightButtonDown;
                TopButtonIndexDict.Add(btn.Name,i);
                topGridButton.Insert(i, btn);
                TopGrid.Children.Insert(i, btn);
            }

        }
        
        //上层按钮左键点击事件
        private void Btn_MouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            if (timeState == TimeState.End)
                timeState = TimeState.Start;
            var btn = sender as Button;
            int index = TopButtonIndexDict[btn.Name];
            //如果点击的是雷,游戏结束
            if (deepGridButton[index].Content.ToString() == "雷")
            {
                FailText.Visibility = Visibility.Visible;
                timeState = TimeState.End;
            }
            //如果点中的按钮下为空,周围8格同时消除
            if (deepGridButton[index].Content.ToString() == "")
            {
                 Clean8GridWithIndex(index);
            }
            btn.Visibility = Visibility.Hidden;
        }

        //上层按钮右键点击事件
        private void Btn_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var btn = sender as Button;
            int minesCounter = int.Parse(MinesCounter.Text);
            if (btn.Content.ToString() == "")
            {
                btn.Content = "旗";
                minesCounter--;
            }
            else
            {
                btn.Content = "";
                minesCounter++;
            }
            MinesCounter.Text = minesCounter.ToString();
            if (minesCounter == 0)
            {//排雷成功
                WinText.Visibility = Visibility.Visible;
                timeState = TimeState.Pause;
                MessageBox.Show("恭喜你赢得了游戏,游戏记录为:" + TimerText.Text + "s");
            }
        }

        //根据索引排除周围8格
        private void Clean8GridWithIndex(int index) {
            //格子周围8格的索引
            int[] indexArr = { index - GRID_COLS - 1, index - GRID_COLS, index - GRID_COLS + 1, index - 1, index + 1, index + GRID_COLS - 1, index + GRID_COLS, index + GRID_COLS + 1 };
            for (int i = 0; i < indexArr.Length; i++)
            {
                //最左边的格子,单独判断,排除左边三个格子索引
                if (index % 30 == 0)
                {
                    indexArr[0] = -1;
                    indexArr[3] = -1;
                    indexArr[5] = -1;
                }
                //右边的格子
                if (index % 30 == 29)
                {
                    indexArr[2] = -1;
                    indexArr[4] = -1;
                    indexArr[7] = -1;
                }
                if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM&& topGridButton[indexArr[i]].Visibility==Visibility.Visible)//筛掉范围之外的格子
                {
                    if (deepGridButton[indexArr[i]].Content.ToString() == "雷")
                        continue;
                    topGridButton[indexArr[i]].Visibility = Visibility.Hidden;
                    if (deepGridButton[indexArr[i]].Content.ToString() == "") {
                        Clean8GridWithIndex(indexArr[i]);//利用递归把周围可消除的空格都消除
                    }
                }
            }
        }
        
    }
}

写代码的过程极其艰辛,尤其是关于那个递归的方法,想了两天才想明白,不过真的把自己喜欢的游戏做出来了也很有成就感,就这样,希望对大家有帮助。

*******************最近更新:2022/1/30**********************

把地雷和棋子换成图片形式显示了,以下是代码

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Windows.Threading;

namespace SaoLei
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
       
        private const int GRID_NUM = 480;//游戏格子数
        private const int GRID_ROWS = 16;//格子行数
        private const int GRID_COLS = 30;//格子列数
        private const int RANDOM_MINES_NUM = 99;//地雷数量

        private List<Button> deepGridButton = new List<Button>();//存储底层按钮的集合
        private List<Image> deepMineImage = new List<Image>();//底层地雷图片的集合
        private List<Button> topGridButton = new List<Button>();//存储上层按钮的集合
        private List<Image> topFlagImage = new List<Image>();//上层旗子图片的集合

        private DispatcherTimer timer = null;//计时器
        private enum TimeState {//计时器的三种状态
            Start,
            Pause,
            End
        }
        TimeState timeState = TimeState.End;//初始时间状态
        private TimeSpan timeSpan = new TimeSpan(0, 0, 0, 0, 0);
        private string str = "";

        public MainWindow()
        {
            InitializeComponent();
            Title = "扫雷";
            Panel.SetZIndex(GridBorder,1);//设置边框的层级在其他控价之上
            deepGridButton.Insert(0,Deep0);
            //计时器初始化
            timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 0, 1);
            timer.Tick += OnTimer;
            timer.IsEnabled = true;
            timer.Start();
            RefreshButton.Click += RefreshButtonClick;
            MinesCounter.Text = RANDOM_MINES_NUM.ToString();//剩余地雷数初始化
            CreateDeepMinesAndNums(RANDOM_MINES_NUM);
            CreateTopGridButton(GRID_NUM);
            Deep0.Click += Num0_Click;
        }

        //刷新按钮点击事件
        private void RefreshButtonClick(object sender, RoutedEventArgs e)
        {
            timeState = TimeState.End;
            if (WinText.Visibility == Visibility.Visible || FailText.Visibility == Visibility.Visible)
            {
                WinText.Visibility = Visibility.Hidden;FailText.Visibility = Visibility.Hidden;
            }
            for (int i = 0; i < GRID_NUM; i++)
            {
                if (i != 0)//Deep0不移除
                    DeepGrid.Children.Remove(deepGridButton[i]);
                MineGrid.Children.Remove(deepMineImage[i]);
                TopGrid.Children.Remove(topGridButton[i]);
                FlagGrid.Children.Remove(topFlagImage[i]);
            }
            deepGridButton.Clear();
            DeepButtonIndexDict.Clear();
            deepMineImage.Clear();
            topGridButton.Clear();
            TopButtonIndexDict.Clear();
            topFlagImage.Clear();
            deepGridButton.Insert(0, Deep0);
            MinesCounter.Text = RANDOM_MINES_NUM.ToString();//剩余地雷数初始化
            str = "";//地雷索引信息清零
            CreateDeepMinesAndNums(RANDOM_MINES_NUM);
            CreateTopGridButton(GRID_NUM);
        }

        //时间回调方法
        private void OnTimer(object sender, EventArgs e)
        {
            switch (timeState) {
                case TimeState.Start: timeSpan += new TimeSpan(0,0,0,1);break;
                case TimeState.Pause: { }break;
                case TimeState.End: timeSpan = new TimeSpan();break;
            }
            TimerText.Text= (timeSpan.Hours * 3600 + timeSpan.Minutes * 60 + timeSpan.Seconds).ToString();
        }
        
        private void Num0_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(str);//显示地雷的索引
        }

        Dictionary<string, int> DeepButtonIndexDict = new Dictionary<string, int>();//存储底层按钮名字索引的字典

        //创建底层的地雷和数字
        private void CreateDeepMinesAndNums(int n) {
            //生成指定个随机不相等的数
            List<int> randomList = new List<int>();
            for (int i = 0; i < n; i++)
            {
                tryAgain:
                Random ra = new Random();
                int num = ra.Next(0, GRID_NUM);
                if (randomList.Count!=0&& randomList.Contains(num))
                    goto tryAgain;
                else
                    randomList.Insert(i,num);
            }
            //创建底层按钮
            for (int i = 1; i < GRID_NUM; i++)
            {
                Button btn = new Button();
                btn.Name = "Deep" + i.ToString();
                btn.Width = 28;
                btn.Height = 28;
                btn.FontSize = 22;
                btn.FontWeight = FontWeights.Bold;
                btn.Background = Brushes.AliceBlue;
                //if (randomList.Contains(i))
                    //btn.Content = "雷";
                btn.MouseDown += DeepButtonBothClick;
                deepGridButton.Insert(i, btn);
                DeepButtonIndexDict.Add(btn.Name,i);
                DeepGrid.Children.Insert(i, btn); 
            }
            //创建底层雷
            for (int i = 0; i < GRID_NUM; i++)
            {
                Image img = new Image();
                img.Name = "Mine" + i.ToString();
                img.Width = 28;
                img.Height = 28;
                img.Source = null;
                if (randomList.Contains(i))
                {
                    Uri uri = new Uri(System.Environment.CurrentDirectory + "\\" + "Image/mine.png", UriKind.Absolute);
                    BitmapImage bitmap = new BitmapImage(uri);
                    img.Source = bitmap;
                }
                deepMineImage.Insert(i, img);
                MineGrid.Children.Insert(i, img);
            }
            //随机数集合排序
            int temp;
            for (int i = 0; i < n-1; i++)
            {
                for (int j = i+1; j < n; j++)
                {
                    if (randomList[i] > randomList[j]){
                        temp = randomList[i];
                        randomList[i] = randomList[j];
                        randomList[j] = temp;
                    }
                }
            }
            for (int i = 0; i < n; i++)
            {
                str += randomList[i].ToString() + "...";
            }
            //对生成的数字再次处理
            for (int i = 0; i < GRID_NUM; i++)
            {
                if(!randomList.Contains(i))
                deepGridButton[i].Content = CreateNumBaseOnMinesAround(i, randomList);
                if(deepGridButton[i].Content == null)
                    deepGridButton[i].Content = "-1";
                if (deepGridButton[i].Content.ToString() == "0")
                    deepGridButton[i].Content = "";
                //处理数字颜色
                switch (deepGridButton[i].Content.ToString()) {
                    case "1":deepGridButton[i].Foreground = Brushes.DeepSkyBlue;break;
                    case "2":deepGridButton[i].Foreground = Brushes.Green;break;
                    case "3":deepGridButton[i].Foreground = Brushes.OrangeRed;break;
                    case "4":deepGridButton[i].Foreground = Brushes.DarkBlue;break;
                    case "5":deepGridButton[i].Foreground = Brushes.DarkRed;break;
                    case "6":deepGridButton[i].Foreground = Brushes.LightSeaGreen;break;
                    default:{ }break;
                }
            }
        }

        private int clickImageIndex = -1;
        private void FlagImageMouseDown(Object sender, MouseButtonEventArgs e)
        {
            if (e.RightButton == MouseButtonState.Pressed)
            {
                var img = sender as Image;
                clickImageIndex = int.Parse(img.Name.Split('_')[1]);
            }
        }

        private void FlagImageMouseUp(Object sender, MouseButtonEventArgs e)
        {
            if (e.RightButton == MouseButtonState.Released)
            {
                var img = sender as Image;
                int upIndex = int.Parse(img.Name.Split('_')[1]);
                if (upIndex == clickImageIndex)
                {
                    int minesCounter = int.Parse(MinesCounter.Text);
                    Image flagImg = topFlagImage[clickImageIndex];
                    if (flagImg.Visibility == Visibility.Hidden)
                    {
                        flagImg.Visibility = Visibility.Visible;
                        minesCounter--;
                    }
                    else
                    {
                        flagImg.Visibility = Visibility.Hidden;
                        minesCounter++;
                    }
                    MinesCounter.Text = minesCounter.ToString();
                    if (minesCounter == 0)
                    {//排雷成功
                        WinText.Visibility = Visibility.Visible;
                        timeState = TimeState.Pause;
                        MessageBox.Show("恭喜你赢得了游戏,游戏记录为:" + TimerText.Text + "s");
                    }
                }
            }
        }

        //底层按钮左右键同时按下,触发清除事件
        private void DeepButtonBothClick(Object sender, MouseButtonEventArgs e) {
            var btn = sender as Button;
            int n = DeepButtonIndexDict[btn.Name];
            //判断鼠标左右键同时按下的状态
            if (e.LeftButton == MouseButtonState.Pressed && e.RightButton == MouseButtonState.Pressed) {
                if (deepGridButton[n].Content.ToString() == "")
                    return;
                int minesCount = int.Parse(deepGridButton[n].Content.ToString());//按下的按钮的数字
                int flagCount = 0;
                //格子周围8格的索引
                int[] indexArr = { n - GRID_COLS - 1, n - GRID_COLS, n - GRID_COLS + 1, n - 1, n + 1, n + GRID_COLS - 1, n + GRID_COLS, n + GRID_COLS + 1 };
                for (int i = 0; i < indexArr.Length; i++)
                {
                    //最左边的格子,单独判断,排除左边三个格子索引
                    if (n % 30 == 0)
                    {
                        indexArr[0] = -1;
                        indexArr[3] = -1;
                        indexArr[5] = -1;
                    }
                    //右边的格子
                    if (n % 30 == 29)
                    {
                        indexArr[2] = -1;
                        indexArr[4] = -1;
                        indexArr[7] = -1;
                    }
                    if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM)//筛掉范围之外的格子
                        if (topFlagImage[indexArr[i]].Visibility == Visibility.Visible && deepMineImage[indexArr[i]].Source != null)
                            flagCount++;
                }
                if (flagCount == minesCount)
                    Clean8GridWithIndex(n);
            }
        }

        //根据周围的地雷数生成数字
        private string CreateNumBaseOnMinesAround(int n,List<int> randList) {
            int count = 0;
            //格子周围8格的索引
            int[] indexArr = { n - GRID_COLS - 1, n - GRID_COLS, n - GRID_COLS + 1, n - 1, n + 1, n + GRID_COLS - 1, n + GRID_COLS, n + GRID_COLS + 1 };
            for (int i = 0; i < indexArr.Length; i++)
            {
                //最左边的格子,单独判断,排除左边三个格子索引
                if (n% 30 == 0)
                {
                    indexArr[0] = -1;
                    indexArr[3] = -1;
                    indexArr[5] = -1;
                }
                //右边的格子
                if (n % 30 == 29)
                {
                    indexArr[2] = -1;
                    indexArr[4] = -1;
                    indexArr[7] = -1;
                }
                if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM)//筛掉范围之外的格子
                    if (randList.Contains(indexArr[i]))
                        count++;
            }
            return count.ToString();
        }

        Dictionary<string, int> TopButtonIndexDict = new Dictionary<string, int>();//存储上层按钮名字索引的字典

        //创建上层按钮格子
        private void CreateTopGridButton(int n) {
            for (int i = 0; i < n; i++)
            {
                Button btn = new Button();
                btn.Name = "Top_" + i.ToString();
                btn.Height = 28;
                btn.Width = 28;
                btn.FontSize = 22;
                btn.Content = "";
                btn.Background = Brushes.LightBlue;
                btn.Foreground = Brushes.Red;
                btn.FontWeight = FontWeights.Bold;
                btn.Click += Btn_MouseLeftButtonDown;
                btn.MouseDown += Btn_MouseRightButtonDown;
                TopButtonIndexDict.Add(btn.Name,i);
                topGridButton.Insert(i, btn);
                TopGrid.Children.Insert(i, btn);

                //上层旗子
                Image img = new Image();
                img.Name = "Flag_" + i.ToString();
                img.Width = 28;
                img.Height = 28;
                Uri uri = new Uri(System.Environment.CurrentDirectory + "\\" + "Image/flag.png", UriKind.Absolute);
                BitmapImage bitmap = new BitmapImage(uri);
                img.Source = bitmap;
                img.Visibility = Visibility.Hidden;
                img.MouseDown += FlagImageMouseDown;
                img.MouseUp += FlagImageMouseUp;
                topFlagImage.Insert(i, img);
                FlagGrid.Children.Insert(i, img);
            }

        }
        
        //上层按钮左键点击事件
        private void Btn_MouseLeftButtonDown(object sender, RoutedEventArgs e)
        {
            if (timeState == TimeState.End)
                timeState = TimeState.Start;
            var btn = sender as Button;
            int index = TopButtonIndexDict[btn.Name];
            //如果点击的是雷,游戏结束
            if (deepMineImage[index].Source != null)
            {
                FailText.Visibility = Visibility.Visible;
                timeState = TimeState.End;
            }
            //如果点中的按钮下为空,周围8格同时消除
            else
            {
                 Clean8GridWithIndex(index);
            }
            btn.Visibility = Visibility.Hidden;
        }

        //上层按钮右键点击事件
        private void Btn_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            var btn = sender as Button;
            int btnIndex = int.Parse(btn.Name.Split('_')[1].ToString());
            int minesCounter = int.Parse(MinesCounter.Text);
            Image flagImg = topFlagImage[btnIndex];
            if (flagImg.Visibility == Visibility.Hidden)
            {
                flagImg.Visibility = Visibility.Visible;
                minesCounter--;
            }
            else
            {
                flagImg.Visibility = Visibility.Hidden;
                minesCounter++;
            }
            MinesCounter.Text = minesCounter.ToString();
            if (minesCounter == 0)
            {//排雷成功
                WinText.Visibility = Visibility.Visible;
                timeState = TimeState.Pause;
                MessageBox.Show("恭喜你赢得了游戏,游戏记录为:" + TimerText.Text + "s");
            }
        }

        //根据索引排除周围8格
        private void Clean8GridWithIndex(int index) {
            //格子周围8格的索引
            int[] indexArr = { index - GRID_COLS - 1, index - GRID_COLS, index - GRID_COLS + 1, index - 1, index + 1, index + GRID_COLS - 1, index + GRID_COLS, index + GRID_COLS + 1 };
            for (int i = 0; i < indexArr.Length; i++)
            {
                //最左边的格子,单独判断,排除左边三个格子索引
                if (index % 30 == 0)
                {
                    indexArr[0] = -1;
                    indexArr[3] = -1;
                    indexArr[5] = -1;
                }
                //右边的格子
                if (index % 30 == 29)
                {
                    indexArr[2] = -1;
                    indexArr[4] = -1;
                    indexArr[7] = -1;
                }
                if (indexArr[i] >= 0 && indexArr[i] < GRID_NUM && topGridButton[indexArr[i]].Visibility==Visibility.Visible)//筛掉范围之外的格子
                {
                    if (deepGridButton[indexArr[i]].Content.ToString() == "-1")
                        continue;
                    topGridButton[indexArr[i]].Visibility = Visibility.Hidden;
                    if (deepGridButton[indexArr[i]].Content.ToString() == "") {
                        Clean8GridWithIndex(indexArr[i]);//利用递归把周围可消除的空格都消除
                    }
                }
            }
        }
        
    }
}

参考博文:Wpf计时器:https://blog.csdn.net/dlmuxgyang/article/details/8494999

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值