飞机大战实训报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

程序设计综合实践
实习报告
学院名称
专业班级
学生姓名
学号
指导教师
山东科技大学
一、实习题目:飞机大战游戏的设计与实现
二、实习时间:18周~ 19周实习地点:
三、实习任务:
1.基本功能要求:飞机大战游戏必须运用透明贴图、按键处理、定时控制、双缓冲技术等技术实现战机(玩家)和敌机(计算机)对战功能
2.扩展功能:在完成基本功能基础上可以增加双人对战、游戏积分制、声音效果、多种子弹类型、客机类型、游戏关卡设计、多种类型敌机、游戏中间结果存贮等功能
四、小组分工说明:自己完成
五、实习成绩
六、指导教师对实习的评语:
指导教师(签章):
2015年月日
目录
1.概述 (4)
1.1实训项目简介 (4)
1.2实训项目功能说明 (4)
2.相关技术 (5)
2.1透明贴图技术 (5)
2.2 获取矩形区域并判断两个矩形区域是否相撞 (5)
2.3鼠标控制我方战机 (5)
2.4 Windows定时器技术 (6)
2.5 CObList链表 (6)
2.6对话框的应用 (7)
2.7双缓冲技术 (7)
3.需求分析 (7)
3.1功能需求分析 (7)
3.2 数据需求分析 . (7)
3.3 行为需求分析 (7)
3.4 其他需求 (7)
4.总体设计与详细设计 (8)
4.1 系统模块划分 (8)
4.2 主要功能模块 (8)
4.2.1系统主要类图 (8)
4.2.2飞机大战游戏设计执行流程图 (8)
4.3 扩展功能设计思路 (9)
4.4 软件结构设计体会 (9)
5.编码实现 (10)
5.1绘制游戏背景位图的程序 (10)
5.2各个游戏对象的绘制 (10)
5.3我方战机位置的动态控制 (12)
5.4各个游戏对象碰撞的实现 (13)
5.5游戏界面输出当前游戏信息 (15)
6.测试情况说明 (17)
6.1主要模块测试情况 (17)
6.2 主要功能测试情况 (18)
7. 实训中遇到的主要问题及解决方法 (19)
8.实训收获与体会 (19)
1. 概述
1.1实训项目简介
本次实训项目是应用MFC编程完成一个界面简洁、运行流畅、操作简单、易于上手的飞机大战。

该飞机大战项目运用的主要技术是MFC编程中的一些函数、链表、贴图技术。

1.2实训项目功能说明
1.2.1基本功能
(1)设定我方战机有速度初值,可通过键盘方向键控制我方战机位置,空格键控制我方战机发射导弹。

(2)游戏界面中敌机出现的位置、敌机导弹的发射是随机的,敌机有不同的速度。

(3)敌机以及敌机发射的导弹,一旦超出游戏界面边界,则删除出界对象。

(4)敌机导弹击中我方战机、我方战机导弹击中敌机、我方战机与敌机碰撞均会产生爆炸效果。

并且产生爆炸效果后,敌机、敌机导弹、我方战机、我方战机导弹消失,我方战机生命值减一,得分加五分。

1.2.2附加功能
(1)为游戏界面添加了背景图片。

(2)为游戏设置积分制,每击落一架敌机或与敌机相撞得分加5分。

(3)敌机从游戏界面上界和下界随机飞出。

(4)为游戏设置关卡制,每得分增加100分自动进入下一关,每进入新的一关,通过减缓我方战机速度来逐渐增加游戏难度。

(5)添加无敌模式,当得分达到1000分后,按“Z”键即可开启无敌模式。

开启无敌模式后,我方战机生命值增加到999,并且被敌方战机击中或与敌方战机相撞生命值不减少,击落敌机分数继续增加。

(6)游戏界面显示当前游戏信息,游戏界面左上角分别显示“我的分数、战机生命值、开启无敌模式还需杀敌的数量、关数”,右上角显示“是否开启了无敌模式”,当达到开启无敌模式的条件后,右上角显示“按Z键开启无敌模式”,开启无敌模式后,右上角变为“无敌模式已开启”,右下角显示开启无敌模式需达到的条件,当每进入新的一关,游
戏界面中心显示“玩的不错,进入第X关”。

(7)增加鼠标左键控制我方战机发射导弹的功能。

(8)当我方战机炸毁后,弹出对话框提示玩家是否重新开始游戏。

2. 相关技术
2.1 透明贴图技术
绘制透明位图的关键就是创建一个“掩码”位图(mask bitmap),这个“掩码”位图是一个单色位图,它是位图中图像的一个单色剪影。

(1)DDB可以用MFC中的CBitmap来表示,而DDB一般储存在资源文件中,在加载时只需通过资源ID号就可以将图形装入。

(2)BOOL CBitmap::LoadBitmap(UINT nIDResource)可以装入指定DDB,但是在绘制时必须借助另一个和当前绘图DC兼容的内存DC来进行。

(3)通过CDC::BitBLT()绘制图形,同时指定光栅操作的类型。

2.2 获取矩形区域并判断两个矩形区域是否相撞
首先,使用CRect定义一个对象,然后使用GetRect(&对象名)函数,获取界面的矩形区域rect.Width() 为矩形区域的宽度,rect.Height()为矩形区域的高度。

使用IntersectRect(&,&))函数来判断两个源矩形是否有重合的部分。

如果有不为空,则返回非零值;否则,返回0。

2.3鼠标控制我方战机
WM_LBUTTONDOWN(鼠标左键被按下)对应的函数为OnLButtonDown (UINT nFlags,CPoint point)
当鼠标左键被按下时,我方战机两翼开始发射导弹。

void CPlaneGameView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CView::OnLButtonDown(nFlags, point);
if( is_Pause == 0)
{
CBomb *BombOne=new CBomb( myplane->GetPoint().x+10,
myplane->GetPoint().y+35,1);
ListBomb.AddTail(BombOne);
CBomb *BombTwo=new CBomb( myplane->GetPoint().x+70,
myplane->GetPoint().y+35,1);
ListBomb.AddTail(BombTwo);
}
}
2.4 Windows定时器技术
Windows定时器是一种输入设备,它周期性地在每经过一个指定的时间间隔后就通知应用程序一次。

程序将时间间隔告诉Windows,然后Windows给您的程序发送周期性发生的WM_TIMER消息以表示时间到了。

本程序中使用多个定时器,分别控制不同的功能。

在MFC 的API函数中使用SetTimer()函数设置定时器,设置系统间隔时间,在OnTimer()函数中实现响应定时器的程序。

2.5 CObList链表
MFC类库中提供了丰富的CObList类的成员函数,在CPlaneGameView.h文件中声明各游戏对象与游戏对象链表:
(1)创建各游戏对象:
//创建各游戏对象
CMyPlane *myplane;
CEnemy *enemy;
CBomb *bomb;
CBall *ball;
CExplosion *explosion;
(2)创建储存各游戏对象的游戏链表:
//创建存储游戏对象的对象链表
CObList ListEnemy;
CObList ListMe;
CObList ListBomb;
CObList ListBall;
CObList ListPeople;
CObList ListExplosion;
2.6对话框的应用
当我方战机炸毁时,弹出是否重新开始游戏的对话框。

对话框的应用过程如下:
(1)资源视图下,添加Dialog对话框。

然后添加使用到的控件,并修改控件的ID。

(2)为对话框添加类,在对话框模式下,点击项目,添加类。

(3)在类视图中,为对话框类添加成员变量(控件变量)。

设置变量的名称、类型、最值等信息。

(4)在资源视图菜单中,选择相应的菜单项,右击添加时间监听程序,设置函数处理程序名称。

(5)在处理程序函数中添加相应的信息。

2.7双缓冲技术
当数据量很大时,绘图可能需要几秒钟甚至更长的时间,而且有时还会出现闪烁现象,为了解决这些问题,可采用双缓冲技术来绘图。

双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

双缓冲实现过程如下:
1、在内存中创建与画布一致的缓冲区
2、在缓冲区画图
3、将缓冲区位图拷贝到当前画布上
4、释放内存缓冲区
3.需求分析
● 3.1功能需求分析
基本功能:键盘控制战机移动、发射导弹,战机、敌机爆炸
拓展功能:游戏界面背景,鼠标控制战机发射导弹,积分制,过关制,对话框弹出,无敌模式
● 3.2 数据需求分析
我的分数、战机生命值、击落敌机数目、关数实时显示。

● 3.3 行为需求分析
键盘方向键控制战机移动,空格键控制战机发射导弹,鼠标左键控制战机发射导弹,键位之间互不冲突,战机移动不卡顿。

● 3.4 其他需求
游戏界面简洁,游戏操作简单易于上手。

4.总体设计与详细设计
4.1 系统模块划分
游戏系统模块
模块名称功能简介
应用程序对象游戏程序的加载、游戏对象的绘制、游戏规则的调用、玩家的键盘
事件获取
我方战机对象战机类
敌机对象敌机类
我方战机导弹对象我方战机导弹类
敌机炸弹对象敌机炸弹类
爆炸对象爆炸类
4.2 主要功能模块
4.2.1系统主要类图
4.2.2飞机大战游戏设计执行流程图
. 除实现最基本的人工智能对战功能之外,还增加人性化的设计,使游戏的可玩性更高。

4.3 扩展功能设计思路
1、为游戏添加背景,是游戏更加美观。

2、为使画面更能实时显示当前游戏信息,为游戏界面添加“我的分数”、“战机生命”、“关数”等实时变化的信息。

3、为使游戏更具可玩性,为游戏添加无敌模式。

4.4 软件结构设计体会
软件结构设计部分是软件工程开发过程的重要部分,设计内容的好坏关系到整个软件的优劣,在这次飞机大战项目开发中,对结构设计中出现的种种问题以及解决方法,加深了对软件结构设计方法的理解,熟悉了对其的应用,从宏观和细节处展示了整个软件的体系结构,使整个软件更具层次感。

5. 编码实现
5.1绘制游戏背景位图的程序
CDC *pDC = GetDC();
//获得矩形区域对象
CRect rect;
GetClientRect(&rect);
//设备环境对象类----CDC类。

CDC cdc;
//内存中承载临时图像的位图
CBitmap bitmap1;
//该函数创建一个与指定设备兼容的内存设备上下文环境(DC)
cdc.CreateCompatibleDC(pDC);
//该函数创建与指定的设备环境相关的设备兼容的位图。

bitmap1.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
//该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。

CBitmap *pOldBit = cdc.SelectObject(&bitmap1);
cdc.FillSolidRect(rect, RGB(0, 0, 0));
//添加背景图片
CBitmap bitmap_BackGround;
bitmap_BackGround.LoadBitmap(IDB_BLACKGROUND);
BITMAP bimap2;//位图图像
bitmap_BackGround.GetBitmap(&bimap2);
CDC cdc_BackGround;//定义一个兼容的DC
cdc_BackGround.CreateCompatibleDC(&cdc);//创建DC
CBitmap*Old = cdc_BackGround.SelectObject(&bitmap_BackGround);
cdc.StretchBlt(0, 0, rect.Width(), rect.Height(), &cdc_BackGround, 0, 0, bimap2.bmWidth, bimap2.bmHeight, SRCCOPY);
5.2各个游戏对象的绘制
if ((GetKeyState(VK_SPACE) < 0))//空格键发射炸弹(后面鼠标左键){
//我方战机炸弹
//我方战机左侧炸弹
CBomb *BombOne = new CBomb(myplane->GetPoint().x + 10,
myplane->GetPoint().y + 35, 1);
ListBomb.AddTail(BombOne);
//我方战机右侧炸弹
CBomb *BombTwo = new CBomb(myplane->GetPoint().x + 70,
myplane->GetPoint().y + 35, 1);
ListBomb.AddTail(BombTwo);
}
//敌方战机,敌方战机炸弹
if(myplane!=NULL&& is_Pause == 0)
{
switch(nIDEvent)
{
case 2://产生敌机
{
int motion1 = 1; //敌方飞机从上面出
CEnemy *enemy1=new CEnemy(motion1);
enemy1->SetSpeed_en((rand()%5 +1)/** pass_Num*/);
ListEnemy.AddTail(enemy1);//产生敌机
int motion2 = -1;//敌方飞机从下面出
CEnemy *enemy2=new CEnemy(motion2);
enemy2->SetSpeed_en((rand()%5 +1)/** pass_Num*/);
ListEnemy.AddTail(enemy2);//产生敌机
}
break;
}
//我方战机炸弹
if( myplane!=NULL&& is_Pause== 0)
{
//战机炸弹位置
POSITION posBomb=NULL,bombTemp=NULL;
posBomb= ListBomb.GetHeadPosition();
while(posBomb!=NULL)
{
bombTemp=posBomb;
bomb=(CBomb *) ListBomb.GetNext(posBomb);
if( bomb->GetPoint().x<rect.left|| bomb->GetPoint().x>rect.right|| bomb->GetPoint().y<rect.top|| bomb->GetPoint().y>rect.bottom)
{
//删除出界的子弹
ListBomb.RemoveAt(bombTemp);
delete bomb;
}
else
bomb->Draw(&cdc,TRUE);
}
}
5.3我方战机位置的动态控制
//控制我方战机
if (myplane != NULL)
{
myplane->Draw(&cdc, TRUE);
}
//键盘控制我方战机
if (GetKeyState(VK_UP) < 0)//战机上移
{
if (myplane->GetPoint().y < rect.top)
myplane->SetPoint(myplane->GetPoint().x, rect.bottom);
else
myplane->SetPoint(myplane->GetPoint().x, (myplane->GetPoint().y - speed));
}//if
if (GetKeyState(VK_DOWN) < 0)//战机下移
{
if (myplane->GetPoint().y>rect.bottom)
myplane->SetPoint(myplane->GetPoint().x, rect.top);
else
myplane->SetPoint(myplane->GetPoint().x, (myplane->GetPoint().y + speed));
}//if
if (GetKeyState(VK_LEFT) < 0)//战机左移
{
if (myplane->GetPoint().x < rect.left)
myplane->SetPoint(rect.right, myplane->GetPoint().y);
else
myplane->SetPoint((myplane->GetPoint().x - speed),
myplane->GetPoint().y);
}//if
if (GetKeyState(VK_RIGHT) < 0)//战机右移
{
if (myplane->GetPoint().x > rect.right)
myplane->SetPoint(rect.left, myplane->GetPoint().y);
else
myplane->SetPoint((myplane->GetPoint().x + speed),
myplane->GetPoint().y);
}//if
if ((GetKeyState(VK_SPACE) < 0))//空格键发射炸弹(后面鼠标左键)
{
//我方战机炸弹
//我方战机左侧炸弹
CBomb *BombOne = new CBomb(myplane->GetPoint().x + 10,
myplane->GetPoint().y + 35, 1);
ListBomb.AddTail(BombOne);
//我方战机右侧炸弹
CBomb *BombTwo = new CBomb(myplane->GetPoint().x + 70,
myplane->GetPoint().y + 35, 1);
ListBomb.AddTail(BombTwo);
}
5.4各个游戏对象碰撞的实现
本飞机大战游戏中的碰撞考虑了飞机子弹打中敌机、敌机炸弹打中战机、战机与敌机相撞、三种情况,根据游戏对象的矩形区域是否有交叉,而确认两者是否相撞,而产生爆炸对象,添加到爆炸链表中。

//如果我方战机炸弹打中敌机
if( myplane!=NULL/*&& is_Pause== 0*/)
{
POSITION explosionPos;
explosionPos = ListExplosion.GetHeadPosition();
while(explosionPos!=NULL)
{
explosion = (CExplosion *) ListExplosion.GetNext(explosionPos);
explosion->Draw(&cdc,TRUE);
}
//炸弹位置,敌机位置
POSITION bombPos,bombTemp,enemyPos,enemyTemp;
for(bombPos= ListBomb.GetHeadPosition();(bombTemp=bombPos)!=NULL;)
{
bomb = (CBomb *) ListBomb.GetNext(bombPos);
//获得战机炸弹的矩形区域
CRect bombRect = bomb->GetRect();
for(enemyPos=
ListEnemy.GetHeadPosition();(enemyTemp=enemyPos)!=NULL;)
{
enemy = (CEnemy *) ListEnemy.GetNext(enemyPos);
//获得敌机的矩形区域
CRect enemyRect = enemy->GetRect();
//判断两个矩形区域是否有交接
CRect tempRect;
if(tempRect.IntersectRect(&bombRect,enemyRect))
{
//将爆炸对象添加到爆炸链表中
CExplosion *explosion=new
CExplosion(( enemy->GetPoint().x+17),( enemy->GetPoint().y+17));
ListExplosion.AddTail(explosion);
//后删除子弹
ListBomb.RemoveAt(bombTemp);
delete bomb;
//删除敌机
ListEnemy.RemoveAt(enemyTemp);
delete enemy;
score_Me+=5;
break;
}
}
}
}
//如果敌机炸弹打中我方战机
if( myplane != NULL/*&& is_Pause== 0*/)
{
POSITION ballPos,ballTemp;
for(ballPos= ListBall.GetHeadPosition();(ballTemp=ballPos)!=NULL;)
{
ball = (CBall *) ListBall.GetNext(ballPos);
//获得敌机炸弹的矩形区域
CRect ballRect = ball->GetRect();
//获得战机的矩形区域
CRect myPlaneRect = myplane->GetRect();
CRect tempRect;
//如果敌机炸弹打中我方战机
if(tempRect.IntersectRect(&ballRect,myPlaneRect))
{
CExplosion *explosion = new CExplosion(( myplane->GetPoint().x + 25) , ( myplane->GetPoint().y + 30));
ListExplosion.AddTail(explosion);
lifeNum_Me-=1;
ListBall.RemoveAt(ballTemp);
delete ball;
if(lifeNum_Me <= 0)
{
//删除战机
delete myplane;
myplane=NULL;
}
break;
}
}
}
5.5游戏界面输出当前游戏信息
游戏界面上显示的信息有:游戏界面左上角分别显示“我的分数、战机生命值、开启无敌模式还需杀敌的数量、关数”,右上角显示“是否开启了无敌模式”,当达到开启无敌模式的条件后,右上角显示“按Z键开启无敌模式”,开启无敌模式后,右上角变为“无敌模式已开启”,右下角显示开启无敌模式需达到的条件,当每进入新的一关,游戏界面中心显示“玩的不错,进入第X关”。

//显示得分和我方战机剩余生命值
if(myplane != NULL&& is_Pause== 0)
{
HFONT font;
font=CreateFont(20,10,0,0,0,0,0,0,0,0,0,10,100,0);
cdc.SelectObject(font);
CString str;
cdc.SetTextColor(RGB(0,255,0));//设置文字颜色
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
str.Format(_T("战机生命:%d"),lifeNum_Me);
cdc.TextOutW(200,5,str);
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
str.Format(_T("我的分数:%d"),score_Me);
cdc.TextOutW(5,5,str);
str.Format(_T("关数:%d"), score_Me/100);
cdc.TextOutW(5, 25, str);
int n = score_Me / 100;
cdc.SetTextColor(RGB(0, 0, 225));//设置文字颜色
str.Format(_T("分数达到1000"));
cdc.TextOutW(1000, 600, str);
str.Format(_T("按Z键可开启无敌模式"));
cdc.TextOutW(1000, 618, str);
cdc.SetTextColor(RGB(0, 255, 0));//设置文字颜色
// enemy->set(n);
//判断无敌模式剩余杀敌数
if (score_Me <= 1000)
{
cdc.SetBkColor(TRANSPARENT);
str.Format(_T("开启无敌模式还需杀敌:%d"), 200 - score_Me / 5);
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
cdc.TextOutW(400, 5, str);
}
else
{
str.Format(_T("开启无敌模式还需杀敌:0"));
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
cdc.TextOutW(400, 5, str);
}
//开启无敌模式
if (score_Me >= 1000 && f == 1)
{
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
str.Format(_T("按“Z”键开启无敌模式"));
cdc.TextOutW(1000, 5, str);
}
if (GetKeyState('Z') < 0)
{
f = 0;
}
if (score_Me >= 1000&&f==0 )
{
cdc.SetTextColor(RGB(255, 0, 0));
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
str.Format(_T("杀敌数超过200,无敌模式开启"));
cdc.TextOutW(1000, 5, str);
lifeNum_Me = 999;
}
//玩的不错,继续努力
if (score_Me >= 100 && (score_Me % 100 == 0 || score_Me % 100 == 5 || score_Me % 100 == 10 || score_Me % 100 == 15 || score_Me % 100 == 20 || score_Me % 100 == 25 || score_Me % 100 == 30))
{
cdc.SetTextColor(RGB(225, 0, 0));
cdc.SetBkMode(TRANSPARENT);//设置文字背景为透明色
str.Format(_T("玩的不错,关数%d,继续努力!"),score_Me/100);
cdc.TextOutW(525,250 , str);
}
}
6.测试情况说明。

6.1主要模块测试情况
模块2、敌机及敌机炸弹模块测试
6.2 主要功能测试情况
功能2、无敌模式测试
功能3、重新开始对话框测试
7. 实训中遇到的主要问题及解决方法
(1)在开发初期,屏幕和战机、敌机一直不停的闪烁。

解决方法:设置双缓冲,在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。

(2)在碰撞处理中,避免游戏对象多次删除
解决方法:删除前先查询是否已被删除,这样就可以避免已删除已不存在的变量被二次删除。

(3)子弹发射速率过快,战机子弹连在一起
解决方法:将将键盘信息处理函数设置在OnTimer函数里,使程序接收按键信息的频率降低,使战机子弹的发射速度更加平滑。

9.实训收获与体会
通过这次实训,我增长了许多知识,学习到了MFC的应用,学习了MFC编程的基本思想,但是对于MFC的理解还是不够透彻,加深了对程序设计的理解,熟悉了对编程思想的应用,并且对面向对象的思想和方法更加熟悉。

对于面向对象的程序设计思想的培养很有好处,它是经典的c++面向对象思想的结构化的体现。

同时我也发现了自己已经学过的知识上面的不足,并且通过实践加深了理解。

我也理解了软件工程产品的生产是怎么实现的,在项目开始前的分析与方案的确定对项目的成败有着至关重要的影响,再就是在软件开发的过程中要及时做好备份,不光是最新的解决方案的备份,历史版本也要留一份,这样在遇到不可逆转错误或者不容易逆转的错误时可以在历史版本的基础上继续开发,而不必把过多的经历浪费在程序代码的恢复上。

在这次实训中,学习了透明贴图,滚动背景,利用定时器处理消息,利用双缓冲解决卡屏等技术,相信这些细节在以后的编程之路上都会用到。

通过这次实训,也让我认识到态度对于工作和学习的重要性。

总之,这次实训给我们带来的收获颇丰。

相关文档
最新文档