面向对象编程技术实验指导教程.docx
《面向对象编程技术实验指导教程.docx》由会员分享,可在线阅读,更多相关《面向对象编程技术实验指导教程.docx(23页珍藏版)》请在冰豆网上搜索。
面向对象编程技术实验指导教程
面向对象编程技术实验
指导教程
郑州轻工业学院
计算机与通信工程学院网络工程系
目录
1实验目的3
2实验题目3
3实验步骤4
3.1需求4
3.2设计5
3.3编码6
3.4测试18
3.5系统升级19
4实验报告20
5实验验收20
6实验成绩20
附录1实验报告格式21
1实验目的
通过开发一款贪吃蛇游戏程序,熟练掌握C#编程语言、和面向对象程序设计方法,独立完成一个游戏程序的开发。
2实验题目
使用C#编程语言,开发一款贪吃蛇游戏,如下图所示。
游戏基本功能描述如下:
1)游戏场地是一片矩形区域的草坪。
2)一条蛇由蛇头和蛇身组成。
3)当游戏开始之后,草坪中出现一颗豆和一条蛇,并且蛇不停地移动,蛇移动的方向与蛇头的方向一致。
4)当蛇移动时,玩家使用“↑”、“↓”、“←”和“→”四个键控制蛇的方向。
5)当蛇头与豆的位置重合时,豆被蛇吃掉,同时在草坪中再生成一颗新的豆,蛇身增加一节。
6)当蛇头碰到草坪四周或蛇身时,蛇立即毙命,游戏结束。
3实验步骤
3.1需求
根据功能描述可知,贪吃蛇游戏的系统结构图如下所示。
定义数据字典如下:
1)草坪(Lawn):
草坪是贪吃蛇游戏的场地。
豆和蛇只能存在于草坪范围之内。
草坪具有大小和颜色等属性。
2)蛇(Snake):
在贪吃蛇游戏中,蛇由若干节组成,其中第一节是蛇头,其余是蛇身。
在游戏过程中,有且仅有一条蛇,并且蛇在不停地移动。
如果蛇吃了豆,则蛇生长一节。
如果蛇头碰到蛇身或离开草坪,则蛇死亡游戏结束。
蛇具有长度、颜色、运动方向、每一节的位置等属性。
3)豆(Bean):
在贪吃蛇游戏中,豆是蛇的食物。
在游戏过程中,有且仅有一颗豆。
如果蛇吃了豆,则重新生成一颗豆。
豆具有位置、大小和颜色等属性。
3.2设计
根据需求分析可知,Snake的每一节都有位置和大小等属性。
而Bean也具有这两个属性。
抽象出二者的共同特征,抽象出一般类Block,用于描述一个块。
Block派生出Bean和SnakeBlock两个类,其中SnakeBlock类用于描述蛇的一节。
为了使游戏的运行更易于控制,定义Game类用于启动、暂停和继续游戏。
根据需求分析可知,Lawn仅包含大小和颜色两个属性。
为了减少类的数量,可将其大小和颜色等属性添加到Game类中。
综上所述,在贪吃蛇游戏中,有Block(块)、Bean(豆)、SankeBlock(节)、Snake(蛇)、Game(游戏)和MainForm(用户接口)六个类。
贪吃蛇游戏的逻辑模型如下图所示。
3.3编码
3.3.1Block(块)类编码
Block是用来构成Bean(豆)和Snake(蛇)的最基本的单位,是Bean和SnakeBlock的基类。
Block类的参考代码如下。
usingSystem;
usingSystem.Drawing;
namespaceHungrySnake
{
classBlock
{
protectedPointorigion;//Block的左上顶点
publicconstintWIDTH=10;//Block的宽度
publicconstintHEIGHT=10;//Block的高度
protectedColorcolor;//Block的颜色
publicBlock()
{
origion=newPoint(0,0);
color=newColor();
}
publicBlock(intx,inty,Color_color)
{
origion=newPoint(x,y);
color=_color;
}
publicPointOrigion
{
get
{
returnorigion;
}
}
publicvoidDisplay(Graphicsg)
{
SolidBrushbrush=newSolidBrush(color);
g.FillRectangle(brush,origion.X,origion.Y,WIDTH,HEIGHT);
Penpen=newPen(Color.Black);
g.DrawRectangle(pen,newRectangle(origion.X,origion.Y,WIDTH-1,HEIGHT-1));
}
publicvoidClear(Graphicsg,ColorbackGroundColor)
{
SolidBrushbrush=newSolidBrush(backGroundColor);
g.FillRectangle(brush,origion.X,origion.Y,WIDTH,HEIGHT);
}
}
}
3.3.2Bean(豆)类编码
Bean表示豆,是由Block派生而来的。
Bean类的参考代码如下。
usingSystem;
usingSystem.Drawing;
namespaceHungrySnake
{
classBean:
Block
{
publicBean(Color_color)
{
origion=newPoint(0,0);
color=_color;
}
publicvoidCreat(Graphicsg,ColorbackGroundColor,intlawnWidth,intlawnHeight,Snakesnake)
{
Clear(g,backGroundColor);
boolbGetAPosition=false;//是否找到生成豆的位置
Randomrandom=newRandom();
while(!
bGetAPosition)
{
origion.X=random.Next(0,lawnWidth-1)/WIDTH*WIDTH;
origion.Y=random.Next(0,lawnHeight-1)/HEIGHT*HEIGHT;
inti;
for(i=0;i{
if(origion==snake.blocks[i].Origion)
break;
}
if(i==snake.Length)
bGetAPosition=true;
}
Display(g);
}
}
}
3.3.3SnakeBlock(节)类编码
SnakeBlock表示蛇的一节,是由Block派生而来的。
SnakeBlock类的参考代码如下:
usingSystem;
usingSystem.Drawing;
namespaceHungrySnake
{
classSnakeBlock:
Block
{
privateboolisHead;
publicboolIsHead
{
get
{
returnisHead;
}
}
publicSnakeBlock(intx,inty,Color_color,bool_isHead)
{
origion=newPoint(x,y);
color=_color;
isHead=_isHead;
}
publicvoidChangeHeadToBody()
{
if(isHead)
isHead=false;
}
publicvoidDisplay(Graphicsg,Directiondirection)
{
base.Display(g);
if(isHead)
{
//绘制蛇眼
SolidBrushbrush=newSolidBrush(Color.Brown);
switch(direction)
{
caseDirection.Up:
caseDirection.Down:
g.FillRectangle(brush,origion.X+WIDTH/4,origion.Y+HEIGHT/2,2,2);
g.FillRectangle(brush,origion.X+WIDTH/4*3,origion.Y+HEIGHT/2,2,2);
break;
caseDirection.Left:
caseDirection.Right:
g.FillRectangle(brush,origion.X+WIDTH/2,origion.Y+HEIGHT/4,2,2);
g.FillRectangle(brush,origion.X+WIDTH/2,origion.Y+HEIGHT/4*3,2,2);
break;
}
}
}
}
}
3.3.4Snake(蛇)类编码
Snake表示蛇。
Snake类的参考代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Drawing;
namespaceHungrySnake
{
publicenumDirection
{
Up,
Down,
Left,
Right
};
classSnake
{
privateintlength;
publicDirectiondirection;
privateColorcolor;
publicListblocks;
privateconstintINIT_LENGTH=3;
publicintLength
{
get
{
returnlength;
}
}
publicSnake(Color_color,Direction_direction)
{
direction=_direction;
color=_color;
blocks=newList();
}
publicvoidCreat(Graphicsg,ColorbackGroundColor,intlawnWidth,intlawnHeight)
{
Clear(g,backGroundColor);
blocks.Clear();
length=INIT_LENGTH;
intx;
inty;
Randomrandom=newRandom();
x=random.Next(lawnWidth/4,lawnWidth/4*3)/Block.WIDTH*Block.WIDTH;
y=random.Next(lawnHeight/4-1,lawnHeight/4*3)/Block.HEIGHT*Block.HEIGHT;
blocks.Add(newSnakeBlock(x,y,color,true));
switch(direction)
{
caseDirection.Up:
for(inti=1;i{
blocks.Add(newSnakeBlock(x,y+Block.HEIGHT*i,color,false));
}
break;
caseDirection.Down:
for(inti=1;i{
blocks.Add(newSnakeBlock(x,y-Block.HEIGHT*i,color,false));
}
break;
caseDirection.Left:
for(inti=1;i{
blocks.Add(newSnakeBlock(x+Block.WIDTH*i,y,color,false));
}
break;
caseDirection.Right:
for(inti=1;i{
blocks.Add(newSnakeBlock(x-Block.WIDTH*i,y,color,false));
}
break;
}
Display(g);
}
publicvoidGrow()
{
intx=2*blocks[blocks.Count-1].Origion.X-blocks[blocks.Count-2].Origion.X;
inty=2*blocks[blocks.Count-1].Origion.Y-blocks[blocks.Count-2].Origion.Y;
blocks.Insert(length,newSnakeBlock(x,y,color,false));
length++;
}
publicvoidMove()
{
intx=0;
inty=0;
blocks[0].ChangeHeadToBody();
switch(direction)
{
caseDirection.Up:
x=blocks[0].Origion.X;
y=blocks[0].Origion.Y-Block.HEIGHT;
break;
caseDirection.Down:
x=blocks[0].Origion.X;
y=blocks[0].Origion.Y+Block.HEIGHT;
break;
caseDirection.Left:
x=blocks[0].Origion.X-Block.WIDTH;
y=blocks[0].Origion.Y;
break;
caseDirection.Right:
x=blocks[0].Origion.X+Block.WIDTH;
y=blocks[0].Origion.Y;
break;
}
blocks.Insert(0,newSnakeBlock(x,y,color,true));
blocks.RemoveAt(blocks.Count-1);
}
publicvoidDisplay(Graphicsg)
{
for(inti=0;i{
blocks[i].Display(g,direction);
}
}
publicvoidClear(Graphicsg,ColorbackGroundColor)
{
for(inti=0;i{
blocks[i].Clear(g,backGroundColor);
}
}
publicboolCanEatBean(Beanbean)
{
if(blocks[0].Origion==bean.Origion)
returntrue;
else
returnfalse;
}
publicvoidEatBean(Beanbean,Graphicsg,ColorbackGroundColor,intlawnWidth,intlawnHeight)
{
bean.Clear(g,backGroundColor);
Grow();
bean.Creat(g,backGroundColor,lawnWidth,lawnHeight,this);
}
publicboolIsAlive(intlawnWidth,intlawnHeight)
{
if(blocks[0].Origion.X<0)
returnfalse;
if(blocks[0].Origion.Y<0)
returnfalse;
if(blocks[0].Origion.X+Block.WIDTH>lawnWidth)
returnfalse;
if(blocks[0].Origion.Y+Block.HEIGHT>lawnHeight)
returnfalse;
for(inti=3;i{
if(blocks[0].Origion==blocks[i].Origion)
returnfalse;
}
returntrue;
}
}
}
3.3.5Game(游戏)类设计
Game控制游戏的运行,负责在游戏开始时生成Bean和Snake,以及负责在游戏运行中Snake的移动、Snake的生长、Bean的重生,并随时检测Snake的生死状态。
Game类的参考代码如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Drawing;
namespaceHungrySnake
{
classGame
{
publicSnakesnake;
publicBeanbean;
publicboolisSnakeAlive;
publicintlawnWidth;
publicintlawnHeight;
publicGame(int_lawnWidth,int_lawnHeight)
{
Randomrandom=newRandom();
intx=random.Next(0,_lawnWidth-1)/Block.WIDTH*Block.WIDTH;
inty=random.Next(0,_lawnHeight-1)/Block.HEIGHT*Block.HEIGHT;
Directiondirection=(Direction)random.Next(1,4);
snake=newSnake(Color.YellowGreen,direction);
bean=newBean(Color.Pink);
isSnakeAlive=false;
lawnWidth=_lawnWidth;
lawnHeight=_lawnHeight;
}
publicvoidBegin(Graphicsg,ColorbackGroundColor,intlawnWidth,intlawnHeight)
{
isSnakeAlive=true;
snake.Creat(g,backGroundColor,lawnWidth,lawnHeight);
bean.Creat(g,backGroundColor,lawnWidth,lawnHeight,snake);
}
publicvoidOnTime(Graphicsg,ColorbackGroundColor,intlawnWidth,intlawnHeight)
{
if(isSnakeAlive)
{
snake.Clear(g,backGroundColor);
snake.Move();
snake.Display(g);
bean.Display(g);
if(snake.CanEatBean(bean))
{
bean.Clear(g,backGroundColor);
snake.EatBean(bean,g,backGroundColor,lawnWidth,lawnHeight);
bean.Display(g);
}
if(!
snake.IsAlive(lawnWidth,lawnHeight))
isSnakeAlive=false;
}
}
}
}
3.3.6MainForm(主界面)类设计
MainForm可通过继承System.Windows.Forms.Form实现,通过向MainForm中添加控件及设置控件的属性系统会自动向MainForm类中添加相应的对象字段,如本程序的menuStrip1和timer1等。
3.3.6.1添加属性
添加属性game,来控制游戏的开始和运行,参考代码如下:
privateGamegame;
3.3.6.2修改构造函数
在构造函数的最后对属性game进行实例化,参考代码如下:
game=newGame(lawn.Width,lawn.Height);
3.3.6.3Panel容器
Panel容器作为游戏运行的场地。
Snake和Bean都在Panel容器中绘制。
Panel容器的添加步骤如下:
●在MainForm中添加一个Panel容器
。
●拖动Panel容器的大小才,使其充满整个窗体。
●修改Panel容器的属性Name=lawn。
●修改Panel容器的属性BackColor=Green。
3.3.6.4Timer组件
Timer组件用于在用户定义的时间间隔引发事件。
Timer组件的添加步骤如下:
●在MainForm中添加一个Timer组件
。
●修改Timer组件的属性Enalbed=false。
●修改Timer组件的属性Interval=100。
●双击
,生成Tick事件。
Tick事件的参考代码如下:
if(game.isSnakeAlive)
{
Graphicsg;
g=lawn.CreateGraphics();
game.OnTime(g,lawn.BackColor,lawn.Width,lawn.Height);
if(!
game.isSnakeAlive)
{
MessageBox.Show("GameOver!
");
}
}
3.3.6.5MenuStrip菜单
MenuStrip菜单用于提供用户可以使用的功能。
MenuStrip菜单的添加步