您好,登錄后才能下訂單哦!
簡(jiǎn)單的總結(jié)一下,如何利用C#進(jìn)行WinForm 掃雷小游戲的開發(fā):
掃雷游戲的主要設(shè)計(jì)的類有三個(gè): Main、Pane 、MineField
1)Main 是主控窗體,負(fù)責(zé)項(xiàng)目的啟動(dòng)和關(guān)閉;并協(xié)調(diào)內(nèi)部各個(gè)組建模塊的協(xié)調(diào)工作。
2)Pane是一個(gè)方格的封裝,是雷區(qū)的重要組建;它表示一個(gè)方格的當(dāng)前狀態(tài),以及是否布雷等信息。
3)MineField是雷區(qū)的封裝,是游戲的核心組建;它負(fù)責(zé)方格的布局以及地雷的分布;并控制玩家的基本操作以及正確的響應(yīng)。
類的實(shí)現(xiàn):
一、 Pane類
功能描述:Pane是一個(gè)方格的封裝,是雷區(qū)的重要組建;它表示一個(gè)方格的當(dāng)前狀態(tài),以及是否布雷等信息
One.它所具有的公共屬性:
名稱 | 可見性 | 返回值類型 | 功能描述 |
AroundMineCount | public | int | 獲取或設(shè)置當(dāng)前方塊周圍地雷的數(shù)量 |
HasMine | Public | bool | 獲取或設(shè)置當(dāng)前方塊是否又雷 |
State | Public | PaneState | 獲取或設(shè)當(dāng)前方塊掃雷的狀態(tài) |
Two.它所具有的公共方法:
名稱 | 可見性 | 返回類型 | 參數(shù) | 功能描述 |
Mark | public | void | 無 | 把當(dāng)前方塊標(biāo)記為【有雷】狀態(tài),即:插上一個(gè)小紅旗。 |
Open | public | void | 無 | 打開該方塊。 打開后如果如果有雷,則顯示地理圖標(biāo);否則如果周圍有相鄰的地理,則顯示地雷數(shù)量。 |
Reset | public | void | 無 | 恢復(fù)關(guān)閉狀態(tài),即:取消Mark()的操作結(jié)果。 |
Three:源碼:
//默認(rèn)的構(gòu)造方法
public Pane()
{InitializeComponent();
this.BackgroundImageLayout = ImageLayout.Stretch;
}
//公有屬性:
Public bool HasMine { get; set; }
Public int AroundMineCount { get; set; }
Public PaneState State { get; set; } //由于它有幾種狀態(tài),設(shè)置一個(gè)枚舉類型屬性
public enum PaneState
{
Closed, //關(guān)閉狀態(tài)
Opened, //打開狀態(tài)
Marked, //標(biāo)記狀態(tài)
}
//共有方法:
public void Mark() //標(biāo)記當(dāng)前方格為又雷狀態(tài),插個(gè)小紅旗
{
this.BackgroundImage = Properties.Resources.Marked;
this.State = PaneState.Marked;
}
public void Reset() //恢復(fù)標(biāo)記狀態(tài),取消小紅旗標(biāo)記
{
this.BackgroundImage = null;
this.State = PaneState.Closed;
}
//打開方法
//打開后如果如果有雷,則顯示地理圖標(biāo);否則如果周圍有相鄰的地理,則顯示地雷數(shù)量。
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是雷區(qū)的封裝,是游戲的核心組建;它負(fù)責(zé)方格的布局以及地雷的分布;并控制玩家的基本操作以及正確的響應(yīng)。
One.它所具有的公有方法
名稱 | 可見性 | 返回值類型 | 參數(shù) | 功能描述 |
InitMineField | Public | Void | int paneNumber, int mineNumber | 初始化雷區(qū)。布局方格并隨機(jī)分布地理。 |
DisplayAll | Public | Void | 無 | 明示雷區(qū)的全部方塊里的內(nèi)容。當(dāng)踩雷以后,給玩家顯示所有地雷位置。 |
DisplayAround | Pubic | Void | Pane pane | 明示與給定方格相關(guān)聯(lián)的無地雷的方格。玩家點(diǎn)擊一個(gè)無雷方格后使用。 |
Two.它有具有的私有方法
名稱 | 可見性 | 返回值類型 | 參數(shù) | 功能描述 |
GetPanesAround | Private | List<Pane> | Pane pane | 獲取與當(dāng)前方格相鄰的所有方格。 |
GetMineCountAround | Private | int | Pane pane | 獲取周圍地雷的總數(shù)量 |
GetPaneSize | Private | Size | 無 | 獲取每個(gè)小方格的大小 |
LayoutPanes | Private | Void | 無 | 排列有所方格,完成布雷 |
LayMines | Private | Void | int mineNumber | 隨機(jī)布雷 |
IsAllMineSweeped | Private | Bool | 無 | 判斷是否掃雷成功 |
Three.事件處理
名稱 | 可見性 | 返回值類型 | 參數(shù) | 功能描述 |
MineField_SizeChanged | Private | Void | object sender, EventArgs e | 如果雷區(qū)面板尺寸有變化,則重新進(jìn)行布局。 |
OnPaneMouseDown | Private | Void | object sender, EventArgs e | 僅處理鼠標(biāo)左鍵和右鍵事件,忽略其他按鍵。 |
Four.源碼
//事件的委托
public delegate void MineSweepingCompletedEventHandler(object sender, EventArgs e);
public delegate void MineSweepingFailedEventHandler(object sender, EventArgs e);
public partial class CrlMineField : UserControl
{
//成功和失敗兩個(gè)委托事件的申明
public event MineSweepingCompletedEventHandler MineSweepingCompleted;
public event MineSweepingFailedEventHandler MineSweepingFailed;
public CrlMineField()
{
InitializeComponent();
}
/// <summary>
/// 初始化雷區(qū)
/// </summary>
/// <param name="paneNumber">每排方塊的數(shù)量</param>
/// <param name="mineNumber">地雷的數(shù)量</param>
public void InitMineField(int paneNumber, int mineNumber)
{
if (mineNumber >= paneNumber * paneNumber)
{
throw new ApplicationException("地雷太多了,不合法游戲規(guī)則。");
}
// 清空現(xiàn)有的所有方塊
if (this.Controls.Count > 0)
{
this.Controls.Clear();
}
//添加雷區(qū)方格
for (int i = 0; i < paneNumber * paneNumber; i++)
{
Pane pane = new Pane();
pane.MouseDown += new MouseEventHandler(OnPaneMouseDown);
this.Controls.Add(pane);
}
// 布局方格
this.LayoutPanes();
// 隨機(jī)部署地雷
this.LayMines(mineNumber);
// 設(shè)置每個(gè)方格周邊的地雷數(shù)
foreach (Pane p in this.Controls)
{
p.AroundMineCount = this.GetMineCountAround(p);
}
}
/// <summary>
/// 明示雷區(qū)的全部方塊里的內(nèi)容
/// </summary>
public void DisplayAll()
{
foreach (Pane pane in this.Controls)
{
if (pane.State != PaneState.Opened)
{
pane.Open();
}
}
}
/// <summary>
/// 明示與給定方格相關(guān)聯(lián)的無地雷的方格
/// </summary>
/// <param name="pane"></param>
public void DisplayAround(Pane pane)
{
if (pane.State == PaneState.Opened || pane.HasMine)
{
return;
}
// 明示當(dāng)前方格本身
pane.Open();
// 通過遞歸明示當(dāng)前方格四周的所有方格
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>
/// 獲取與當(dāng)前方格相鄰的所有方格。
/// </summary>
/// <param name="pane">當(dāng)前方格</param>
/// <returns></returns>
private List<Pane> GetPanesAround(Pane pane)
{
List<Pane> result = new List<Pane>();
// 通過遞歸明示當(dāng)前方格四周的所有方格
int paneHeight = this.GetPaneSize().Height;
int paneWidth = this.GetPaneSize().Width;
foreach (Pane p in this.Controls)
{
逐個(gè)掃描當(dāng)前方格四周地雷數(shù)目
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>
/// 獲取當(dāng)前方格四周地雷數(shù)量
/// </summary>
/// <param name="pane">當(dāng)前方格</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>
/// 獲取當(dāng)前每個(gè)方格的尺寸
/// </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>
/// 排列所有雷區(qū)的方格,完成布局。
/// </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;
// 繪制雷區(qū)方塊
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);//設(shè)置方塊位置
pane.Size = new Size(paneWidth, paneHeight);//設(shè)置方塊大小
paneIndex++;
}
}
}
/// <summary>
/// 隨機(jī)部署地雷
/// </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>
/// 是否掃雷成功。即:所有地雷都已經(jīng)正確作出標(biāo)記
/// </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)
{
//存在做了標(biāo)記但沒有地雷的方格,掃雷沒有正確完成。
return false;
}
}
}
return mineCount == markedCount;
}
#endregion
#region 事件處理
/// <summary>
/// 如果雷區(qū)面板尺寸有變化,則重新進(jìn)行布局。
/// 使得通過改變方格大小來整體適應(yīng)雷區(qū)面板的尺寸。
/// </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)
{
// 僅處理鼠標(biāo)左鍵和右鍵事件,忽略其他按鍵。
if (e.Button != MouseButtons.Left && e.Button != MouseButtons.Right)
{
return;
}
try
{
Pane pane = sender as Pane; //獲取當(dāng)前被鼠標(biāo)點(diǎn)中的方格
if (e.Button == MouseButtons.Left)//鼠標(biāo)左鍵
{
if (pane.HasMine) //踩地雷了
{
pane.Open();
this.DisplayAll();
if (this.MineSweepingFailed != null)
{
this.MineSweepingFailed(this, EventArgs.Empty);
}
}
else
{
//明示當(dāng)前方格相鄰的所有無地雷的方格
this.DisplayAround(pane);
}
}
else if (e.Button == MouseButtons.Right)//鼠標(biāo)右鍵
{
if (pane.State == PaneState.Marked)
{
pane.Reset();//取消小紅旗標(biāo)記
}
else
{
pane.Mark(); //插個(gè)小紅旗做標(biāo)記
}
}
// 所有地雷掃除成功
if (this.IsAllMineSweeped())
{
if (this.MineSweepingCompleted != null)
{
this.MineSweepingCompleted(this, EventArgs.Empty);
}
}
}
catch (Exception ex)
{
ExceptionHandler.OnException(ex);
}
}
#endregion
三、Main類
還未完善,負(fù)責(zé)各個(gè)模塊的協(xié)調(diào)工作,如導(dǎo)航菜單里面設(shè)置游戲的開始,結(jié)束,時(shí)間計(jì)時(shí),保存結(jié)果,查看排行榜,游戲的級(jí)別等,由于周末兩天的時(shí)間還未能將其完善,只實(shí)現(xiàn)了一個(gè)大體的功能,當(dāng)然還存在一些Bug,有待調(diào)試!
附屬插圖:
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。