c#怎么开发出扫雷小游戏

简单的总结一下,如何利用C#进行WinForm 扫雷小游戏的开发:

扫雷游戏的主要设计的类有三个: Main、Pane 、MineField

1)Main 是主控窗体,负责项目的启动和关闭;并协调内部各个组建模块的协调工作。

2)Pane是一个方格的封装,是雷区的重要组建;它表示一个方格的当前状态,以及是否布雷等信息。

3)MineField是雷区的封装,是游戏的核心组建;它负责方格的布局以及地雷的分布;并控制玩家的基本操作以及正确的响应。

类的实现:

一、 Pane类

功能描述:Pane是一个方格的封装,是雷区的重要组建;它表示一个方格的当前状态,以及是否布雷等信息

One.它所具有的公共属性:

名称

可见性

返回值类型

功能描述

AroundMineCount

public

int

获取或设置当前方块周围地雷的数量

HasMine

Public

bool

获取或设置当前方块是否又雷

State

Public

PaneState

获取或设当前方块扫雷的状态

Two.它所具有的公共方法:

名称

可见性

返回类型

参数

功能描述

Mark

public

void

无

把当前方块标记为【有雷】状态,即:插上一个小红旗。

Open

public

void

无

打开该方块。

打开后如果如果有雷,则显示地理图标;否则如果周围有相邻的地理,则显示地雷数量。

Reset

public

void

无

恢复关闭状态,即:取消Mark()的操作结果。

Three:源码:

//默认的构造方法

public Pane()

{InitializeComponent();

this.BackgroundImageLayout = ImageLayout.Stretch;

}

//公有属性:

Public bool HasMine { get; set; }

Public int AroundMineCount { get; set; }

Public PaneState State { get; set; } //由于它有几种状态,设置一个枚举类型属性

public enum PaneState

{
Closed, //关闭状态

Opened, //打开状态

Marked, //标记状态

}

//共有方法:

public void Mark() //标记当前方格为又雷状态,插个小红旗

{
this.BackgroundImage = Properties.Resources.Marked;

this.State = PaneState.Marked;

}

public void Reset() //恢复标记状态,取消小红旗标记

{
this.BackgroundImage = null;

this.State = PaneState.Closed;

}

//打开方法

//打开后如果如果有雷,则显示地理图标;否则如果周围有相邻的地理,则显示地雷数量。

public void Open()

{
if (this.HasMine)

{
this.BackgroundImage = Properties.Resources.MineBomp;

this.Enabled = false;

}

else

{
switch (this.AroundMineCount)

{
case 0:

this.BackgroundImage = null;

this.Enabled = false;

break;

case 1:

this.BackgroundImage = Properties.Resources.Num1;

this.Enabled = false;

break;

case 2:

this.BackgroundImage = Properties.Resources.Num2;

this.Enabled = false;

break;

case 3:

this.BackgroundImage = Properties.Resources.Num3;

this.Enabled = false;

break;

case 4:

this.BackgroundImage = Properties.Resources.Num4;

this.Enabled = false;

break;

case 5:

this.BackgroundImage = Properties.Resources.Num5;

this.Enabled = false;

break;

case 6:

this.BackgroundImage = Properties.Resources.Num6;

this.Enabled = false;

break;

case 7:

this.BackgroundImage = Properties.Resources.Num7;

this.Enabled = false;

break;

case 8:

this.BackgroundImage = Properties.Resources.Num8;

this.Enabled = false;

break;

}

}

}

二、 MineField类

功能描述:CrlMineField是雷区的封装,是游戏的核心组建;它负责方格的布局以及地雷的分布;并控制玩家的基本操作以及正确的响应。

One.它所具有的公有方法

名称

可见性

返回值类型

参数

功能描述

InitMineField

Public

Void

int paneNumber, int mineNumber

初始化雷区。布局方格并随机分布地理。

DisplayAll

Public

Void

无

明示雷区的全部方块里的内容。当踩雷以后,给玩家显示所有地雷位置。

DisplayAround

Pubic

Void

Pane pane

明示与给定方格相关联的无地雷的方格。玩家点击一个无雷方格后使用。

Two.它有具有的私有方法

名称

可见性

返回值类型

参数

功能描述

GetPanesAround

Private

List<Pane>

Pane pane

获取与当前方格相邻的所有方格。

GetMineCountAround

Private

int

Pane pane

获取周围地雷的总数量

GetPaneSize

Private

Size

无

获取每个小方格的大小

LayoutPanes

Private

Void

无

排列有所方格,完成布雷

LayMines

Private

Void

int mineNumber

随机布雷

IsAllMineSweeped

Private

Bool

无

判断是否扫雷成功

Three.事件处理

名称

可见性

返回值类型

参数

功能描述

MineField_SizeChanged

Private

Void

object sender, EventArgs e

如果雷区面板尺寸有变化,则重新进行布局。

OnPaneMouseDown

Private

Void

object sender, EventArgs e

仅处理鼠标左键和右键事件,忽略其他按键。

Four.源码

//事件的委托

public delegate void MineSweepingCompletedEventHandler(object sender, EventArgs e);

public delegate void MineSweepingFailedEventHandler(object sender, EventArgs e);

public partial class CrlMineField : UserControl

{
//成功和失败两个委托事件的申明

public event MineSweepingCompletedEventHandler MineSweepingCompleted;

public event MineSweepingFailedEventHandler MineSweepingFailed;

public CrlMineField()

{
InitializeComponent();

}

 

/// <summary>

/// 初始化雷区

/// </summary>

/// <param name="paneNumber">每排方块的数量</param>

/// <param name="mineNumber">地雷的数量</param>

public void InitMineField(int paneNumber, int mineNumber)

{
if (mineNumber >= paneNumber * paneNumber)

{
throw new ApplicationException("地雷太多了,不合法游戏规则。");

}

// 清空现有的所有方块

if (this.Controls.Count > 0)

{
this.Controls.Clear();

}

//添加雷区方格

for (int i = 0; i < paneNumber * paneNumber; i++)

{
Pane pane = new Pane();

pane.MouseDown += new MouseEventHandler(OnPaneMouseDown);

this.Controls.Add(pane);

}

 

// 布局方格

this.LayoutPanes();

// 随机部署地雷

this.LayMines(mineNumber);

// 设置每个方格周边的地雷数

foreach (Pane p in this.Controls)

{
p.AroundMineCount = this.GetMineCountAround(p);

}

}

/// <summary>

/// 明示雷区的全部方块里的内容

/// </summary>

public void DisplayAll()

{
foreach (Pane pane in this.Controls)

{
if (pane.State != PaneState.Opened)

{
pane.Open();

}

}

}

/// <summary>

/// 明示与给定方格相关联的无地雷的方格

/// </summary>

/// <param name="pane"></param>

public void DisplayAround(Pane pane)

{
if (pane.State == PaneState.Opened || pane.HasMine)

{
return;

}

// 明示当前方格本身

pane.Open();

// 通过递归明示当前方格四周的所有方格

List<Pane> panesAround = this.GetPanesAround(pane);

foreach (Pane p in panesAround)

{
// 如果该方格四周没有相邻的地雷,则递归

if (this.GetMineCountAround(p) == 0)

{
this.DisplayAround(p);

}

else

{
if (p.State != PaneState.Opened && !p.HasMine)

{
p.Open();

}

 

}

}

}

#region 私有方法

/// <summary>

/// 获取与当前方格相邻的所有方格。

/// </summary>

/// <param name="pane">当前方格</param>

/// <returns></returns>

private List<Pane> GetPanesAround(Pane pane)

{
List<Pane> result = new List<Pane>();

// 通过递归明示当前方格四周的所有方格

int paneHeight = this.GetPaneSize().Height;

int paneWidth = this.GetPaneSize().Width;

foreach (Pane p in this.Controls)

{
逐个扫描当前方格四周地雷数目

if (Math.Abs(p.Top - pane.Top) == 0 && Math.Abs(p.Left - pane.Left) == paneWidth

||

Math.Abs(p.Left - pane.Left) == 0 && Math.Abs(p.Top - pane.Top) == paneHeight

||

Math.Abs(p.Top - pane.Top) == paneHeight && Math.Abs(p.Left - pane.Left) == paneWidth

||

Math.Abs(p.Left - pane.Left) == paneWidth && Math.Abs(p.Top - pane.Top) == paneHeight)

{
result.Add(p);

}

}

return result;

}

/// <summary>

/// 获取当前方格四周地雷数量

/// </summary>

/// <param name="pane">当前方格</param>

/// <returns></returns>

private int GetMineCountAround(Pane pane)

{
int result = 0;

List<Pane> panes = this.GetPanesAround(pane);

foreach (Pane p in panes)

{
if (p.HasMine)

{
result++;

}

}

return result;

}

/// <summary>

/// 获取当前每个方格的尺寸

/// </summary>

/// <returns></returns>

private Size GetPaneSize()

{
if (this.Controls.Count == 0)

{
return new Size();

}

else

{
int paneNumber = (int)Math.Sqrt(this.Controls.Count);

int paneWidth = this.Width / paneNumber;

int paneHeight = this.Height / paneNumber;

return new Size(paneWidth, paneHeight);

}

}

/// <summary>

/// 排列所有雷区的方格,完成布局。

/// </summary>

private void LayoutPanes()

{
if (this.Controls.Count <= 0)

{
return;

}

int paneNumber = (int)Math.Sqrt(this.Controls.Count);

int paneHeight = this.GetPaneSize().Height;

int paneWidth = this.GetPaneSize().Width;

int paneIndex = 0;

// 绘制雷区方块

int paneLeft = 0;

int paneTop = 0;

for (int colNum = 0; colNum < paneNumber; colNum++)

{
paneTop = colNum * paneHeight;

for (int rowNum = 0; rowNum < paneNumber; rowNum++)

{
paneLeft = rowNum * paneWidth;

Pane pane = this.Controls[paneIndex] as Pane;

pane.Location = new Point(paneLeft, paneTop);//设置方块位置

pane.Size = new Size(paneWidth, paneHeight);//设置方块大小

paneIndex++;

}

}

}

/// <summary>

/// 随机部署地雷

/// </summary>

/// <param name="mineNumber"></param>

private void LayMines(int mineNumber)

{
Random rdm = new Random();

for (int i = 0; i < mineNumber; i++)

{
while (true)

{
int index = rdm.Next(0, this.Controls.Count);

Pane pane = this.Controls[index] as Pane;

if (!pane.HasMine)

{
pane.HasMine = true;

break;

}

}

}

}

/// <summary>

/// 是否扫雷成功。即:所有地雷都已经正确作出标记

/// </summary>

/// <returns></returns>

private bool IsAllMineSweeped()

{
int markedCount = 0;

int mineCount = 0;

foreach (Pane pane in this.Controls)

{
if (pane.HasMine)

{
mineCount++;

}

if (pane.State == PaneState.Marked)

{
markedCount++;

if (!pane.HasMine)

{
//存在做了标记但没有地雷的方格,扫雷没有正确完成。

return false;

}

}

}

return mineCount == markedCount;

}

#endregion

#region 事件处理

/// <summary>

/// 如果雷区面板尺寸有变化,则重新进行布局。

/// 使得通过改变方格大小来整体适应雷区面板的尺寸。

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

private void CrlMineField_SizeChanged(object sender, EventArgs e)

{
try

{
this.LayoutPanes();

}

catch (Exception ex)

{
ExceptionHandler.OnException(ex);

}

 

}

private void OnPaneMouseDown(object sender, MouseEventArgs e)

{
// 仅处理鼠标左键和右键事件,忽略其他按键。

if (e.Button != MouseButtons.Left && e.Button != MouseButtons.Right)

{
return;

}

try

{
Pane pane = sender as Pane; //获取当前被鼠标点中的方格

if (e.Button == MouseButtons.Left)//鼠标左键

{
if (pane.HasMine) //踩地雷了

{
pane.Open();

this.DisplayAll();

if (this.MineSweepingFailed != null)

{
this.MineSweepingFailed(this, EventArgs.Empty);

}

 

}

else

{
//明示当前方格相邻的所有无地雷的方格

this.DisplayAround(pane);

}

}

else if (e.Button == MouseButtons.Right)//鼠标右键

{
if (pane.State == PaneState.Marked)

{
pane.Reset();//取消小红旗标记

}

else

{
pane.Mark(); //插个小红旗做标记

}

}

// 所有地雷扫除成功

if (this.IsAllMineSweeped())

{
if (this.MineSweepingCompleted != null)

{
this.MineSweepingCompleted(this, EventArgs.Empty);

}

}

}

catch (Exception ex)

{
ExceptionHandler.OnException(ex);

}

}

#endregion
————————————————
版权声明:本文为CSDN博主「夜刺」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/heiyefengdi/article/details/131718246

posted @ 2023-07-14 10:35  夜刺  阅读(175)  评论(0)    收藏  举报