第7章 贪吃蛇游戏.docx
- 文档编号:9558965
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:85
- 大小:559.55KB
第7章 贪吃蛇游戏.docx
《第7章 贪吃蛇游戏.docx》由会员分享,可在线阅读,更多相关《第7章 贪吃蛇游戏.docx(85页珍藏版)》请在冰豆网上搜索。
第7章贪吃蛇游戏
第七章贪吃蛇游戏
本章介绍贪吃蛇游戏设计及实现过程。
通过开发此游戏软件,使读者学会使用C#中类、对象、方法和构造函数来编写程序;能够用GDI+Graphics进行比较简单的图形绘制;能够学会使用类开发比较复杂的程序的方法和过程。
7.1工作目标
终极目标:
用类和GDI+完成一个如下的贪吃蛇游戏软件。
贪吃蛇软件的主窗体,启动界面如图7.1所示。
图7.1贪吃蛇游戏主界面
自定义速度界面如图7.2所示。
图7.2自定义速度界面
促成目标:
1.完成贪吃蛇游戏Bean类设计;
2.完成贪吃蛇游戏Block类设计;
3.完成贪吃蛇游戏Snake类设计;
4.完成贪吃蛇游戏Floor类设计;
5.完成贪吃蛇游戏Form1类设计(界面);
6.完成贪吃蛇游戏窗体菜单设计;
7.完成贪吃蛇游戏键盘操作处理;
8.完成贪吃蛇游戏程序自动运行。
7.2工作任务
贪吃蛇游戏项目包括一个界面(Start类),四个主类:
Floor类、Snake类、Block类和Bean类,另外还有两个附加类:
Speed类和PubClass类。
具体工作任务分解如下:
工作任务一:
项目总体设计;
工作任务二:
豆类(Bean)设计;
工作任务三:
块类(Block)设计;
工作任务四:
蛇类(Snake)设计;
工作任务五:
场地类(Floor)设计;
工作任务六:
公共类(PubClass)设计;
工作任务七:
速度类(Speed)设计;
工作任务八:
界面(Start)类设计。
7.3知识准备—类、对象、字段、属性和方法
在贪吃蛇项目中,包括七个类,所以类是本项目中最基本的内容,如果没有类的知识,就无法完成此项目,下面我们首先了解有关类的知识。
7.3.1类的基本概念
对象充满着整个世界,举例如表7.1所示。
表7.1对象和类
对象(实体)
(分)类
男人、女人、高人、矮人、胖人、瘦人
人
狗、猫、兔、鸡、狼
动物
台式电脑、笔记本电脑、服务器
电脑
类表示对现实生活中一类具有共同特征的事物的抽象,对象是具体的类,类和对象是面向对象编程的基础。
类有其特征数据:
用字段表示,即以前我们说的变量(只是名字不同而已)。
如人有年龄、名字和身高等;动物有毛的颜色、脚的数量和跑的速度等;电脑有CPU型号、CPU品牌、内存容量等。
类有其行为(即能干、会干的事情):
用方法表示。
如人都能走路、干活等;动物也能跑、找食等;电脑能帮助我们处理事务、计算表达式的值。
类的字段和方法都叫类的成员。
类是对象的模板,我们定义类的目的是为了描述具体的对象。
下面我们举例给予说明。
1.实例:
设计汽车类(Car)
汽车是一个类,具体的汽车是它的一个实例或叫对象。
usingSystem;
classCar//定义小汽车类
{
privateintwheels;//私有字段:
轮子个数
privatestringtrademark;//私有成员:
汽车牌号
privatefloatmaxspeed;//公有字段:
汽车的运行速度
publicvoidStart()//公共方法:
启动汽车
{
Console.WriteLine(trademark+“汽车已启动!
”);
}
publicvoidStop()//公共方法:
汽车停下
{
Console.WriteLine(trademark+“汽车已停止运行”);
}
publicstaticvoidMain()
{
CarmyCar;//创建对象
myCar=newCar();//实例化对象
myCar.trademark=”宝马”;//给字段赋值
myCar.Start();//调用Start方法
myCar.Stop();//调用Stop方法
}
}
上程序的运行结果如图7.3所示。
图7.3汽车类实例运行结果
2.程序解读
⑴类定义
类的定义有一个基本的框架,所有类定义时都要遵循这个框架结构。
class类名
{
类体(类成员)
}
如上例中的Car类。
⑵类成员的访问属性private和public
private(私有)成员只能在定义它的类中被访问,在定义它的类外不能被访问。
public(公共)成员既可以在定义它的类中被访问,也在定义它的类外被访问。
如:
privatestringtrademark;//私有成员:
汽车牌号
publicvoidStart()//公共方法:
启动汽车
注意:
private是默认的。
⑶字段
类中的字段实际上是变量,因此字段的定义与变量定义相同,形式如下:
数据的访问说明符数据类型字段名
小汽车有几个特征数据,汽车的车轮数目、汽车的牌号和汽车能达到的最快速度。
定义如下:
privateintwheels;//私有字段:
轮子个数
privatestringtrademark;//私有成员:
汽车牌号
privatefloatmaxspeed;//公有字段:
汽车的运行速度
⑷方法
小汽车能启动也能停下来,所以分别用Start方法和Stop方法模汽车的起动和停止。
方法的定义见前面第六章。
如:
publicvoidStop()//公共方法:
汽车停下
{
Console.WriteLine(trademark+“汽车已停止运行”);
}
⑸创建对象
定义了类后一般还不能用(特殊情况可以直接用),它只是创建了对象的模板或者说是定义了新的类型,还必须创建类的变量即类的对象。
创建类的对象分两步:
①声明对象
类名对象名;
如:
CarmyCar;
②对象实例化
定义对象后,必须使用new运算符对其实例化(初始化),然后才能使用该对象。
对象名=new类名();
如:
myCar=newCar();
由类创建了对象后,每一个对象都有了类中的所有非静态成员,即对象myCar具有了wheels、trademark、maxspeed字段和Start和Stop方法。
上面创建类对象的两步可以合并成一步:
类名对象名=newCar();
如:
CarmyCar=newCar();
⑹类成员的访问
在类的作用域内即在类的内部,成员可以由类的所有方法直接访问,并可用它的名字进行引用。
在类的作用域外即在类的外部,对象成员的存取必须通过该类或该类的对象和点操作符(类成员存取操作符)来存取。
对象的成员存取方式如下:
对象.成员名
如:
myCar.trademark=”宝马”;//给字段赋值
stringtr=myCar.trademark;//读取字段的值
myCar.Start();//调用Start方法
myCar.Stop();//调用Stop方法
7.3.2属性
在上述实例中,Main方法被放在了Car类中,所以可以访问所有的字段。
一般我们不把Main方法放在具体的类中,要单独设计一个类来放Main方法,这样的话,上程序要设计成如下:
UsingSystem;
ClassCar//定义小汽车类
{
privateintwheels;//私有字段:
轮子个数
privatestringtrademark;//私有成员:
汽车牌号
privatefloatmaxspeed;//公有字段:
汽车的运行速度
publicvoidStart()//公共方法:
启动汽车
{
Console.WriteLine(trademark+“汽车已启动!
”);
}
publicvoidStop()//公共方法:
汽车停下
{
Console.WriteLine(trademark+“汽车已停止运行”);
}
}
publicclasstest
{
publicstaticvoidMain()
{
CarmyCar;//创建对象
myCar=newCar();//实例化对象
myCar.trademark=”宝马”;//给字段赋值
myCar.Start();//调用Start方法
myCar.Stop();//调用Stop方法
}
}
运行上程序结果如图7.4所示。
图7.4汽车类实例运行界面
上例不可运行,出现了编译错误“不可访问”Car.trademark”,因为它受保护级别限制”。
面向对象程序设计的特性之一是隐藏数据,从而避免无意的错误操作,保证类的完整性。
所以,在类中一般的字段都设计成private的,它也是默认访问权限。
有时需要在类外访问私有字段,面向对象的程序设计通过公共属性来完成这一任务。
上例修改如下:
usingSystem;
classCar//定义小汽车类
{
privateintwheels;//私有字段:
轮子个数
privatestringtrademark;//私有成员:
汽车牌号
privatefloatmaxspeed;//公有字段:
汽车的运行速度
publicintWheels//访问wheels的属性
{
get
{
returnwheels;
}
set
{
wheels=value;
}
}
publicstringTrademark//访问trademark的属性
{
get
{
returntrademark;
}
set
{
trademark=value;
}
}
publicfloatMaxspeed//访问maxspeed的属性
{
get
{
returnmaxspeed;
}
set
{
maxspeed=value;
}
}
publicstringcar_message()//输出汽车的信息
{
return"汽车有"+wheels+"个轮子,最大速度为"+maxspeed;
}
publicvoidStart()//公共方法:
启动汽车
{
Console.WriteLine(trademark+"汽车已启动!
");
}
publicvoidStop()//公共方法:
汽车停下
{
Console.WriteLine(trademark+"汽车已停止运行");
}
}
publicclasstest
{
publicstaticvoidMain()
{
CarmyCar;//创建对象
myCar=newCar();//实例化对象
myCar.Wheels=4;
myCar.Maxspeed=230;
Console.WriteLine(myCar.car_message());
myCar.Trademark="宝马";//给字段赋值
myCar.Start();//调用Start方法
myCar.Stop();//调用Stop方法
}
}
运行结果为如图7.5所示。
图7.5改进的汽车类实例运行结果
1.属性
属性主要是用来访问字段的,它有访问器。
这些访问器用来读取或写入字段值,也可以对字段和属性进行计算,然后将计算结果给相应的字段。
属性也需要声明,格式如下:
类型属性名{访问器声明}
属性的访问器:
get访问器
set访问器
1)get访问器
通过get访问器读取字段值。
get访问器与无参数的方法结构相似,它必须返回一个属性类型的值。
2)set访问器
通过set访问器给字段赋值。
set访问器与具有单个属性类型值参数和返回void的方法结构相似,这个属性类型值参数是它隐含的名为value的参数。
在set访问器中最简单的是把value值赋给字段。
如:
privateintwheels;//私有字段:
轮子个数
publicintWheels//访问wheels的属性
{
get
{
returnwheels;
}
set
{
wheels=value;
}
}
根据类中属性的实际需要,把属性分成下面几种:
1)读写属性:
包括get和set两个访问器,既能读取属性值,也能向属性写入。
2)只读属性:
只包括get访问器,即只能读取属性值。
3)只写属性:
只包括set访问器,即只能向属性写入。
7.3.3实例构造函数
上例中,在Main方法中有一语句myCar=newCar();实例化对象,现在把这句屏蔽掉,再运行程序,结果如图7.6所示。
图7.6去掉实例化对象的运行结果
按“否(N)”按钮,结果如图7.7所示。
图7.7按“否(N)”按钮后的运行结果
出现了错误信息:
“使用了未赋值的局部变量‘myCar’”,即未对建立的对象进行实例化,语句myCar=newCar();是对类的对象进行实例化的,在类中没有发现对Car()的说明和定义,它是什么呢?
它是类的默认构造函数。
1.构造函数
构造函数是与类同名的特殊方法成员。
它是实现初始化类实例所必须操作的成员。
在类中声明构造函数时,必须指定标识符和构造函数体且标识符必须命名为声明构造函数的类名。
即:
类名称(可选形参表)
{
方法体
}
2.默认构造函数
在C#中,如果类不包括任何实例构造函数声明,则自动提供一个默认的无参数实例构造函数。
如:
上例中语句myCar=newCar();中的Car(),它是默认的构造函数,形式如下:
publicCar()
{}
并使用默认值初始化对象字段。
默认:
数值类型为0,bool为false,引用为null
⒊实例构造函数重载
定义:
当类定义中含有两个以上其参数个数或类型或种类不同的实例构造函数时,称为实例构造函数重载。
上例修改如下:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Windows.Forms;
namespaceProject1
{
classCar//定义小汽车类
{
privatestringtrademark;//私有成员:
汽车牌号
privateintwheels;//私有字段:
轮子个数
privatefloatmaxspeed;//私有字段:
汽车的运行速度
publicCar()//空构造函数
{}
publicCar(stringtr,intwh,floatmas)//带参数的构造函数
{
trademark=tr;
wheels=wh;
maxspeed=mas;
}
publicintWheels//访问wheels的属性
{
get
{
returnwheels;
}
set
{
wheels=value;
}
}
publicstringTrademark//访问trademark的属性
{
get
{
returntrademark;
}
set
{
trademark=value;
}
}
publicfloatMaxspeed//访问maxspeed的属性
{
get
{
returnmaxspeed;
}
set
{
maxspeed=value;
}
}
publicstringcar_message()//输出汽车的信息
{
returnTrademark+"汽车有"+wheels+"个轮子,最大速度为"+maxspeed;
}
publicvoidStart()//公共方法:
启动汽车
{
Console.WriteLine(trademark+"汽车已启动!
");
}
publicvoidStop()//公共方法:
汽车停下
{
Console.WriteLine(trademark+"汽车已停止运行");
}
}
publicclasstest
{
publicstaticvoidMain()
{
stringoutput;
CarmyCar1;//创建对象
myCar1=newCar();//实例化对象
myCar1.Wheels=4;
myCar1.Maxspeed=230;
myCar1.Trademark="宝马";//给字段赋值
output=myCar1.car_message();
output="使用默认构造函数:
"+output;
Console.WriteLine(output);
myCar1.Start();//调用Start方法
myCar1.Stop();//调用Stop方法
CarmyCar2;//创建对象
myCar2=newCar("红旗",4,180);//实例化对象
output=myCar2.car_message();
output="使用创建构造函数:
"+output;
Console.WriteLine(output);
myCar2.Start();//调用Start方法
myCar2.Stop();//调用Stop方法
}
}
}
程序执行结果如图7.8所示。
图7.8构造函数重载实例的运行结果
⒋程序解读
1)程序中两种构造函数比较
程序中添加了两个类的构造函数,一个是空构造函数;一个是带参数的构造函数。
⑴空构造函数
publicCar()//空构造函数
{}
用此构造函数创建的类对象,是没有具体值的对象,只是把对象字段设置为默认值:
数值类型为0,bool类型为false,引用类型为null。
注意:
创建了带参数的构造函数后,要用空构造函数实例化对象,必须创建此空构造函数,否则出现编译错误。
⑵带参数的构造函数
publicCar(stringtr,intwh,floatmas)//带参数的构造函数
{
trademark=tr;
wheels=wh;
maxspeed=mas;
}
用此构造函数创建类对象,要传递三个参数,在函数体中依次初始化三个字段,这样用此构造函数创建的对象就是具体的对象了。
2)程序中两种实例化对象比较
⑴用空构造函数实例化对象
由于用此创建的对象不是具体的,还得对字段赋值后才能使用。
myCar1=newCar();//实例化对象
myCar1.Wheels=4;
myCar1.Maxspeed=230;
myCar1.Trademark="宝马";//给字段赋值
output=myCar1.car_message();
⑵用带参数的构造函数实例化对象
由于用此创建的对象是具体对象,所以可以直接使用。
myCar2=newCar("红旗",4,180);//实例化对象
output=myCar2.car_message();
7.4工作任务一:
总体设计
7.4.1项目功能描述
⒈正常运行
一条蛇在密闭的围墙内朝一定的方向移动,在围墙内随机出现一个豆,通过操作键盘上的四个光标键控制蛇向上下左右四个方向移动,蛇头撞到豆,则豆被蛇吃掉,这时蛇的身体长一节,同是按不同的等级进行加分,接着又在场地内随机出现一个豆,等待被蛇吃掉,在蛇移动过程中,蛇头撞到场地的墙壁或蛇头撞到自己的身体时,游戏结束。
⒉重新开始游戏
不管什么时候都可以通过“重新开始”子菜单使游戏重新开始。
⒊暂停和继续游戏
在程序正常运行过程中,可以通过“暂停”子菜单使游戏暂停,同时子菜单变成“继续”子菜单;要想继续运行游戏,通过“继续”子菜单使游戏继续,同时子菜单也变成了“暂停”子菜单。
⒋设置游戏级别
本游戏设置了多个级别,从第一关到第五关,难度逐渐增大,蛇的移动速度越快;还有自定义速度。
7.4.2.主窗体布局
项目的主窗体布局如图7.9所示。
图7.9主窗体布局
1.窗体布局说明
窗体布局说明如表7.2所示。
表7.2窗体布局说明
编号
描述
1
菜单,包括了游戏中的所有操作
2
得分区,显示游戏中的等级和分数
3
场地,由Floor类对象实现
4
蛇,由Snake类对象实现
5
豆,由Bean类对象实现
从上面可知,本游戏程序整个窗体的布局和一般windows应用程序非常类似,可以说是一个典型的windows应用程序界面
2.程序处理流程
程序处理总流程图如图7.10所示。
图7.10贪吃蛇总体流程
7.4.3项目的总体结构
在整个项目中,Start类是顶层类,它主要调用Floor类来显示场地,另外还要使用Speed类和PubClass类;Floor类调用Snake类和Bean类在场地上显示蛇和豆;Snake类调用Block类来组成蛇。
项目的总体结构如图7.10所示。
图7.10总体结构设计
7.5工作任务二:
Bean类
7.5.1豆(Bean)类分析
1.Bean类的分析
在此游戏中,首先会在场地的特定位置出现一个豆,豆要不断被蛇吃掉,当豆被吃掉后,原豆消失,又在新的位置出现新的豆。
这些豆都是由豆(Bean)类创建的对象。
下面我们来设计豆类:
1)豆类的字段
//豆的显示位置
privatePointorigin;
2)属性:
//位置属性
publicPointOrigin
3)方法:
//绘制豆
publicvoidDisplay(Graphicsg)
//消除豆
publicvoidUnDisplay(Graphicsg)
豆类的类图如图7.11所示。
图7.11豆类的类图
7.5.2豆(Bean)类实现
1.字段和属性
注意字段和属性的类别是Point结构类型的。
知识点介绍:
Point结构
Point结构表示在二维平面中定义点的整数X和Y坐标的有序对。
命名空间:
System.Drawing
程序集:
System.Drawing(在system.drawing.dll中)
Point结构有两个属性:
X—获取或设置此Point的X坐标;Y—获取或设置此Point的Y坐标。
C#中的结构使用与类的使用相似,C#中结构的使用简单介绍如下:
⑴定义结构变量及实例化
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第7章 贪吃蛇游戏 贪吃 游戏