溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C#如何開發(fā)掃雷游戲

發(fā)布時(shí)間:2020-06-26 17:57:32 來源:網(wǎng)絡(luò) 閱讀:771 作者:蓬萊仙羽 欄目:開發(fā)技術(shù)

簡(jiǎn)單的總結(jié)一下,如何利用C#進(jìn)行WinForm 掃雷小游戲的開發(fā)

掃雷游戲的主要設(shè)計(jì)的類有三個(gè): Main、Pane MineField

1Main 是主控窗體,負(fù)責(zé)項(xiàng)目的啟動(dòng)和關(guān)閉;并協(xié)調(diào)內(nèi)部各個(gè)組建模塊的協(xié)調(diào)工作。

2Pane是一個(gè)方格的封裝,是雷區(qū)的重要組建;它表示一個(gè)方格的當(dāng)前狀態(tài),以及是否布雷等信息。

3MineField是雷區(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)試!

附屬插圖:

C#如何開發(fā)掃雷游戲C#如何開發(fā)掃雷游戲C#如何開發(fā)掃雷游戲C#如何開發(fā)掃雷游戲

向AI問一下細(xì)節(jié)

免責(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)容。

AI