詳解從零開始---用C#制作掃雷游戲
學(xué)C#的原因其實(shí)挺簡(jiǎn)單的,因?yàn)橐恢睂?duì)游戲挺感興趣,查了下比較流行的游戲引擎Unity的主要開發(fā)語(yǔ)言是C#,所以就決定從C#入手,學(xué)學(xué)面向?qū)ο蟮木幊谭椒ā?/p>
以前基本都做的是嵌入式開發(fā),做嵌入式久了,基本上只用C語(yǔ)言,C語(yǔ)言面向過(guò)程的特性在嵌入式編程這種資源極度受限的情況確實(shí)十分有利,但這種方式在面對(duì)大型軟件的開發(fā)的時(shí)候就很難勝任了。編程的模式其實(shí)是一種思維習(xí)慣,習(xí)慣久了以后,想改變確實(shí)是一個(gè)艱難的過(guò)程···
說(shuō)起C#,其實(shí)在大學(xué)的時(shí)候?qū)W過(guò)一個(gè)學(xué)期,說(shuō)來(lái)慚愧那時(shí)候倒也沒把它當(dāng)一門面向?qū)ο蟮恼Z(yǔ)言(其實(shí)是當(dāng)時(shí)根本不知道面向?qū)ο笫巧叮?,感覺跟C語(yǔ)言也就一點(diǎn)語(yǔ)法差異,把所有的用法全部歸為語(yǔ)法不同,說(shuō)來(lái)也神奇,這種方法倒也能編程。最終學(xué)期結(jié)束的時(shí)候交上去一份用Winform開發(fā)的掃雷游戲結(jié)束了我的C#學(xué)習(xí),在那之后就再也沒碰過(guò)C#。
現(xiàn)在重拾C#,為了免除掉不必要的干擾,并沒有直接在Unity上學(xué)習(xí),而是仍然在VS中學(xué)習(xí),但這次選擇了比較新的WPF,而不是WInform,作為學(xué)習(xí),第一個(gè)任務(wù)還是跟以前一樣做一個(gè)掃雷游戲。
寫在不怎么前面的前面:本文主要分享下程序分析過(guò)程,具體的實(shí)現(xiàn)方法不是本文重點(diǎn),對(duì)實(shí)現(xiàn)有問(wèn)題的朋友可以自行評(píng)論區(qū)留言索要源碼或者提問(wèn)^_^。
一、分析
1.游戲分析
那進(jìn)入正題,應(yīng)該如何完成這個(gè)游戲。忽略細(xì)枝末節(jié)的部分(如計(jì)時(shí),顯示剩余雷數(shù),菜單欄等)不說(shuō),就單說(shuō)這個(gè)游戲的主體:掃雷區(qū)。
在游戲沒開始的時(shí)候,掃雷區(qū)放眼望去其實(shí)只有一個(gè)東西,那就是方塊...
忽略光影效果不談(是的,我又忽略了···),所有方塊的顏色都一樣,都響應(yīng)相同的事件,那就是左鍵和右鍵。左鍵點(diǎn)開方塊,右鍵給方塊做個(gè)標(biāo)記,認(rèn)定為地雷。再繼續(xù)分析,方塊具有不同的種類。有的方塊點(diǎn)開之后周圍會(huì)有一大片方塊一起打開。有的方塊下面是地雷,點(diǎn)開就GameOver。還有方塊下面是數(shù)字,代表著周圍有多少個(gè)地雷。(果然,我又忽略了鼠標(biāo)兩個(gè)鍵同時(shí)按自動(dòng)打開周圍格子和第二次右鍵可以顯示問(wèn)號(hào)的功能···但其實(shí)之后會(huì)發(fā)現(xiàn)這個(gè)功能其實(shí)要增加也會(huì)很簡(jiǎn)單)。
所以,先來(lái)總結(jié)下掃雷游戲?qū)崿F(xiàn)的核心:
- 方塊會(huì)響應(yīng)鼠標(biāo)事件(左鍵按下,左鍵單擊,右鍵按下,鼠標(biāo)移入,鼠標(biāo)移出)。
- 方塊被點(diǎn)開后的效果有三種(炸彈,數(shù)字,空),其中為空的時(shí)候會(huì)自動(dòng)展開周圍所有的方塊。
- 方塊只能被打開一次,之后不再響應(yīng)按鍵事件。
- 當(dāng)插旗的方塊數(shù)和地雷數(shù)相等,并且每個(gè)包含地雷的方塊都被插了旗,則游戲勝利。
- 當(dāng)包含地雷的方塊被打開,則游戲失敗。
2.實(shí)現(xiàn)技術(shù)分析
經(jīng)過(guò)分析,是不是發(fā)現(xiàn)掃雷的的玩法其實(shí)很簡(jiǎn)單,實(shí)現(xiàn)的技術(shù)也不難,全是靜態(tài)的沒有動(dòng)畫的存在。
方塊的表現(xiàn)很像一個(gè)只能按一次的按鈕(事實(shí)上,在大學(xué)的時(shí)候我就是直接繼承的按鈕控件)。
但這一次為了能使用到更多C#相關(guān)的東西我使用了更加麻煩的自定義控件的方式。
方塊有三種表現(xiàn)形式,為特殊性,但很顯然也具有共性,所以在設(shè)計(jì)的時(shí)候,我把按鈕共性抽離出來(lái),設(shè)計(jì)成了一個(gè)抽象的基類Cube。方塊有三種類型,但因?yàn)槲覒?,所以把其中的兩種(空白和數(shù)字)合并為了NumCube類,包含地雷的為BombCube類,這兩個(gè)類分別繼承了Cube。
Cube的實(shí)現(xiàn):
Cube類中擁有以下字段:
ImageSource cubeNormalPic ImageSource cubeOnPic ImageSource cubeDownPic ImageSource cubeDisablePic ImageSource cubeFlagPic
這5個(gè)字段是用來(lái)設(shè)置Cube在各個(gè)狀態(tài)所顯示的圖片的(普通,鼠標(biāo)進(jìn)入,左鍵按下,失能,標(biāo)記)
Bool isEnable Bool isFlag
這兩個(gè)字段就是標(biāo)記Cube是否被使能和Flag
Image cubeImageHigh Image cubeImageLow
這2個(gè)是兩個(gè)image控件,作用是用來(lái)顯示圖片,之所以要2個(gè)圖片是因?yàn)槠熳訄D片被設(shè)計(jì)為一個(gè)疊加在Cube上的圖片。
下面再來(lái)重點(diǎn)講下下面2個(gè)東西:
displayCube mouseEvent
在設(shè)計(jì)中,這是兩個(gè)接口,分別用來(lái)處理鼠標(biāo)事件和方塊的展開。不同于直接在內(nèi)部直接實(shí)現(xiàn)接口,將兩個(gè)接口設(shè)計(jì)為Cube屬性是為了能動(dòng)態(tài)的修改這兩個(gè)接口的實(shí)現(xiàn)方式,不至于每次修改都需要對(duì)Cube內(nèi)的代碼進(jìn)行修改,且可以實(shí)現(xiàn)每個(gè)不同的Cube都使用不同的代碼而不需要使用重寫,這種方式在設(shè)計(jì)模式中也叫“策略模式”。
Cube只擁有一個(gè)方法,那就是Open,但這個(gè)方法其實(shí)也是有display接口代理實(shí)現(xiàn)。
public void Open()
{
if (displayCube != null)
{
displayCube.Open(this);
}
}
displayCube.Open(this)之所以要把自身傳入,是因?yàn)镺pen方法要用到Cube自己的參數(shù)和方法。
BombCube繼承自Cube
只添加了一個(gè)字段:
ImageSource bombPic
用來(lái)存儲(chǔ)地雷圖片.
NumCube 繼承自Cube
Int bombNum
用來(lái)記錄方塊周圍有多少個(gè)BombCube,當(dāng)其為0的時(shí)候,NumCube就是顯示為空的方塊。
添加了一個(gè)組件lable用來(lái)顯示數(shù)字Text。
interface的實(shí)現(xiàn)
分別為每種Cube設(shè)計(jì)了一種接口的實(shí)現(xiàn)方式,使用這種方式,若后期需要改為動(dòng)畫顯示,也只需要實(shí)現(xiàn)一個(gè)動(dòng)畫的接口,賦值給對(duì)應(yīng)的Cube就可以了。
二、實(shí)現(xiàn)
控件繼承:
Wpf進(jìn)行控件繼承的時(shí)候需要注意,被繼承的控件不能有xaml。
在繼承的時(shí)候,xaml中需要加入如下語(yǔ)句:
< myTypes:Cube x:Class="掃雷.UserControl.NumCube" xmlns=" http:// schemas.microsoft.com/w infx/2006/xaml/presentation " xmlns:x=" http:// schemas.microsoft.com/w infx/2006/xaml " xmlns:mc=" http:// schemas.openxmlformats.org /markup-compatibility/2006 " xmlns:d=" http:// schemas.microsoft.com/e xpression/blend/2008 " mc:Ignorable="d" xmlns:myTypes="clr-namespace:掃雷.UserControl" d:DesignHeight="18" d:DesignWidth="18">
Cube 鼠標(biāo)事件的實(shí)現(xiàn):
鼠標(biāo)事件主要是在各個(gè)事件中實(shí)現(xiàn)對(duì)Cube圖片的變換,例如鼠標(biāo)移出事件
public void MouseLeaveCube(object sender, MouseEventArgs e)
{
BombCube bombCube = sender as BombCube;
if (bombCube.IsEnable)
{
isClicking = false;
bombCube.cubeImageLow.Source =
bombCube.cubeNormalPic;
}
}
關(guān)于地雷位置的生成算法實(shí)現(xiàn):
游戲很重要的一個(gè)方面是,每次地雷的位置應(yīng)該不同。很容易想到應(yīng)該用隨機(jī)數(shù)來(lái)產(chǎn)生地雷的位置。這就需要隨機(jī)生成N個(gè)不相同的坐標(biāo)。本程序的實(shí)現(xiàn)方法是創(chuàng)建一個(gè)list<int>,之后使用隨機(jī)數(shù)在0-sizeX * sizeY - 1之間隨機(jī)生成一個(gè)數(shù),檢查list中是否包含該數(shù)字,若不包含則添加進(jìn)list,直到list擁有N個(gè)元素停止。
List<int> BombIndexList=new List<int>();
Random ran = new Random();
do
{
int bombIndex = ran.Next(0,sizeX * sizeY - 1);
if(!BombIndexList.Contains(bombIndex))
{
BombIndexList.Add(bombIndex);
}
else
{
continue;
}
} while (BombIndexList.Count < BombNum);
IndexList = BombIndexList;
之后根據(jù)生成的list來(lái)確定坐標(biāo)上應(yīng)該是NumCube還是BombCube
for (int y = 0; y < sizeY; y++)
{
for (int x = 0; x < sizeX;x++)
{
//cube屬性設(shè)置
if(bombIndexList.Exists((int temp) => temp == x + y * cubeX))
{
cubexMatrix[x, y] =bombCubeList[bombIndex++];
}
else
{
numCubeList[numIndex].Text ="";
cubexMatrix[x, y] =numCubeList[numIndex++];
}
cubexMatrix[x, y].IsFlag =false;
cubexMatrix[x, y].Margin =new Thickness(x * 18, y * 18, 0, 0);
cubexMatrix[x, y].IsEnable = true;
SetCubeBombNum(cubexMatrix,cubeX, cubeY);
bombGrid.Children.Add(cubexMatrix[x, y]);
}
}
如何讓空白Cube打開以后會(huì)打開周圍的Cube:
因?yàn)檫@種打開方式有點(diǎn)類似于遞歸,需要有傳染性(即若打開的也是空白Cube,則其也應(yīng)該打開周圍的Cube),所以執(zhí)行該事件的時(shí)候一定要具有周圍Cube的信息(即能獲取到周圍的控件)。
獲取周圍的Cube的方法有兩種:
1.保存Cube自身的位置,并獲取所有Cube的位置
2.保存周圍Cube的信息
我使用的是第二種方式,之前Cube類中的Cubelist就是用來(lái)保存周圍Cube的信息的。通過(guò)CubeList找到周圍Cube,并觸發(fā)他們的左鍵單擊事件。
public void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
NumCube numCube = sender as NumCube;
if (numCube.IsEnable && numCube.IsFlag == false)
{
// 完成在控件上點(diǎn)擊
if (isClicking)
{
isClicking = false;
numCube.IsEnable = false;
if (numCube.BombNum != 0)
numCube.Text = Convert.ToString(numCube.BombNum);
else
{
foreach (Cube cubeTemp in numCube.CubeList)
{
MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
args.RoutedEvent = Cube.MouseLeftButtonDownEvent;
cubeTemp.RaiseEvent(args);
args.RoutedEvent = Cube.MouseLeftButtonUpEvent;
cubeTemp.RaiseEvent(args);
}
}
}
}
}
一些小技巧:
1.可以把一些圖片的修改放在屬性的set內(nèi),例如disable的圖片。
public bool IsEnable
{
get { return isEnable; }
set
{
isEnable = value;
if (isEnable)
{
if (cubeNormalPic != null)
cubeImageLow.Source = cubeNormalPic;
}
else
{
if (cubeDisablePic != null)
cubeImageLow.Source = cubeDisablePic;
}
}
}
2.Wpf創(chuàng)建控件較慢,為了提升(修改寬度長(zhǎng)度或地雷數(shù)量之后)游戲開始速度,應(yīng)該預(yù)先創(chuàng)建控件,并把控件放入list或者arr保存,按照需求取出。
到這掃雷游戲的制作就沒什么難度技術(shù)上的難度的,只需要通過(guò)百度了解一些WPF常用的事件,控件,xalm相關(guān)的知識(shí)就能做出一個(gè)掃雷游戲啦。相關(guān)源碼就不發(fā)在這了,需要的朋友可以評(píng)論中找我,這次游戲制作讓我對(duì)面向?qū)ο蟮幕揪幊谭椒ǖ牧私庥辛艘粋€(gè)很大的提升,下次應(yīng)該就可以在Unity中做游戲啦 哈哈。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C#開發(fā)微信門戶及應(yīng)用(1) 微信接口使用
欄 目:C#教程
本文標(biāo)題:詳解從零開始---用C#制作掃雷游戲
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/5657.html
您可能感興趣的文章
- 01-10C#中Socket通信用法實(shí)例詳解
- 01-10C#裝箱和拆箱原理詳解
- 01-10C#類的多態(tài)性詳解
- 01-10C#創(chuàng)建不規(guī)則窗體的4種方式詳解
- 01-10C#中深度復(fù)制和淺度復(fù)制詳解
- 01-10C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(1)
- 01-10輕松學(xué)習(xí)C#的String類
- 01-10C#數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Quene)實(shí)例詳解
- 01-10C#數(shù)據(jù)結(jié)構(gòu)之順序表(SeqList)實(shí)例詳解
- 01-10C#編程實(shí)現(xiàn)連接ACCESS數(shù)據(jù)庫(kù)實(shí)例詳解


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過(guò)反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過(guò)重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法


