C#贪吃蛇课程设计报告

C#课程设计

基于VC#.NET的

贪吃蛇游戏的

开发与设计

姓名:李贵敏

学号:200880114105

班级:软件081班

指导教师:程铭

完成日期:2011-6-24

C#课程设计

目录

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#课程设计

1. 实验目的

通过C#课程设计,使学生能将学到的面向对象的程序设计思想应用到具体的工作和学习中,加深对类与对象的理解,要求学生能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。

通过这次课程设计掌握《C#语言程序设计》的编程思想,为后续课程打下基础。

2. 实验任务与要求

2.1实验内容

编写一个C#GUI版小游戏程序

2.2实验要求

编写C#语言程序实现贪吃蛇游戏。一条蛇在密闭的围墙内,在围墙内随机出现多个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计1分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。并实现多人一起玩。

2.3实验环境

Windows XP, Microsoft Visual Studio 2010

3. 设计方案

3.1程序功能

贪吃蛇游戏是一个经典小游戏,一条蛇在密闭的围墙内,在围墙内随机出现一个食物,通过按键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到食物,则表示食物被蛇吃掉,时蛇的身体长一节,同时计1分,接着又出现食物,等待被蛇吃掉,如果蛇在移动过程中,撞到墙壁或身体交叉蛇头撞到自己的身体游戏结束。

3.2设计思想

程序关键在于表示蛇的图形及蛇的移动。用一个小矩形块表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用一节表示。移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇。食物的出现与消失也是画矩形块和覆盖矩形块。为了便于理解,定义两个结构体:食物与蛇。

3.3设计总体流程图

2

C#课程设计

3.4设计的具体实现

(1)画板的设计

3

C贪吃蛇课程设计报告

C#课程设计

1.新建一个Windows 应用程序,起名Snake。

2.重命名Form1,改为Splash。

3.从工具栏里拖放一个picturebox到Splash上面,设置属性。

(2) Palette类的实现

画板 Palette类是整个游戏的核心处理类,里面定义了画布的大小,背景色,蛇块列表以及游戏速度,移动方向等属性,另外还提供了timer计时器,用于定时更新蛇块坐标位置,以及如何在画面上画图的函数。

C贪吃蛇课程设计报告

(3) Start函数

Start函数用于开始游戏,这个函数的内部其实就是设定食物,以及触发计时器,代码片段如下

4

C#课程设计

(4) OnBlockTimedEvent函数

OnBlockTimedEvent函数是计时器的执行函数,这个函数用于更新蛇块信息列表,以及检测游戏是否结束等等,代码片段如下

C贪吃蛇课程设计报告

(5) CheckDead函数

checkDead函数用于检测游戏是否结束,具体检查规则如下

C贪吃蛇课程设计报告

(6) Move函数

Move函数用于更新整个蛇块的坐标,我们前面通过将蛇块信息放到ArrayList里来表示贪吃蛇的整个信息,其中根据下标从0到Count-1依次表示各个蛇块的信息。

(7) GetFood函数

GetFood函数用于生成下一个食物,其实就是一个蛇块,生成的规则就是,坐标要在画布范围内,并且食物的坐标不能和贪吃蛇的坐标重合,具体代码如下

C贪吃蛇课程设计报告

5

C#课程设计

通过for循环检查食物坐标是否和贪吃蛇的蛇块列表ArrayList里的蛇块有冲突

(8) PaintPalette函数

PaintPalette函数需要一个参数,也就是绘图句柄,然后在这个画布上画图也就是我们看到的游戏效果

C贪吃蛇课程设计报告

首先用背景色清空画布,然后画食物,其次是通过for循环将贪吃蛇的每个蛇块画在画布上,以此达到游戏效果。

(9) FormMain_KeyDown函数

这个函数用于更改贪吃蛇的移动方向,这里设定了wdsa和上下左右都可以使用,更改移动方向的前提就是新的方向不能和当前方向相反,也即是只能90度拐弯,不能180度拐弯。

C贪吃蛇课程设计报告

6

C#课程设计

(10) pictureBox1_Paint函数

这个事件在pictureBox1需要重新绘制的时候发生,这里面只要简单调用一下让贪吃蛇重新绘制一下游戏就行了

C贪吃蛇课程设计报告

4、程序测试

4.1测试内容与结果

A 选项——新游戏 游戏正常启动

B 选项——新游戏——暂停 游戏暂停,并显示当前得分

C 选项——新游戏——暂停——继续 游戏继续运行

D 选项——新游戏——(暂停——继续)退出游戏 显示当前得分,确认键后退出游戏

E 选项——新游戏,蛇头撞出画布界面 游戏结束,并显示当前得分0 F 选项——新游戏,蛇头吃到食物 游戏继续,得分+1

G 选项——新游戏,蛇头吃到8个食物后,蛇头撞到蛇尾 游戏结束,并显示当前得分8

4.2程序运行效果图

C贪吃蛇课程设计报告

7

C#课程设计

C贪吃蛇课程设计报告

8

C贪吃蛇课程设计报告

C#课程设计

C贪吃蛇课程设计报告

5、实验总结

经过短短两星期的VC#.NET课程设计,让我对C#有了一个更深的了解,以前总认为C#很枯燥,认为那些我们所设计的程序没有什么用处,但现在通过设计贪吃蛇游戏这个程序使我懂得了如何将所学的知识运用于生活当中。虽然在刚开始设计程序时不太明白如何去设计这程序,但当我看过老师的范例以后,有李初步的思路,用C#语言做出这个贪吃蛇程序后,让我深深感受到C#语言的神奇。

在设计这个程序中我主要学会了运用有关C#语言的知识把面向对象的程序

C贪吃蛇课程设计报告

9

C#课程设计

设计思想应用到具体的工作和学习中,加深对类与对象的理解并能够对现实生活中许多具体的事物抽象出类,并掌握继承与派生,基类、虚方法和抽象方法和多态性的概念。

同时也产生李很多关于做程序的启发:

1) 在设计程序之前,务必要对你所设计的题目和内容有一个系统的了解, 知道所设计的题目和内容包含那些资源。

2) 设计程序采用什么编程语言并不是非常重要,关键要有一个清晰的思路

和一个完整的软件流程图,因而,要先把设计原理与思路搞清楚,再把流程图画出来,这样设计起来就简单多了。

3) 在设计程序时,不能妄想一次就将整个程序设计好,“反复修改,不断改 进”是程序设计的必经之路,发现错误也是取得成绩的一种。

4) 要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而 应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便。 参考文献

《Visual Studio C#.NET 2005教程》

《C#入门经典》、《C#高级编程》、《C#程序开发范例宝典》

附录

附录A:部分源程序

1、Main.cs 文件

using System;

using System.Drawing;

using System.Windows.Forms;

namespace Netterpillars {

while ( WinSplash.ShowDialog()==DialogResult.OK) { WinGameField = new GameField(); WinGameField.Show();

10 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 object netterpillarGameEngine = new GameEngine(); WinSplash = new Splash();

C#课程设计

} Application.DoEvents(); //Creates a copy of the background image to allow erasing the sprites GameEngine.BackgroundImage = (Image)WinGameField.PicGameField.Image.Clone(); netterpillarGameEngine.CreateGameField(WinGameField.PicGameField.Handle); } netterpillarGameEngine = null; WinSplash.Dispose(); WinGameOver.Dispose(); while ( !netterpillarGameEngine.GameOver) { } WinGameOver.ShowDialog(); WinGameField.Dispose(); if (!netterpillarGameEngine.Paused) { } Application.DoEvents(); // EXTRA: Force a Frame rate of 10 frames to second on maximum if } MoveComputerCharacters(); netterpillarGameEngine.Render(); LastTick = System.Environment.TickCount; (System.Environment.TickCount-LastTick>=1000/DesiredFrameRate) { public static void MoveComputerCharacters() { //Move the Netterpillars for(int i=0; i<netterpillarGameEngine.NetterpillarNumber; i++) { if (!netterpillarGameEngine.netterPillars[i].IsDead) { // A.I. for the computer-controled Netterpillars if (netterpillarGameEngine.netterPillars[i].IsComputer) { netterpillarGameEngine.netterPillars[i].Direction = objAINetterpillar.ChooseNetterpillarDirection(netterpillarGameEngine.netterPillars[i].Location, netterpillarGameEngine.netterPillars[i].Direction);

} } } } } }

2、NetterPillar.cs文件

using System;

using System.Drawing;

11

C#课程设计

using System.Windows.Forms; namespace Netterpillars {

IsComputer = isComputer; NetterHeadN

? "" = :

=

? "" : public Netterpillar(int x, int y, Sprite.CompassDirections initialDirection, NetterBody = new NetterBody[25+1]; int incX=0, incY=0; bool isComputer) { private CompassDirections direction; public new CompassDirections Direction { } get { } set { } // Only set the direction once, until we receive the direction from // the remote player if (!directionSet) { } direction = value; directionSet = true; return direction; // We can only set the direction once, until the // netterpillar moves, or we can run over our own tail private bool directionSet = false; public bool IsComputer = true; // Defaults to computer-controled netterpillar public bool IsDead = false; // Defaults to alive netterpillar public class Netterpillar : Sprite { private Bitmap NetterHeadN; private Bitmap NetterHeadS; private Bitmap NetterHeadE; private Bitmap NetterHeadW; public NetterBody[] NetterBody; public int NetterBodyLength = 4; Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer "Player")+"NetterHeadN.gif"); NetterHeadS Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer

12

C#课程设计

"Player")+"NetterHeadS.gif");

NetterHeadE

? "" = :

=

? "" : Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer "Player")+"NetterHeadE.gif"); NetterHeadW Load(Application.StartupPath+"\\"+IMAGE_PATH+"\\"+(IsComputer

"Player")+"NetterHeadW.gif");

public void EatAndMove(int x, int y, System.IntPtr winHandle) { // If the NetterBody array is full, allocate more space if (NetterBodyLength == NetterBody.Length) { NetterBody [] tempNetterBody = new NetterBody[NetterBody.Length+25+1]; NetterBody.CopyTo(tempNetterBody, 0); } // Position the Netterpillar on the given point Direction = initialDirection; Location.X = x; Location.Y = y; // Position each of the body parts switch(Direction) { } for(int i=0; i<NetterBodyLength; i++) { } x += incX; y += incY; NetterBody[i].Location.X = x; NetterBody[i].Location.Y = y; case Sprite.CompassDirections.East: incX = -1; break; incY = -1; break; incX = 1; break; incY = 1; break; for(int i=0; i<NetterBodyLength; i++) { } NetterBody[i] = new NetterBody(IsComputer); case Sprite.CompassDirections.South: case Sprite.CompassDirections.West: case Sprite.CompassDirections.North:

13

C#课程设计 it } NetterBody = tempNetterBody; NetterBody[NetterBodyLength] = new NetterBody(IsComputer); NetterBody[NetterBodyLength].Location = NetterBody[NetterBodyLength-1].Location; } // Updates the whole bodys position and then the head position for(int i=NetterBodyLength-1; i>=1; i--) { } NetterBody[0].Location = Location; NetterBody[0].Draw(winHandle); NetterBodyLength++; // Updates the Netterpillar head position Location = new Point(x, y); //Clear the mushroom Erase(winHandle); // Draw the Netterpillar head Draw(winHandle); // Reset the direction controller variable directionSet = false; NetterBody[i].Location = NetterBody[i-1].Location; public void Move(int x, int y, System.IntPtr winHandle) { // Erase the last part of the body NetterBody[NetterBodyLength-1].Erase(winHandle); // Updates the whole bodys position and then the head position for(int i=NetterBodyLength-1; i>=1; i--) { } NetterBody[0].Location = Location; Location = new Point(x, y); // Redraws only the first part of the body and the head NetterBody[0].Draw(winHandle); //We don't need to erase the netterpillar head, since the body will cover NetterBody[i].Location = NetterBody[i-1].Location;

14

C#课程设计

} Draw(winHandle); // Reset the direction controller variable directionSet = 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; i<NetterBodyLength; i++) { NetterBody[i].Draw(winHandle); }

15

相关推荐