练手WPF——扫雷小游戏的简易实现(中)

Posted lonelyxmas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了练手WPF——扫雷小游戏的简易实现(中)相关的知识,希望对你有一定的参考价值。

原文:练手WPF(三)——扫雷小游戏的简易实现(中)

八、随机布雷

/// <summary>
/// 随机布地雷
/// </summary>
/// <param name="mineNum">地雷数</param>
private void SetRndMine(int mineNum)
{
    for (int k = 0; k < mineNum; k++)
    {
        int nullnum = 0;

        for (int j = 0; j < _gameLevel._colGrid; j++)
        {
            for (int i = 0; i < _gameLevel._rowGrid; i++)
            {
                if (_backData[j, i] == (int)BackState.BLANK)
                    nullnum++;
            }
        }

        if (nullnum < 1)
            return;

        int index = rnd.Next(1, nullnum);
        nullnum = 0;
        for (int j = 0; j < _gameLevel._colGrid; j++)
        {
            for (int i = 0; i < _gameLevel._rowGrid; i++)
            {
                if (_backData[j, i] == 0)
                {
                    nullnum++;
                    if (nullnum != index)
                        continue;

                    _backData[j, i] = (int)BackState.MINE;        // 设置为地雷
                }
            }
        }
    }
}

这个方法是不是很熟悉,我们在2048游戏中用到过,这里就不再多说了。


九、设置地雷旁边的格子标注的地雷数值
原理就是读取地雷位置,然后分别给不是地雷的格子数值+1。
/// <summary>
/// 设置地雷周围格子雷数
/// </summary>
private void SetCellMineNumber()
{
    for (int y = 0; y < _gameLevel._colGrid; y++)
    {
        for (int x = 0; x < _gameLevel._rowGrid; x++)
        {
            if (_backData[y, x] == (int)BackState.MINE)       // 遇到地雷则周围8格分别+1
            {
                if (x - 1 > -1 && y - 1 > -1 && _backData[y - 1, x - 1] != (int)BackState.MINE)
                    _backData[y - 1, x - 1]++;

                if (y - 1 > -1 && _backData[y - 1, x] != (int)BackState.MINE)
                    _backData[y - 1, x]++;

                if (y - 1 > -1 && x + 1 < _gameLevel._rowGrid && _backData[y - 1, x + 1] != (int)BackState.MINE)
                    _backData[y - 1, x + 1]++;

                if (x - 1 > -1 && _backData[y, x - 1] != (int)BackState.MINE)
                    _backData[y, x - 1]++;

                if (x + 1 < _gameLevel._rowGrid && _backData[y, x + 1] != (int)BackState.MINE)
                    _backData[y, x + 1]++;

                if (y + 1 < _gameLevel._colGrid && x - 1 > -1 && _backData[y + 1, x - 1] != (int)BackState.MINE)
                    _backData[y + 1, x - 1]++;

                if (y + 1 < _gameLevel._colGrid && _backData[y + 1, x] != (int)BackState.MINE)
                    _backData[y + 1, x]++;

                if (y + 1 < _gameLevel._colGrid && x + 1 < _gameLevel._rowGrid && _backData[y + 1, x + 1] != (int)BackState.MINE)
                    _backData[y + 1, x + 1]++;
            }
        }
    }
}

 

十、设置背景区图片组

循环读取背景区数据,根据数值设置对应的图片源。

private void SetBackCellImage()
{
    BackCanvas.Children.Clear();

    for (int y=0; y<_gameLevel._colGrid; y++)
    {
        for (int x=0; x<_gameLevel._rowGrid; x++)
        {
            _backImage[y, x] = new Image();
            if (_backData[y, x] == (int)BackState.BLANK)
            {
                _backImage[y, x].Source = ImageHelper.CutImage(_bmpSpace, new Int32Rect(0, 0, _cellSize.Width, _cellSize.Height));
            }
            else if (_backData[y, x] == (int)BackState.MINE)
            {
                _backImage[y, x].Source = ImageHelper.CutImage(_bmpMine, new Int32Rect(0, 0, _cellSize.Width, _cellSize.Height));
            }
            else
            {
                for (int i = 0; i < 8; i++)
                {
                    if (_backData[y, x] == (i+1))
                    {
                        _backImage[y, x].Source = ImageHelper.CutImage(
                            _bmpNum1_8, new Int32Rect(i * _cellSize.Width, 0, _cellSize.Width, _cellSize.Height));
                        break;
                    }
                }
            }

            _backImage[y, x].SetValue(Canvas.LeftProperty, x * (double)_cellSize.Width);
            _backImage[y, x].SetValue(Canvas.TopProperty, y * (double)_cellSize.Height);
            BackCanvas.Children.Add(_backImage[y, x]);
        }
    }
}

 

十一、开始游戏准备

根据游戏级别分别调用随机布雷、设置雷边数值方法,同时添加背景图片数组到游戏背景区。

private void ResetGame()
{
    InitialGameState();
    InitGameData(_level);
    textBlockMineNum.Text = _gameLevel._mineNum.ToString();

    SetRndMine(_gameLevel._mineNum);
    SetCellMineNumber();
    SetBackCellImage();
}

将该方法添加到开始游戏菜单中,并计时器打开。

private void MenuGameStart_Click(object sender, RoutedEventArgs e)
{
    ResetGame();
    _gameState = GameState.START;

    //  开始计时
    _stopWatchGame.Start();
    _timerSetTimeText.Start();
}

重复点击开始菜单,看看效果。

技术图片

 

十二、调整游戏级别

根据菜单设置的当前级别值设置菜单选择状态。

/// <summary>
/// 设置级别菜单状态
/// </summary>
/// <param name="level"></param>
private void SetMenuLevelState(Level level)
{
    switch (level)
    {
        case Level.SIMPLE:
            MenuLowLevel.IsChecked = true;
            MenuMiddleLevel.IsChecked = false;
            MenuHighLevel.IsChecked = false;
            break;
        case Level.NORMAL:
            MenuLowLevel.IsChecked = false;
            MenuMiddleLevel.IsChecked = true;
            MenuHighLevel.IsChecked = false;
            break;
        case Level.HARD:
            MenuLowLevel.IsChecked = false;
            MenuMiddleLevel.IsChecked = false;
            MenuHighLevel.IsChecked = true;
            break;
    }
}
/// <summary>
/// 初级级别菜单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuLowLevel_Click(object sender, RoutedEventArgs e)
{
    if (_level == Level.SIMPLE)
        return;

    if (MessageBox.Show("将用新难度级别重置游戏,确认要继续吗?", "警告", MessageBoxButton.YesNo, MessageBoxImage.Asterisk)
        == MessageBoxResult.Yes)
    {
        _level = Level.SIMPLE;
        SetMenuLevelState(_level);

        ResetGame();
    }
}

/// <summary>
/// 中级级别菜单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuMiddleLevel_Click(object sender, RoutedEventArgs e)
{
    if (_level == Level.NORMAL)
        return;

    if (MessageBox.Show("将用新难度级别重置游戏,确认要继续吗?", "警告", MessageBoxButton.YesNo, MessageBoxImage.Asterisk)
        == MessageBoxResult.Yes)
    {
        _level = Level.NORMAL;
        SetMenuLevelState(_level);
        ResetGame();
    }
}

/// <summary>
/// 高级级别菜单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MenuHighLevel_Click(object sender, RoutedEventArgs e)
{
    if (_level == Level.HARD)
        return;

    if (MessageBox.Show("将用新难度级别重置游戏,确认要继续吗?", "警告", MessageBoxButton.YesNo, MessageBoxImage.Asterisk)
        == MessageBoxResult.Yes)
    {
        _level = Level.HARD;
        SetMenuLevelState(_level);
        ResetGame();
    }
}

 

十三、设置前景区图片组

/// <summary>
/// 设置前景图片数组
/// </summary>
private void SetForeCellImages()
{
    ForeCanvas.Children.Clear();

    for (int y = 0; y < _gameLevel._colGrid; y++)
    {
        for (int x = 0; x < _gameLevel._rowGrid; x++)
        {
            if (_foreData[y, x] > (int)ForeState.NONE)
            {
                _foreImage[y, x] = new Image();
                _foreImage[y, x].Source = ImageHelper.CutImage(_bmpForeground, new Int32Rect(0, 0, _cellSize.Width, _cellSize.Height));

                _foreImage[y, x].SetValue(Canvas.LeftProperty, x * (double)_cellSize.Width);
                _foreImage[y, x].SetValue(Canvas.TopProperty, y * (double)_cellSize.Height);
                ForeCanvas.Children.Add(_foreImage[y, x]);
            }
        }
    }
}

在ResetGame()方法最后位置加入对该方法的调用。
 运行程序,看看效果。

技术图片

以上是关于练手WPF——扫雷小游戏的简易实现(中)的主要内容,如果未能解决你的问题,请参考以下文章

练手WPF——扫雷小游戏的简易实现(上)

练手WPF——扫雷小游戏的简易实现(下)

纯原生JS用面向对象class方法实现简易扫雷小游戏

简易扫雷游戏的详解

C | 简易版扫雷的实现

C语言实现简易版扫雷