博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
练手WPF(三)——扫雷小游戏的简易实现(上)
阅读量:5086 次
发布时间:2019-06-13

本文共 9044 字,大约阅读时间需要 30 分钟。

原文:

一、创建项目

1.创建WPF项目,设置初始化窗口大小(初级难度):高x宽为430x350。
2.添加文件夹Images,并添加相关图片。

3.xaml中引入图片资源。

4.添加窗口元素

(1)菜单

(2)在菜单之后,</DockPanel>之前添加其他界面元素

其中两个Image用于显示时钟和地雷数图例,其后两个TextBlock分别用于显示读秒数和剩余地雷数。

两个重叠的Canvas,分别显示底层图块和前景图块。底层图块游戏开始后是固定的,其中会显示随机分布的地雷及其周边地雷数值,而前景图块可以通过鼠标点击进行移除或标记为问号或小红旗。

二、载入图片资源

1、添加一个静态图片帮助类ImageHelper,方便以后的图片切片操作。

public static class ImageHelper{    ///     /// BitmapSource图片源剪切操作函数    ///     /// 等待剪切的源    /// 剪切矩形    /// 
已剪切的图片源
public static BitmapSource CutImage(BitmapSource bmpSource, Int32Rect cut) { return new CroppedBitmap(bmpSource, cut); } /// /// 将BitmapImage转换为BitmapSource /// /// 待转换的BitmapImage ///
BitmapSource
public static BitmapSource BitmapImageToBitmapSource(BitmapImage bitmapImage) { ImageSource imageSource = bitmapImage; Bitmap bitmap = ImageSourceToBitmap(imageSource); BitmapSource bitmapSource = BitmapToBitmapImage(bitmap);      bitmap.Dispose(); return bitmapSource; } /// /// 将ImageSource转为Bitmap /// /// ///
public static System.Drawing.Bitmap ImageSourceToBitmap(ImageSource imageSource) { BitmapSource m = (BitmapSource)imageSource; Bitmap bmp = new Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); System.Drawing.Imaging.BitmapData data = bmp.LockBits(new Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bmp.UnlockBits(data); return bmp; } /// /// 将Bitmap转为BitmapImage /// /// ///
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap) { using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); stream.Position = 0; BitmapImage result = new BitmapImage(); result.BeginInit(); result.CacheOption = BitmapCacheOption.OnLoad; result.StreamSource = stream; result.EndInit(); result.Freeze(); return result; } }}

2、添加几个字段变量

主程序MainWindow.xaml.cs中添加:

private BitmapSource _bmpSpace, _bmpMine, _bmpNum1_8, _bmpForeground, _bmpMineOrTimer, _bmpBomb;private System.Drawing.Size _cellSize = new System.Drawing.Size(35, 35);

3、获取图片资源

private void GetImageResource(){    BitmapImage bmpSpace = (BitmapImage)TryFindResource("ImgSpace");    BitmapImage bmpMine = (BitmapImage)TryFindResource("ImgMine");    BitmapImage bmpNum1_8 = (BitmapImage)TryFindResource("ImgNum1_8");    BitmapImage bmpForeground = (BitmapImage)TryFindResource("ImgForeground");    BitmapImage bmpMineOrTimer = (BitmapImage)TryFindResource("ImgMineOrTimer");    BitmapImage bmpBomb = (BitmapImage)TryFindResource("ImgBomb");    _bmpSpace = ImageHelper.BitmapImageToBitmapSource(bmpSpace);    _bmpMine = ImageHelper.BitmapImageToBitmapSource(bmpMine);    _bmpNum1_8 = ImageHelper.BitmapImageToBitmapSource(bmpNum1_8);    _bmpForeground = ImageHelper.BitmapImageToBitmapSource(bmpForeground);    _bmpMineOrTimer = ImageHelper.BitmapImageToBitmapSource(bmpMineOrTimer);    _bmpBomb = ImageHelper.BitmapImageToBitmapSource(bmpBomb);}

 

4、将界面中用到的时钟和地图数这两张图片设置到位。

private void SetTimerAndMineImage(){    ImgClock.Source = ImageHelper.CutImage(_bmpMineOrTimer, new Int32Rect(0, 0, _cellSize.Width, _cellSize.Height));    ImgMineNum.Source = ImageHelper.CutImage(_bmpMineOrTimer, new Int32Rect(1 * _cellSize.Width, 0, _cellSize.Width, _cellSize.Height));}

 

5、将上述两个方法添加到构造方法中。

运行程序,如图1。

 

三、设置状态枚举

添加一个MyEnum.cs类文件,让主cs文件看起来简练一点。内容如下:

// 游戏级别public enum Level{    SIMPLE,    NORMAL,    HARD};// 前景状态public enum ForeState{    NONE,           // 无    NORMAL,         // 正常覆盖    FLAG,           // 红旗    QUESTION        // 问号};// 底层状态public enum BackState{    MINE = -1,      // 地雷    BLANK = 0,      // 空};// 游戏状态public enum GameState{    NONE,           // 未开始    STOP,           // 已停止    START,          // 已开始    PAUSE           // 已暂停};

 

四、添加GameLevel类,定义游戏级别相关参数

public class GameLevel{    public int _mineNum { get; set; }      // 地雷数    public int _rowGrid { get; set; }      // 横格子数    public int _colGrid { get; set; }      // 纵格子数    public GameLevel(int currLevel, int mineNum, int rowGrid, int colGrid)    {        _mineNum = mineNum;        _rowGrid = rowGrid;        _colGrid = colGrid;    }}

 

五、定义主游戏数据变量

private int[,] _backData = null;            // 底部背景数据(雷-1,0为空白,数值(1-8)周围雷数)private int[,] _foreData = null;            // 前景数据(1:正常盖住;2:红旗;3:问号)private Image[,] _backImage = null;         // 底图图片数组private Image[,] _foreImage = null;         // 上方图片数组private GameState _gameState = GameState.NONE;private Random rnd = new Random();          // 随机数private GameLevel _gameLevel;private Level _level = Level.Simple;

 

另外还用到几个计时器,看后面的注释

// 计时private System.Diagnostics.Stopwatch _stopWatchGame = new System.Diagnostics.Stopwatch(); // 游戏过程读秒private DispatcherTimer _timerSetTimeText = new DispatcherTimer();      // 更新读秒文本框private DispatcherTimer _timerWinAnim = new DispatcherTimer();     // 用于胜利时动画private DispatcherTimer _timerBomb = new DispatcherTimer();            // 用于踩雷动画

将计时器初始化放在构造方法中

// 计时器_timerSetTimeText.Interval = new TimeSpan(0, 0, 1);_timerSetTimeText.Tick += _timerSetTimeText_Tick;// 动画计时器_timerWinAnim.Interval = new TimeSpan(0, 0, 0, 0, 300);_timerWinAnim.Tick += _timerWinAnim_Tick;// 用户踩雷后的动画_timerBomb.Interval = new TimeSpan(0, 0, 0, 0, 200);_timerBomb.Tick += _timerBomb_Tick;

 

六、初始化游戏状态

private void InitialGameState(){    _timerSetTimeText.Stop();    _timerWinAnim.Stop();    _stopWatchGame.Reset();    _stopWatchGame.Stop();    _gameState = GameState.NONE;    MenuGamePauseOrContinue.Header = "暂停(_P)";}private void _timerSetTimeText_Tick(object sender, EventArgs e){    textBlockTime.Text = ((int)_stopWatchGame.Elapsed.TotalSeconds).ToString();}private void _timerWinAnim_Tick(object sender, EventArgs e){} private void _timerBomb_Tick(object sender, EventArgs e) {
}

后面动画计时事件方法以后再加入,这里先空着。

 

七、初始化游戏主数据

private void InitGameData(Level level){    switch (level)    {        case  Level.SIMPLE:            _gameLevel = new GameLevel(9, 9, 10);            break;        case Level.NORMAL:            _gameLevel = new GameLevel(16, 16, 40);            break;        case Level.HARD:            _gameLevel = new GameLevel(30, 16, 99);            break;    }    // 设置窗口大小    this.Width = _cellSize.Width * _gameLevel._rowGrid + 40;    this.Height = _cellSize.Height * _gameLevel._colGrid + 20 + 100;    // 获取屏幕大小    double screenWidth = SystemParameters.WorkArea.Width;    double screenHeight = SystemParameters.WorkArea.Height;    // 使窗口居中    this.Left = (screenWidth - this.Width) / 2;    this.Top = (screenHeight - this.Height) / 2;    // 设置绘图控件大小    BackCanvas.Width = _gameLevel._colGrid * _cellSize.Width;    BackCanvas.Height = _gameLevel._rowGrid * _cellSize.Height;    ForeCanvas.Width = BackCanvas.Width;    ForeCanvas.Height = BackCanvas.Height;    // 初始化前景和背景数据    _backData = new int[_gameLevel._colGrid, _gameLevel._rowGrid];    _foreData = new int[_gameLevel._colGrid, _gameLevel._rowGrid];    for (int y = 0; y<_gameLevel._colGrid; y++)    {        for (int x=0; x<_gameLevel._rowGrid; x++)        {            _backData[y, x] = (int)BackState.BLANK;            _foreData[y, x] = (int)ForeState.NORMAL;        }    }    // 初始化前景和背景图片数组    _backImage = new Image[_gameLevel._colGrid, _gameLevel._rowGrid];    _foreImage = new Image[_gameLevel._colGrid, _gameLevel._rowGrid];    // 清理绘制区    BackCanvas.Children.Clear();    ForeCanvas.Children.Clear();}

 

posted on
2019-05-29 22:35 阅读(
...) 评论(
...)

转载于:https://www.cnblogs.com/lonelyxmas/p/10946753.html

你可能感兴趣的文章
map基本用法
查看>>
poj-1163 动态规划
查看>>
Golang之interface(多态,类型断言)
查看>>
Redis快速入门
查看>>
BootStrap---2.表格和按钮
查看>>
Linear Algebra lecture 2 note
查看>>
CRC计算模型
查看>>
Ajax之404,200等查询
查看>>
Aizu - 1378 Secret of Chocolate Poles (DP)
查看>>
csv HTTP简单表服务器
查看>>
OO设计的接口分隔原则
查看>>
数据库连接字符串大全 (转载)
查看>>
java类加载和对象初始化
查看>>
对于负载均衡的理解
查看>>
django简介
查看>>
window.event在IE和Firefox的异同
查看>>
常见的js算法面试题收集,es6实现
查看>>
IO流写出到本地 D盘demoIO.txt 文本中
查看>>
Windows10 下Apache服务器搭建
查看>>
HDU 5458 Stability
查看>>