c++实训报告.docx
《c++实训报告.docx》由会员分享,可在线阅读,更多相关《c++实训报告.docx(32页珍藏版)》请在冰点文库上搜索。
c++实训报告
实训报告
飞机大战游戏设计与开发
孙业栋
专业名称:
软件工程
班级:
2010级04班
学号:
201001050819
信息科学与工程学院
二零一一年十一月
目录
1.概述3
2.相关技术3
2.1透明贴图.........................................................................3
2.2MFC基础类库3
3.总体设计与详细设计3
3.1系统模块划分4
3.2主要功能模块4
3.3主要类图5
4.编码实现5
5.实训中遇到的主要问题及解决方法21
6.实训体会.........................................................................21
1.概述
这是一款休闲小游戏。
本游戏是我方战机打敌机的游戏,主要为得分。
战机初始生命数是100,可发射导弹;敌机随机无限产生,可发射敌机子弹。
当敌方战机发射子弹击中战机时,生命数就减1;当敌机与战机碰撞时,会爆炸,战机生命数减1,敌被击中便死。
每隔一段时间,敌方的boss机会出现并发射子弹,击落它会会得到很多分。
2.相关技术
2.1透明贴图
绘制透明位图的关键就是创建一个“掩码”位图(maskbitmap),这个“掩码”位图是一个单色位图,它是位图中图像的一个单色剪影。
在MFC中,绘图需要使用设备描述表,透明贴图时需要创建两个内存设备描述表,一个是用于存放位图的设备描述表(imgDC),一个是用于存放“掩码”位图的设备描述表(maskDC)。
在“掩码”位图设备描述表中制作“掩码”位图的方法是先创建一个单色的bitmap,放入掩码设备描述表(maskDC)中,然后使用拷贝粘贴的方式将存放有位图的设备描述表(imgDC)绘制到掩码设备描述表上,这样,掩码设备描述表显示的位图即是“掩码”位图。
在详细介绍实现过程之前先介绍下所使用的画图函数以及函数参数所代表的功能;
整个绘制过程需要使用到BitBlt()函数,关于这个函数,MSDN上的说明是这样的:
这个函数的功能是把源设备上下文中的一个矩形区域中所有像素的颜色比特信息输。
2.2MFC基础类库
用到的主要MFC函数及消息
OnDraw绘制函数
OnTimer定时刷新函数
OnInitialUpdate初始化
OnDestroy销毁
OnEraseBkgnd禁用屏幕刷新,使用双缓冲
SetTimer设置定时器
KillTimer销毁定时器
3.总体设计与详细设计
3.1系统模块划分
有两个主要的部分组成,分别是规则子系统、游戏对象子系统。
系统的总体结构图如下:
3.2主要功能模块
3.2.1规则子系统
该子系统主要是实现飞机大战各项游戏规则。
实现了需求中的游戏规则。
组成结构如下图所示:
这个系统包含1个重要的模块,人工智能,它实现了敌机对战机的攻击以及游戏对象碰撞监测规则,其实实现的是代表计算机方玉玩家进行对战。
✧攻击规则
⏹敌机在战机上方或下方时发射炸弹,炸弹从下至上或从上至下射向战机
✧碰撞规则
⏹导弹或炸弹本身的矩形区域和敌机或战机的矩形区域相交时,表示导弹或炸弹射中了战机或敌机
⏹战机生命值为零,游戏结束。
⏹敌机被击中,战机得分;敌机与战机相撞,两者爆炸,战机不得分。
⏹每得一百分,或者BOSS机死亡,或者游戏结束,会有文字提示。
3.2.2游戏对象子系统
该子系统包含了各个游戏对象的实现,它实现了需求中的部分规则以及游戏特效。
本子系统的组织结构图如下:
✧应用程序对象
●游戏程序的加载
●游戏对象的绘制
●游戏规则的调用
●玩家的键盘事件获取(用GetKeyState函数)
✧游戏对象
●敌机图像加载
●敌机贴图
●位置存储
3.3主要类图
游戏规则子系统
模块名称
功能简述
人工智能
人机对战规则的实现
游戏子系统
模块名称
功能简述
应用程序对象
游戏程序的加载、游戏对象的绘制、游戏规则的调用、玩家的键盘事件获取
战机对象
战机类(Cpalne)
敌机对象
敌机类(enemy)派生出两个敌机类(enup、endown)
导弹对象
导弹类(bomb)
炸弹对象
炸弹类(Zidan)
爆炸对象
爆炸类(explosion)
4.编码实现
//planeView.cpp:
CplaneView类的实现
//
#include"stdafx.h"
#include"plane.h"
#include"planeDoc.h"
#include"planeView.h"
#include"Cplane.h"
#include"ZiDan.h"
#include"explosion.h"
#include"enemy.h"
#include"SetUp.h"
#include"enemydown.h"
#include"enemyup.h"
#include"bomb.h"
#include"boss.h"
#pragmacomment(lib,"winmm.lib")
#include"mmsystem.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#endif
//CplaneView
intj,z;
intENUM=0;
intp=400;
intcount=0,count1=0;
intRan=rand()%2;
IMPLEMENT_DYNCREATE(CplaneView,CView)
BEGIN_MESSAGE_MAP(CplaneView,CView)
//标准打印命令
ON_COMMAND(ID_FILE_PRINT,&CView:
:
OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,&CView:
:
OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,&CView:
:
OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
ON_WM_TIMER()
ON_WM_DESTROY()
ON_COMMAND(ID_32771,&CplaneView:
:
Onchangspeed)
ON_WM_CREATE()
END_MESSAGE_MAP()
//CplaneView构造/析构
CplaneView:
:
CplaneView()
:
ZNUM(0)
BNUM(0)
Pause(true)
{
//m_pMemDC=newCDC();
//m_pMemBitmap=newCBitmap();
//TODO:
在此处添加构造代码intNUM=100;
}
CplaneView:
:
~CplaneView()
{
//deletem_pMemBitmap;
//deletem_pMemDC;
}
BOOLCplaneView:
:
PreCreateWindow(CREATESTRUCT&cs)
{
//TODO:
在此处通过修改
//CREATESTRUCTcs来修改窗口类或样式
returnCView:
:
PreCreateWindow(cs);
}
//CplaneView绘制
voidCplaneView:
:
OnDraw(CDC*pDC)
{
CplaneDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
//pDoc->e1.Drawexplosion(pDC);
//TODO:
在此处为本机数据添加绘制代码
}
//CplaneView打印
BOOLCplaneView:
:
OnPreparePrinting(CPrintInfo*pInfo)
{
//默认准备
returnDoPreparePrinting(pInfo);
}
voidCplaneView:
:
OnBeginPrinting(CDC*/*pDC*/,CPrintInfo*/*pInfo*/)
{
//TODO:
添加额外的打印前进行的初始化过程
}
voidCplaneView:
:
OnEndPrinting(CDC*/*pDC*/,CPrintInfo*/*pInfo*/)
{
//TODO:
添加打印后进行的清理过程
}
//CplaneView诊断
#ifdef_DEBUG
voidCplaneView:
:
AssertValid()const
{
CView:
:
AssertValid();
}
voidCplaneView:
:
Dump(CDumpContext&dc)const
{
CView:
:
Dump(dc);
}
CplaneDoc*CplaneView:
:
GetDocument()const//非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CplaneDoc)));
return(CplaneDoc*)m_pDocument;
}
#endif//_DEBUG
//CplaneView消息处理程序
voidCplaneView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
在此添加消息处理程序代码和/或调用默认值
CplaneDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
pDoc->p1.x=point.x;
pDoc->p1.y=point.y;
//this->Invalidate();
CView:
:
OnLButtonDown(nFlags,point);
}
voidCplaneView:
:
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)
{
//TODO:
在此添加消息处理程序代码和/或调用默认值
CplaneDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
switch(nChar)
{
caseVK_CONTROL:
//暂停
Pause=!
Pause;
if(Pause)//假
{
SetTimer(1,20,NULL);
SetTimer(2,800,NULL);
SetTimer(3,500,NULL);
}
else//真
{
KillTimer
(1);
KillTimer
(2);
KillTimer(3);
}
break;
}
//this->Invalidate();
CView:
:
OnKeyDown(nChar,nRepCnt,nFlags);
}
voidCplaneView:
:
OnInitialUpdate()
{
CplaneDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
pdc=newCClientDC(this);
SetTimer(1,15,0);//方向键、子弹、碰撞
SetTimer(2,800,0);
SetTimer(3,500,0);//敌机生成
SetTimer(4,40000,0);
pDoc->e1.loadimage();
PlaySound(TEXT("kanong.wav"),NULL,SND_FILENAME|SND_ASYNC);
CView:
:
OnInitialUpdate();
//TODO:
在此添加专用代码和/或调用基类*/
}
voidCplaneView:
:
OnTimer(UINT_PTRnIDEvent)
{
//TODO:
在此添加消息处理程序代码和/或调用默认值
CplaneDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)
return;
wchar_tShu[100];
CDCMemDC;
CRectrect;
CFontfont;
GetClientRect(&rect);
//定义一个位图对象
CBitmapMemBitmap;
//建立与屏幕设备描述表(前端缓冲区)兼容的内存设备描述表句柄(后备缓冲区)
MemDC.CreateCompatibleDC(pdc);
//这时还不能绘图,因为没有位图的设备描述表是不能绘图的
//下面建立一个与屏幕设备描述表(或者内存设备描述表)兼容的位图
//MemBitmap.CreateCompatibleBitmap(pdc,rect.Width(),rect.Height());
//将位图选入到内存设备描述表
//只有选入了位图的设备描述表才有地方绘图,画到指定的位图上
MemBitmap.LoadBitmapW(IDB_BITMAP6);
CBitmap*pOldBit=MemDC.SelectObject(&MemBitmap);
//MemDC.FillSolidRect(0,0,rect.Width(),rect.Height(),RGB(0,0,255));
//绘图
if(p<=10)p=400;
MemDC.BitBlt(0,0,rect.right,rect.bottom,&MemDC,0,p--,SRCCOPY);
MemDC.SetBkMode(TRANSPARENT);
MemDC.SetTextColor(RGB(0,222,12));
wsprintf(Shu,L"得分:
%.3d",pDoc->p1.score);
MemDC.TextOutW(10,10,Shu,6);
wsprintf(Shu,L"生命值:
%.3d",pDoc->p1.death);
MemDC.TextOutW(10,40,Shu,7);
wsprintf(Shu,L"BOSS生命值:
%.4d",pDoc->boss1.life);
MemDC.TextOutW(10,70,Shu,12);
if(pDoc->p1.score%100==0&&pDoc->p1.score>0)
{
MemDC.TextOutW(300,300,L"身手不错啊!
!
",7);
}
if(pDoc->p1.score==0)
MemDC.TextOutW(300,300,L"AreYouReady?
GO!
!
",18);
if(pDoc->p1.death>=0)
{pDoc->p1.DrawSelf(&MemDC);}//画战机
else{pDoc->p1.x=200;
pDoc->p1.y=1500;}
for(z=0;z<100;z++)//画敌机子弹
{
pDoc->zdown[z].DrawZiDan(&MemDC);
pDoc->zup[z].DrawZiDan(&MemDC);
}
for(z=0;z<5;z++)//画boss子弹
{
pDoc->z1[z].DrawZiDan(&MemDC);
pDoc->z2[z].DrawZiDan(&MemDC);
pDoc->z3[z].DrawZiDan(&MemDC);
}
for(z=0;z<100;z++)//画战机导弹
{
pDoc->bm1[z].drawbomb(&MemDC);
pDoc->bm2[z].drawbomb(&MemDC);
}
//画敌机
for(j=0;j{
pDoc->enup[j].y-=pDoc->mspeed;
pDoc->endown[j].y+=pDoc->mspeed;
pDoc->endown[j].Drawenemy(&MemDC);
pDoc->enup[j].Drawenemy1(&MemDC);
}
//画BOSS
pDoc->boss1.drawboss(&MemDC);
if(count1%80==0&&count1>1)
{
pDoc->boss1.life=100;
count=1;
}
//定时器
switch(nIDEvent)
{
case1:
if(GetKeyState(VK_UP)<0)
if(pDoc->p1.y>rect.top)pDoc->p1.y-=15;
if(GetKeyState(VK_DOWN)<0)
if(pDoc->p1.yp1.y+=15;
if(GetKeyState(VK_LEFT)<0)
if(pDoc->p1.x>rect.left)pDoc->p1.x-=15;
if(GetKeyState(VK_RIGHT)<0)
if(pDoc->p1.xp1.x+=15;
//战机导弹
if(GetKeyState(70)<0)
{
pDoc->bm1[BNUM].x=pDoc->p1.x+10;pDoc->bm1[BNUM].y=pDoc->p1.y;
pDoc->bm2[BNUM].x=pDoc->p1.x+30;pDoc->bm2[BNUM].y=pDoc->p1.y;
BNUM++;
if(BNUM==99)BNUM=0;
}
//战机导弹发射
for(z=0;z<100;z++)
{
if(pDoc->bm1[z].y>rect.top-20&&pDoc->bm2[z].y>rect.top-20)
{
pDoc->bm1[z].y-=35;
pDoc->bm2[z].y-=35;
}
else
{
pDoc->bm1[z].x=3000;
pDoc->bm2[z].x=3000;
}
}
for(j=0;j{
for(intt=0;t<100;t++)
{
//战机导弹射中敌机
if((pDoc->endown[j].x-10bm1[t].x)&&(pDoc->endown[j].y+35>pDoc->bm1[t].y)&&(pDoc->endown[j].x+35>pDoc->bm1[t].x)&&(pDoc->endown[j].y-20bm1[t].y)
&&(pDoc->endown[j].x-10bm2[t].x)&&(pDoc->endown[j].y+35>pDoc->bm2[t].y)&&(pDoc->endown[j].x+35>pDoc->bm2[t].x)&&(pDoc->endown[j].y-20bm2[t].y))
{
pDoc->e1.x=pDoc->endown[j].x;
pDoc->e1.y=pDoc->endown[j].y;
pDoc->e1.Drawexplosion(&MemDC);
pDoc->endown[j].x=rand()%2500;
pDoc->endown[j].y=rect.top-40;
pDoc->bm1[t].x=3000;
pDoc->bm1[t].y=400;
pDoc->bm2[t].x=3000;
pDoc->bm2[t].y=400;
pDoc->p1.score+=1;
}
if((pDoc->enup[j].x-10bm1[t].x)&&(pDoc->enup[j].y+35>pDoc->bm1[t].y)&&(pDoc->enup[j].x+35>pDoc->bm1[t].x)&&(pDoc->enup[j].y-20bm1[t].y)
&&(pDoc->enup[j].x-10bm2[t].x)&&(pDoc->enup[j].y+35>pDoc->bm2[t].y)&&(pDoc->enup[j].x+35>pDoc->bm2[t].x)&&(pDoc->enup[j].y-20bm2[t].y))
{
pDoc->e1.x=pDoc->enup[j].x;
pDoc->e1.y=pDoc->enup[j].y;
pDoc->e1.Drawexplosion(&MemDC);
pDoc->enup[j].x=rand()%2500;
pDoc->enup[j].y=rect.bottom+40;
pDoc->bm1[t].x=3000;
pDoc->bm1[t].y=400;
pDoc->bm2[t].x=3000;
pDoc->bm2[t].y=400;
pDoc->p1.score+=1;
}
//战机导弹击中敌机子弹
if((pDoc->zdown[j].x-10bm1[t].x)&&(pDoc->zdown[j].y+8>pDoc->bm1[t].y)&&(pDoc->zdown[j].x+8>pDoc->bm1[t].x)&&(pDoc->zdown[j].y-20bm1[t].y)
||(pDoc->zdown[j].x-10bm2[t].x)&&(pDoc->zdown[j].y+8>pDoc->bm2[t].y)&&(pDoc->zdow