C#贪吃蛇课程设计报告.pdf
C#课程设计基于基于 VC#.NETVC#.NET 的的贪吃蛇游戏的贪吃蛇游戏的开发与设计开发与设计姓名:李贵敏姓名:李贵敏学号:学号:200880114105200880114105班级:软件班级:软件 081081 班班指导教师:程铭指导教师:程铭完成日期:完成日期:2011-6-22011-6-24 4C#课程设计1目录目录1.1.实验目的实验目的22.2.实验任务与要求实验任务与要求22.1 实验内容22.2 实验要求22.3 实验环境23.3.设计方案设计方案23.1 程序功能23.2 设计思想23.3 设计总体流程图23.4 设计的具体实现34.4.程序测试程序测试74.1 测试内容与结果74.2 程序运行效果图75.5.实验总结实验总结9参考文献参考文献10附录附录10附录 A:主要源程序10C#课程设计21.1. 实验目的实验目的通过 C#课程设计,使学生能将学到的面向对象的程序设计思想应用到具体的工作和学习中,加深对类与对象的理解,要求学生能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。通过这次课程设计掌握C#语言程序设计的编程思想,为后续课程打下基础。2.2. 实验任务与要求实验任务与要求2.1 实验内容编写一个 C#GUI 版小游戏程序2.2 实验要求编写 C#语言程序实现贪吃蛇游戏。一条蛇在密闭的围墙内,在围墙内随机出现多个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计 1 分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。并实现多人一起玩。2.3 实验环境Windows XP, Microsoft Visual Studio 20103.3. 设计方案设计方案3.1 程序功能贪吃蛇游戏是一个经典小游戏,一条蛇在密闭的围墙内,在围墙内随机出现一个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计 1 分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。3.2 设计思想程序关键在于表示蛇的图形及蛇的移动。用一个小矩形块表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用一节表示。移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇。食物的出现与消失也是画矩形块和覆盖矩形块。为了便于理解,定义两个结构体:食物与蛇。3.3 设计总体流程图C#课程设计3载入游戏并初始化蛇开始移动根据键盘控制蛇移动方向判断蛇头和食物的坐标是否重合随机生成多个食物是否判断蛇头和自身及墙是否重游戏结束是否开始游戏退出游戏继续游戏暂停游戏3.4 设计的具体实现(1)画板的设计C#课程设计41.新建一个 Windows 应用程序,起名 Snake。2.重命名 Form1,改为 Splash。3.从工具栏里拖放一个 picturebox 到 Splash 上面,设置属性。(2) PalettePalette 类的实现类的实现画板 Palette 类是整个游戏的核心处理类,里面定义了画布的大小,背景色,蛇块列表以及游戏速度,移动方向等属性,另外还提供了 timer 计时器,用于定时更新蛇块坐标位置,以及如何在画面上画图的函数。(3)Start 函数函数Start 函数用于开始游戏,这个函数的内部其实就是设定食物,以及触发计时器,代码片段如下C#课程设计5(4) OnBlockTimedEvent 函数OnBlockTimedEvent 函数是计时器的执行函数,这个函数用于更新蛇块信息列表,以及检测游戏是否结束等等,代码片段如下(5)CheckDead 函数函数checkDead 函数用于检测游戏是否结束,具体检查规则如下(6) MoveMove 函数函数Move 函数用于更新整个蛇块的坐标, 我们前面通过将蛇块信息放到 ArrayList 里来表示贪吃蛇的整个信息,其中根据下标从 0 到 Count-1 依次表示各个蛇块的信息。(7) GetFood 函数函数GetFood 函数用于生成下一个食物,其实就是一个蛇块,生成的规则就是,坐标要在画布范围内,并且食物的坐标不能和贪吃蛇的坐标重合,具体代码如下C#课程设计6通过 for 循环检查食物坐标是否和贪吃蛇的蛇块列表 ArrayList 里的蛇块有冲突(8) PaintPalettePaintPalette 函数函数PaintPalette 函数需要一个参数,也就是绘图句柄,然后在这个画布上画图也就是我们看到的游戏效果首先用背景色清空画布,然后画食物,其次是通过 for 循环将贪吃蛇的每个蛇块画在画布上,以此达到游戏效果。(9) FormMain_KeyDown 函数函数这个函数用于更改贪吃蛇的移动方向,这里设定了 wdsa 和上下左右都可以使用,更改移动方向的前提就是新的方向不能和当前方向相反, 也即是只能 90 度拐弯, 不能 180 度拐弯。C#课程设计7(10) pictureBox1_PaintpictureBox1_Paint 函数函数这个事件在 pictureBox1 需要重新绘制的时候发生,这里面只要简单调用一下让贪吃蛇重新绘制一下游戏就行了4 4、程序测试、程序测试4.1 测试内容与结果A选项新游戏游戏正常启动B选项新游戏暂停游戏暂停,并显示当前得分C选项新游戏暂停继续游戏继续运行D选项新游戏(暂停继续)退出游戏显示当前得分,确认键后退出游戏E选项新游戏,蛇头撞出画布界面游戏结束,并显示当前得分 0F选项新游戏,蛇头吃到食物游戏继续,得分+1G选项新游戏,蛇头吃到 8 个食物后,蛇头撞到蛇尾游戏结束,并显示当前得分 84.2 程序运行效果图C#课程设计8C#课程设计95 5、实验总结、实验总结经过短短两星期的 VC#.NET 课程设计,让我对 C#有了一个更深的了解,以前总认为 C#很枯燥,认为那些我们所设计的程序没有什么用处,但现在通过设计贪吃蛇游戏这个程序使我懂得了如何将所学的知识运用于生活当中。虽然在刚开始设计程序时不太明白如何去设计这程序,但当我看过老师的范例以后,有李初步的思路,用 C#语言做出这个贪吃蛇程序后,让我深深感受到 C#语言的神奇。在设计这个程序中我主要学会了运用有关 C#语言的知识把面向对象的程序C#课程设计10设计思想应用到具体的工作和学习中,加深对类与对象的理解并能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。同时也产生李很多关于做程序的启发:1) 在设计程序之前,务必要对你所设计的题目和内容有一个系统的了解,知道所设计的题目和内容包含那些资源。2) 设计程序采用什么编程语言并不是非常重要,关键要有一个清晰的思路和一个完整的软件流程图,因而,要先把设计原理与思路搞清楚,再把流程图画出来,这样设计起来就简单多了。3) 在设计程序时,不能妄想一次就将整个程序设计好,“反复修改,不断改进”是程序设计的必经之路,发现错误也是取得成绩的一种。4) 要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便。参考文献参考文献VisualVisual StudioStudio C#.NETC#.NET 20052005 教程教程C#C#入门经典入门经典 、 C#C#高级编程高级编程 、 C#C#程序开发范例宝典程序开发范例宝典附录附录附录 A:部分源程序1 1、Main.csMain.cs 文件文件using System;using System.Drawing;using System.Windows.Forms;namespace Netterpillars class MainGame public static GameEngine netterpillarGameEngine;private static AINetterpillar objAINetterpillar = new AINetterpillar();public static void Main(string args) Splash WinSplash;GameField WinGameField;GameOver WinGameOver = new GameOver();int LastTick=0; int DesiredFrameRate = 10;/ Create the game engine objectnetterpillarGameEngine = new GameEngine();WinSplash = new Splash();while ( WinSplash.ShowDialog()=DialogResult.OK) WinGameField = new GameField();WinGameField.Show();C#课程设计11Application.DoEvents();/Creates a copy of the background image to allow erasing the spritesGameEngine.BackgroundImage=(Image)WinGameField.PicGameField.Image.Clone();netterpillarGameEngine.CreateGameField(WinGameField.PicGameField.Handle);while ( !netterpillarGameEngine.GameOver) if (!netterpillarGameEngine.Paused) / EXTRA: Force a Frame rate of 10 frames to second on maximumif(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();public static void MoveComputerCharacters() /Move the Netterpillarsfor(int i=0; inetterpillarGameEngine.NetterpillarNumber; i+) if (!netterpillarGameEterPillarsi.IsDead) / A.I. for the computer-controled Netterpillarsif (netterpillarGameEterPillarsi.IsComputer) netterpillarGameEterPillarsi.Direction=objAINetterpillar.ChooseNetterpillarDirection(netterpillarGameEterPillarsi.Location, netterpillarGameEterPillarsi.Direction);2 2、NetterPillar.csNetterPillar.cs文件文件using System;using System.Drawing;C#课程设计12using System.Windows.Forms;namespace Netterpillars public class Netterpillar : Sprite private Bitmap NetterHeadN;private Bitmap NetterHeadS;private Bitmap NetterHeadE;private Bitmap NetterHeadW;public NetterBody NetterBody;public int NetterBodyLength = 4;public bool IsComputer = true; / Defaults to computer-controled netterpillarpublic bool IsDead = false; / Defaults to alive netterpillar/ We can only set the direction once, until the/netterpillar moves, or we can run over our own tailprivate bool directionSet = false;private CompassDirections direction;public new CompassDirections Direction get return direction;set / Only set the direction once, until we receive the direction from/the remote playerif (!directionSet) direction = value;directionSet = true;public Netterpillar(int x, int y, Sprite.CompassDirections initialDirection,bool isComputer) NetterBody = new NetterBody25+1;int incX=0, incY=0;IsComputer = isComputer;NetterHeadN=Load(Application.StartupPath+IMAGE_PATH+(IsComputer?:Player)+NetterHeadN.gif);NetterHeadS=Load(Application.StartupPath+IMAGE_PATH+(IsComputer?:C#课程设计13Player)+NetterHeadS.gif);NetterHeadE=Load(Application.StartupPath+IMAGE_PATH+(IsComputer?:Player)+NetterHeadE.gif);NetterHeadW=Load(Application.StartupPath+IMAGE_PATH+(IsComputer?:Player)+NetterHeadW.gif);for(int i=0; iNetterBodyLength; i+) NetterBodyi = new NetterBody(IsComputer);/ Position the Netterpillar on the given pointDirection = initialDirection;Location.X = x;Location.Y = y;/ Position each of the body partsswitch(Direction) case Sprite.CompassDirections.East:incX = -1;break;case Sprite.CompassDirections.South:incY = -1;break;case Sprite.CompassDirections.West:incX = 1;break;case Sprite.CompassDirections.North:incY = 1;break;for(int i=0; i=1; i-) NetterBodyi.Location = NetterBodyi-1.Location;NetterBody0.Location = Location;NetterBody0.Draw(winHandle);NetterBodyLength+;/ Updates the Netterpillar head positionLocation = new Point(x, y);/Clear the mushroomErase(winHandle);/ Draw the Netterpillar headDraw(winHandle);/ Reset the direction controller variabledirectionSet = false;public void Move(int x, int y, System.IntPtr winHandle) / Erase the last part of the bodyNetterBodyNetterBodyLength-1.Erase(winHandle);/ Updates the whole bodys position and then the head positionfor(int i=NetterBodyLength-1; i=1; i-) NetterBodyi.Location = NetterBodyi-1.Location;NetterBody0.Location = Location;Location = new Point(x, y);/ Redraws only the first part of the body and the headNetterBody0.Draw(winHandle);/We dont need to erase the netterpillar head, since the body will coveritC#课程设计15Draw(winHandle);/ Reset the direction controller variabledirectionSet = false;public new void Draw(System.IntPtr winHandle) switch(Direction) case Sprite.CompassDirections.East:base.Draw(NetterHeadE, winHandle);break;case Sprite.CompassDirections.South:base.Draw(NetterHeadS, winHandle);break;case Sprite.CompassDirections.West:base.Draw(NetterHeadW, winHandle);break;case Sprite.CompassDirections.North:base.Draw(NetterHeadN, winHandle);break;for(int i=0; iNetterBodyLength; i+) NetterBodyi.Draw(winHandle);