C#贪吃蛇课程设计报告.docx
《C#贪吃蛇课程设计报告.docx》由会员分享,可在线阅读,更多相关《C#贪吃蛇课程设计报告.docx(19页珍藏版)》请在冰豆网上搜索。
C#贪吃蛇课程设计报告
基于VC#.NET的
贪吃蛇游戏的
开发与设计
姓名:
***
学号:
************
班级:
软件081班
指导教师:
***
完成日期:
2011-6-24
1.实验目的…………………………………………………………………2
2.实验任务与要求………………………………………………………2
2.1实验内容………………………………………………………………2
2.2实验要求………………………………………………………………2
2.3实验环境………………………………………………………………2
3.设计方案…………………………………………………………………2
3.1程序功能………………………………………………………………2
3.2设计思想………………………………………………………………2
3.3设计总体流程图………………………………………………………2
3.4设计的具体实现………………………………………………………3
4.程序测试…………………………………………………………………7
4.1测试内容与结果………………………………………………………7
4.2程序运行效果图………………………………………………………7
5.实验总结…………………………………………………………………9
参考文献……………………………………………………………………10
附录……………………………………………………………………………10
附录A:
主要源程序………………………………………………………10
1.实验目的
通过C#课程设计,使学生能将学到的面向对象的程序设计思想应用到具体的工作和学习中,加深对类与对象的理解,要求学生能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。
通过这次课程设计掌握《C#语言程序设计》的编程思想,为后续课程打下基础。
2.实验任务与要求
2.1实验内容
编写一个C#GUI版小游戏程序
2.2实验要求
编写C#语言程序实现贪吃蛇游戏。
一条蛇在密闭的围墙内,在围墙内随机出现多个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计1分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。
并实现多人一起玩。
2.3实验环境
WindowsXP,MicrosoftVisualStudio2010
3.设计方案
3.1程序功能
贪吃蛇游戏是一个经典小游戏,一条蛇在密闭的围墙内,在围墙内随机出现一个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计1分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。
3.2设计思想
程序关键在于表示蛇的图形及蛇的移动。
用一个小矩形块表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用一节表示。
移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇。
食物的出现与消失也是画矩形块和覆盖矩形块。
为了便于理解,定义两个结构体:
食物与蛇。
3.3设计总体流程图
3.4设计的具体实现
(1)画板的设计
1.新建一个Windows应用程序,起名Snake。
2.重命名Form1,改为Splash。
3.从工具栏里拖放一个picturebox到Splash上面,设置属性。
(2)Palette类的实现
画板Palette类是整个游戏的核心处理类,里面定义了画布的大小,背景色,蛇块列表以及游戏速度,移动方向等属性,另外还提供了timer计时器,用于定时更新蛇块坐标位置,以及如何在画面上画图的函数。
(3)Start函数
Start函数用于开始游戏,这个函数的内部其实就是设定食物,以及触发计时器,代码片段如下
(4)OnBlockTimedEvent函数
OnBlockTimedEvent函数是计时器的执行函数,这个函数用于更新蛇块信息列表,以及检测游戏是否结束等等,代码片段如下
(5)CheckDead函数
checkDead函数用于检测游戏是否结束,具体检查规则如下
(6)Move函数
Move函数用于更新整个蛇块的坐标,我们前面通过将蛇块信息放到ArrayList里来表示贪吃蛇的整个信息,其中根据下标从0到Count-1依次表示各个蛇块的信息。
(7)GetFood函数
GetFood函数用于生成下一个食物,其实就是一个蛇块,生成的规则就是,坐标要在画布范围内,并且食物的坐标不能和贪吃蛇的坐标重合,具体代码如下
通过for循环检查食物坐标是否和贪吃蛇的蛇块列表ArrayList里的蛇块有冲突
(8)PaintPalette函数
PaintPalette函数需要一个参数,也就是绘图句柄,然后在这个画布上画图也就是我们看到的游戏效果
首先用背景色清空画布,然后画食物,其次是通过for循环将贪吃蛇的每个蛇块画在画布上,以此达到游戏效果。
(9)FormMain_KeyDown函数
这个函数用于更改贪吃蛇的移动方向,这里设定了wdsa和上下左右都可以使用,更改移动方向的前提就是新的方向不能和当前方向相反,也即是只能90度拐弯,不能180度拐弯。
(10)pictureBox1_Paint函数
这个事件在pictureBox1需要重新绘制的时候发生,这里面只要简单调用一下让贪吃蛇重新绘制一下游戏就行了
4、程序测试
4.1测试内容与结果
A选项——新游戏游戏正常启动
B选项——新游戏——暂停游戏暂停,并显示当前得分
C选项——新游戏——暂停——继续游戏继续运行
D选项——新游戏——(暂停——继续)退出游戏显示当前得分,确认键后退出游戏
E选项——新游戏,蛇头撞出画布界面游戏结束,并显示当前得分0
F选项——新游戏,蛇头吃到食物游戏继续,得分+1
G选项——新游戏,蛇头吃到8个食物后,蛇头撞到蛇尾游戏结束,并显示当前得分8
4.2程序运行效果图
5、实验总结
经过短短两星期的VC#.NET课程设计,让我对C#有了一个更深的了解,以前总认为C#很枯燥,认为那些我们所设计的程序没有什么用处,但现在通过设计贪吃蛇游戏这个程序使我懂得了如何将所学的知识运用于生活当中。
虽然在刚开始设计程序时不太明白如何去设计这程序,但当我看过老师的范例以后,有李初步的思路,用C#语言做出这个贪吃蛇程序后,让我深深感受到C#语言的神奇。
在设计这个程序中我主要学会了运用有关C#语言的知识把面向对象的程序设计思想应用到具体的工作和学习中,加深对类与对象的理解并能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。
同时也产生李很多关于做程序的启发:
1)在设计程序之前,务必要对你所设计的题目和内容有一个系统的了解,
知道所设计的题目和内容包含那些资源。
2)设计程序采用什么编程语言并不是非常重要,关键要有一个清晰的思路
和一个完整的软件流程图,因而,要先把设计原理与思路搞清楚,再把流程图画出来,这样设计起来就简单多了。
3)在设计程序时,不能妄想一次就将整个程序设计好,“反复修改,不断改
进”是程序设计的必经之路,发现错误也是取得成绩的一种。
4)要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而
应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便。
参考文献
《VisualStudioC#.NET2005教程》
《C#入门经典》、《C#高级编程》、《C#程序开发范例宝典》
附录
附录A:
部分源程序
1、Main.cs文件
usingSystem;
usingSystem.Drawing;
usingSystem.Windows.Forms;
namespaceNetterpillars{
classMainGame{
publicstaticGameEnginenetterpillarGameEngine;
privatestaticAINetterpillarobjAINetterpillar=newAINetterpillar();
publicstaticvoidMain(string[]args){
SplashWinSplash;
GameFieldWinGameField;
GameOverWinGameOver=newGameOver();
intLastTick=0;intDesiredFrameRate=10;
//Createthegameengineobject
netterpillarGameEngine=newGameEngine();
WinSplash=newSplash();
while(WinSplash.ShowDialog()==DialogResult.OK){
WinGameField=newGameField();
WinGameField.Show();
Application.DoEvents();
//Createsacopyofthebackgroundimagetoallowerasingthesprites
GameEngine.BackgroundImage=(Image)WinGameField.PicGameField.Image.Clone();
netterpillarGameEngine.CreateGameField(WinGameField.PicGameField.Handle);
while(!
netterpillarGameEngine.GameOver){
if(!
netterpillarGameEngine.Paused){
//EXTRA:
ForceaFramerateof10framestosecondonmaximum
if(System.Environment.TickCount-LastTick>=1000/DesiredFrameRate){
MoveComputerCharacters();
netterpillarGameEngine.Render();
LastTick=System.Environment.TickCount;
}
}
Application.DoEvents();
}
WinGameOver.ShowDialog();
WinGameField.Dispose();
}
netterpillarGameEngine=null;
WinSplash.Dispose();
WinGameOver.Dispose();
}
publicstaticvoidMoveComputerCharacters(){
//MovetheNetterpillars
for(inti=0;iif(!
netterpillarGameEterPillars[i].IsDead){
//A.I.forthecomputer-controledNetterpillars
if(netterpillarGameEterPillars[i].IsComputer){
netterpillarGameEterPillars[i].Direction=objAINetterpillar.ChooseNetterpillarDirection(netterpillarGameEterPillars[i].Location,netterpillarGameEterPillars[i].Direction);
}
}
}
}
}
}
2、NetterPillar.cs文件
usingSystem;
usingSystem.Drawing;
usingSystem.Windows.Forms;
namespaceNetterpillars{
publicclassNetterpillar:
Sprite{
privateBitmapNetterHeadN;
privateBitmapNetterHeadS;
privateBitmapNetterHeadE;
privateBitmapNetterHeadW;
publicNetterBody[]NetterBody;
publicintNetterBodyLength=4;
publicboolIsComputer=true;//Defaultstocomputer-controlednetterpillar
publicboolIsDead=false;//Defaultstoalivenetterpillar
//Wecanonlysetthedirectiononce,untilthe
//netterpillarmoves,orwecanrunoverourowntail
privatebooldirectionSet=false;
privateCompassDirectionsdirection;
publicnewCompassDirectionsDirection{
get{
returndirection;
}
set{
//Onlysetthedirectiononce,untilwereceivethedirectionfrom
//theremoteplayer
if(!
directionSet){
direction=value;
directionSet=true;
}
}
}
publicNetterpillar(intx,inty,Sprite.CompassDirectionsinitialDirection,boolisComputer){
NetterBody=newNetterBody[25+1];
intincX=0,incY=0;
IsComputer=isComputer;
NetterHeadN=Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer?
"":
"Player")+"NetterHeadN.gif");
NetterHeadS=Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer?
"":
"Player")+"NetterHeadS.gif");
NetterHeadE=Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer?
"":
"Player")+"NetterHeadE.gif");
NetterHeadW=Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer?
"":
"Player")+"NetterHeadW.gif");
for(inti=0;iNetterBody[i]=newNetterBody(IsComputer);
}
//PositiontheNetterpillaronthegivenpoint
Direction=initialDirection;
Location.X=x;
Location.Y=y;
//Positioneachofthebodyparts
switch(Direction){
caseSprite.CompassDirections.East:
incX=-1;
break;
caseSprite.CompassDirections.South:
incY=-1;
break;
caseSprite.CompassDirections.West:
incX=1;
break;
caseSprite.CompassDirections.North:
incY=1;
break;
}
for(inti=0;ix+=incX;
y+=incY;
NetterBody[i].Location.X=x;
NetterBody[i].Location.Y=y;
}
}
publicvoidEatAndMove(intx,inty,System.IntPtrwinHandle){
//IftheNetterBodyarrayisfull,allocatemorespace
if(NetterBodyLength==NetterBody.Length){
NetterBody[]tempNetterBody=newNetterBody[NetterBody.Length+25+1];
NetterBody.CopyTo(tempNetterBody,0);
NetterBody=tempNetterBody;
}
NetterBody[NetterBodyLength]=newNetterBody(IsComputer);
NetterBody[NetterBodyLength].Location=NetterBody[NetterBodyLength-1].Location;
//Updatesthewholebodyspositionandthentheheadposition
for(inti=NetterBodyLength-1;i>=1;i--){
NetterBody[i].Location=NetterBody[i-1].Location;
}
NetterBody[0].Location=Location;
NetterBody[0].Draw(winHandle);
NetterBodyLength++;
//UpdatestheNetterpillarheadposition
Location=newPoint(x,y);
//Clearthemushroom
Erase(winHandle);
//DrawtheNetterpillarhead
Draw(winHandle);
//Resetthedirectioncontrollervariable
directionSet=false;
}
publicvoidMove(intx,inty,System.IntPtrwinHandle){
//Erasethelastpartofthebody
NetterBody[NetterBodyLength-1].Erase(winHandle);
//Updatesthewholebodyspositionandthentheheadposition
for(inti=NetterBodyLength-1;i>=1;i--){
NetterBody[i].Location=NetterBody[i-1].Location;
}
NetterBody[0].Location=Location;
Location=newPoint(x,y);
//Redrawsonlythefirstpartofthebodyandthehead
NetterBody[0].Draw(winHandle);
//Wedon'tneedtoerasethenetterpillarhead,sincethebodywillcoverit
Draw(winHandle);
//Resetthedirectioncontrollervariable
directionSet=false;
}
publicnewvoidDraw(System.IntPtrwinHandle){
switch(Direction){
caseSprite.CompassDirections.East:
base.Draw(NetterHeadE,winHandle);
break;
caseSprite.CompassDirections.South:
base.Draw(NetterHeadS,winHandle);
break;
caseSprite.CompassDirections.West:
base.Draw(NetterHeadW,winHandle);
break;
caseSprite.CompassDirections.North:
base.Draw(Ne