飞机大战游戏设计与开发
专业名称:__________ ____________
班 级:__________________
学 号:___________________
信息科学与工程学院
二零一一年十一月
1. 概述【一级标题,黑体,四号,加粗,顶头】
(介绍所做的项目,要实现的主要功能)【正文,五号,宋体,首行缩进2字符】
此次实训主要是要做一个飞机大战的游戏,其需要实现的功能为:实现游戏对象的爆炸特效、声音特效、文字提示功能和界面背景特效,其主要是遵循一定的游戏规则进行游戏。
游戏中的主要角色可分为如下几个基本部分:战机、敌机、战机的导弹、敌机的子弹。其主要遵循的游戏规则为:战机数量为1;由玩家通过键盘控制(方向键控制位置、CTRL键发射导弹)战机;导弹释放存在间隔,有一定的运行速度;导弹遇到敌机发生爆炸,敌机被炸毁,导弹消失,玩家得分;由计算机控制敌机自动向战机发动攻击;敌机数量随机,计算机生成敌机时随机选择类别;敌机从游戏区域的上下两端进入,左右位置随机;敌机行驶期间,不左右移动,不反向移动;当敌机到达战机下方时发射对战机进行攻击;运行线路为直线,方向为从下至上,或从下至上,不可左右移动。纵向由发射位置起至游戏区域结束;遇到战机时发生爆炸,战机被炸毁,消失,游戏结束;运行时有速度。
2. 相关技术
此次实训的飞机大战游戏其中的技术主要就是一些函数、内存释放和双缓冲技术。
2.1 透明贴图函数(技术一的名称)
此次实训中用于贴图的函数:
LoadImage(CImageList& imageList,UINT bmpID,COLORREF crMask,int cx,int cy,int nInitial) //此函数主要用于将图片放入图像链表imageList中。
img_Bomb.Draw(pDC,0,m_m_ptPos,ILD_TRANSPARENT) //此函数主要是讲img_Bomb1链表中的图像显示在pDC这个句柄中。ILD_TRANSPARENT表示是透明贴图。
其中主要就是CImageList图像列表。它是相同大小图像的一个集合,每个集合中均以0为图像的索引序号基数,图像列表通常由大图标或位图构成,其中包含透明位图模式。可以利用WINDOWS32位应用程序接口函数API来绘制、建立和删除图像,并能实现增加、删除、替换和拖动图像等操作。
2.2 CObList链表(技术二的名称)
CObList m_ObjListball; //主要是定义一个CObList类的一个链表对象用于存储所有的此种相关的对象,易于后续的添加删除和提取数据。
POSITION posball=NULL,posball_t=NULL; //定义指针
posball=pDoc->m_ObjListball.GetHeadPosition();//指针读取头结点
pDoc->pball= (Cball *)pDoc->m_ObjListball.GetNext(posball); //指针读取下一个结点
2.3获取矩形区域函数
CRect rc; //定义
GetClientRect(&rc); //获取其矩形区域 获取结果课为:rc.Width() //矩形区域的宽度rc.Height() //矩形区域的高度
CRect tmpRect;
tmpRect.IntersectRect(&bRect,eRect))//判断两个矩形是否有交接
2.4添加爆炸效果函数
PlaySound((LPCTSTR)IDR_WAVE1,AfxGetInstanceHandle(),SND_RESOURCE|SND_ASYNC); //此函数用于将ID为IDR_WAVE1的音频在执行此语句时进行播放。
2.5弹出对话框函数
if(AfxMessageBox(L"是否进入下一关?",MB_YESNO)==6){}
//此函数主要是弹出对话框供用户进行选择,当用户点击确定按钮时执行此函数的{}内的语句进行继续运行。
2.6字体的个性化输出函数
CString s;
dcMem.SetTextColor(RGB(255,0,0));
dcMem.SetBkMode(TRANSPARENT);
hFont=CreateFont(50,20,0,0,100,0,0,0,0,0,0,100,10,0);
字体高度,字体宽度,字体显示角度,字体的角度,字体的磅值,斜体字体,
带下划线的字体,带删除线的字体,所需的字符集,输出的精度,裁剪的精度,逻辑字体与
输出设备的实际,字体之间的精度,字体间距和字体集,字体名称*/
!"));
dcMem.TextOutW (400,200,s,10);
2.7鼠标键盘控制战机位置的函数
OnLButtonDown(UINT nFlags, CPoint point)
//用于鼠标控制其位置
OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
//用于键盘控制其位置
其中GetKey(int nVirtKey) 用于使键盘更加的灵活课进行粘连。
2.8 延迟函数
Sleep(1000); //此句表示系统将延迟1000毫秒。
2.9设置定时器
定时器告诉WINDOWS一个时间间隔,然后WINDOWS以此时间间隔周期性触发程序。通常有两种方法来实现:发送WM_TIMER消息和调用应用程序定义的回调函数。
SetTimer(1,30,NULL); //设置每30毫秒刷新一次
2.10双缓冲技术
关于双缓冲技术主要就是利用缓存的原理进行将所有的东西都先存在一个缓冲得虚拟的区域,然后再一次性的将所有的虚拟缓存中的东西都放入实在的存储器中。
CDC*pDC=GetDC();
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);//依附窗口DC创建兼容内存DC
依次,所有的图像文字均存入dcMem中,然后一次性的通过pDC->BitBlt(0,0,rc.Width(),rc.Height(),&dcMem,0,0,SRCCOPY);
将内存DC上的图像拷贝到前台
bmp.DeleteObject();
2.11 内存释放技术
在此次实训项目中有太多的对象的生成和运用,造成了内存的极度的紧张,当游戏进行到一定的程度的时候就会出现内存溢出现象。解决此问题的技术就是内存释放。内存释放技术的实现主要是通过释放各个满足一定条件的对象和链表来实现的,pDoc->m_ObjListBomb.RemoveAt(mPos2);用于删除指针
用于删除对象
3. 总体设计与详细设计
总体设计主要课将其分为两大部分:规则子系统,游戏对象子系统。
系统的总体结构图如下:
规则子系统主要是实现飞机大战各项游戏规则。实现需求中的游戏规则,组成结构图如下:
主要是实现敌机战机的攻击和的游戏规则等来实现计算机方和玩家进行对战。
1、主要的攻击规则如下:
1)、敌机可在战机的上方或者下方进行将子弹进行射向战机,同时战机也可根据玩家的指示进行向上或者向下进行发射导弹进行。
2)、攻击时发出声音。
2、主要的碰撞规则如下:
1)、导弹或者子弹本身的矩形区域和敌机或者战机的矩形区域相交时,表示其相互发生碰撞表示其相互爆炸。根据实战规则销毁游戏对象。
2)、战机生命为0,战机被炸,战机被销毁,游戏结束。
3)、敌机或者子弹被炸毁,将其进行销毁同时进行分数的相应的增加,并且出现文字提示。
4)、爆炸时发出声音。
3、主要时间控制规则如下:
)、当游戏的持续时间超过特定的时间,游戏结束,出现文字提示。
)、当游戏的关卡改变时进行游戏持续时间的一个相应的改变。
游戏对象子系统主要包括:应用程序对象和游戏对象
4、应用程序对象:
1)、游戏程序的加载
2)、游戏对象的绘制
3)、游戏规则的调用
4)、玩家键盘鼠标事件的获取
5、游戏对象:
1)、各游戏对象的图像加载
2)、各游戏对象的贴图
3)、各游戏对象的位置存储
3.1 系统模块划分
系统模块划分主要分为如下表中的几个模块:
游戏规则子系统 | |
模块名称 | 功能简述 |
人工智能 | 人机对战规则的实现 |
游戏子系统 | |
模块名称 | 功能简述 |
应用程序对象 | 游戏程序的加载、游戏对象的绘制、游戏规则的调用、玩家的键盘事件获取 |
游戏对象 | 各个游戏对象的抽象父类 |
战机对象 | 战机类 |
敌机对象 | 敌机类 |
导弹对象 | 导弹类 |
对象 | 类 |
爆炸对象 | 爆炸类 |
文字对象 | 文字类 |
3.2 主要功能模块
主要功能模块主要就是那些类的功能模块,主要有:
、各个游戏对象的贴图模块
2、敌机数量、方向、速度以及子弹的数量、方向和速度控制模块。
3、战机的导弹的数目、方向和速度控制模块。
4、战机的键盘控制和鼠标控制位置模块。
5、敌机、子弹和战机、导弹的碰撞检测以及爆炸模块。
6、背景添加模块。
7、战机速度控制模块。
8、游戏关卡游戏难易度设置和游戏关卡选择。
9、游戏得分和生命值控制以及游戏关卡进入控制和游戏结束。
10、游戏重新开始和游戏暂停控制模块。
11、游戏音效控制模块。
3.3 扩展功能设计思路
本次实训由于时间问题还有些扩展功能可进行增加,主要有:
给游戏增加敌机类型,丰富画面,增加难度
2、给游戏进行增加boss,通过boss的添加进行游戏的关卡和难度的更加进一步的提升。
主要思路是:再增加一个类让它继承敌机类,然后再敌机类的基础上进行增加其生命值和后的得分。当战机得分到达一定的值以后boss出现并进行和敌机一个队伍发射另类的子弹进行攻击战机。
、完善暂停/重新开始/继续游戏等功能。
、设置关卡,关卡越往后,难度越大,增加游戏的挑战性
4. 编码实现
此次实训的主要编码主要为:
4.1游戏初始创建
if(GetKey(VK_RETURN)==1)
{
pDoc->bStart=1;
}
if(pDoc->bStart==0)
{
dcMem.SetTextColor(RGB(0,255,0));
dcMem.SetBkMode(TRANSPARENT);
hFont=CreateFont(80,40,0,0,0,0,0,0,0,0,0,100,10,0);
dcMem.SelectObject(hFont);
TextOut(dcMem,cx/2-200,200,L"開始遊戲",4);
dcMem.SetTextColor(RGB(0,255,0));
hFont=CreateFont(60,30,0,0,0,0,0,0,0,0,0,100,10,0);
dcMem.SelectObject(hFont);
TextOut(dcMem,cx/2-300,300,L"PRESS < //进行游戏的开始初始创建对象 4.2定时器 void CPlaneFightView::OnInitialUpdate()//此函数用于进行定时器的设定 void CPLANEBOMPView::OnTimer(UINT_PTR nIDEvent) //在此设定器中进行各种函数的实现和调用进行相应时间的刷新 4.3背景设定 CBitmap bitmap;//封装了Windows图形设备接口中的位图,并且提供了操纵位图的成员函数 bitmap.LoadBitmap(IDB_BITMAP6); 位图图像 bitmap.GetBitmap(&bmp1); 定义一个兼容的DC 创建DC CBitmap*Old=DC.SelectObject(&bitmap); dcMem.StretchBlt(0,0,Rect.Width(),Rect.Height(),&DC,0,0,bmp1.bmWidth,bmp1.bmHeight,SRCCOPY); 4.4键盘控制函数 int CPLANEBOMPView::GetKey(int nVirtKey) return (GetKeyState(nVirtKey) & 0x8000)? 1 : 0; if(GetKey(VK_LEFT)==1) pDoc->m_pMe->m_ptPos.x-=pDoc->mspeed; if(GetKey(VK_RIGHT)==1) pDoc->m_pMe->m_ptPos.x+=pDoc->mspeed; if(GetKey(VK_UP)==1) pDoc->m_pMe->m_ptPos.y-=pDoc->mspeed; if(GetKey(VK_DOWN)==1) pDoc->m_pMe->m_ptPos.y+=pDoc->mspeed; if(GetKey(VK_CONTROL)==1) { CBomb *cbo1=new CBomb(pDoc->m_pMe->m_ptPos.x+10,pDoc->m_pMe->m_ptPos.y,1); 存导弹 CBomb *cbo2=new CBomb(pDoc->m_pMe->m_ptPos.x+30,pDoc->m_pMe->m_ptPos.y,1); 存导弹 PlaySound((LPCTSTR)IDR_WAVE2, AfxGetInstanceHandle(), SND_RESOURCE |SND_ASYNC); if(GetKey(VK_PAUSE)) { if(pDoc->bPause==1) pDoc->bPause=false; else pDoc->bPause=true ; } 4.5文字显示函数 //输出战机 戰機 CString buffer; dcMem.SetTextColor(RGB(255,255,255)); dcMem.SetBkMode(TRANSPARENT); 得分:%d"),pDoc->COUNT); dcMem.TextOutW(0, 10, buffer); 生命:%d"),pDoc->LIVE); dcMem.TextOutW(0,30,buffer); 关卡:%d"),pDoc->style+1); dcMem.TextOutW(0,50,buffer); 暂停",9);5.6调用图片编码 POSITION posBomb=NULL,posBomb_t=NULL; posBomb=pDoc->m_ObjListBomb.GetHeadPosition(); while(posBomb!=NULL) { posBomb_t=posBomb; pDoc->Bomb=(CBomb *)pDoc->m_ObjListBomb.GetNext(posBomb); if(pDoc->Bomb->GetPoint().x<0||pDoc->Bomb->GetPoint().x>Rect.Width()||pDoc->Bomb->GetPoint().y<0||pDoc->Bomb->GetPoint().y>Rect.Height()) { pDoc->m_ObjListBomb.RemoveAt(posBomb_t); delete pDoc->Bomb; } else pDoc->Bomb->Draw(&dcMem,1); } 4.6游戏对象进行碰撞测试和碰撞销毁,文字提示函数 POSITION bPos1=NULL,bPos2=NULL; pDoc->Bomb = (CBomb*)pDoc->m_ObjListBomb.GetNext(bPos1); 获得导弹矩形区域 POSITION ePos11=NULL,ePos22=NULL; for(ePos11=pDoc->m_ObjListEn.GetHeadPosition();( ePos22 = ePos11 ) != NULL;) { pDoc->pEnemy = (CEnemy*)pDoc->m_ObjListEn.GetNext(ePos11); 获得敌机矩形区域 CRect tmpRect; 判断两个矩形是否有交接 { 添加爆炸效果 pDoc->m_ObjListEx.AddTail(new CExplosion(eRect.left,eRect.top)); PlaySound((LPCTSTR)IDR_WAVE2, AfxGetInstanceHandle(), SND_RESOURCE |SND_ASYNC); pDoc->COUNT+=2; if(pDoc->timer<50) { CString s0,s1,s2,s3,s4; dcMem.SetTextColor(RGB(0,255,0)); dcMem.SetBkMode(TRANSPARENT); hFont=CreateFont(30,20,0,0,0,0,0,0,0,0,0,100,10,0); dcMem.SelectObject(hFont); s0.Format(_T("COUNT +2")); dcMem.TextOutW(250,200,s0); pDoc->timer++; } else pDoc->timer=0; 删除zhadan pDoc->m_ObjListBomb.RemoveAt(bPos2); delete pDoc->Bomb; 删除敌机 pDoc->m_ObjListEn.RemoveAt(ePos22); delete pDoc->pEnemy; break; } } 4.7选择下一关卡以及选择完成后的执行代码 if(pDoc->Boss1Death>=1) { pDoc->Boss1Death=0; pDoc->bPause=0; 是否进入下一关?",MB_YESNO)==6) { pDoc->style++; pDoc->bPause=1; pDoc->LIVE+=5; } else pDoc->bEnd=1; 4.8游戏结束代码 if(pDoc->style>=10) { dcMem.SetTextColor(RGB(0,0,0)); dcMem.SetBkMode(TRANSPARENT); hFont=CreateFont(80,40,0,0,0,0,0,0,0,0,0,100,10,0); dcMem.SelectObject(hFont); 恭喜您全部通关",7); CString buffer; dcMem.SetTextColor(RGB(255,255,0)); dcMem.SetBkMode(TRANSPARENT); hFont=CreateFont(30,15,0,0,0,0,0,0,0,0,0,100,10,0); 得分:%d"),pDoc->COUNT); dcMem.TextOutW(0, 10, buffer); pDoc->bEnd=1; } if(pDoc->bEnd==1) { CString buffer; dcMem.SetTextColor(RGB(255,255,0)); dcMem.SetBkMode(TRANSPARENT); hFont=CreateFont(80,40,0,0,0,0,0,0,0,0,0,100,10,0); dcMem.SelectObject(hFont); 得分:%d"),pDoc->COUNT); dcMem.TextOutW(cx/2-200,300, buffer); pDoc->bEnd=1; 4.9鼠标控制战机代码 void CPLANEBOMPView::OnLButtonDown(UINT nFlags, CPoint point) { 在此添加消息处理程序代码和/或调用默认值 CView::OnLButtonUp(nFlags, point); CPLANEBOMPDoc* pDoc = GetDocument(); if(pDoc->Myplane!=NULL&&pDoc->time>0) { if(pDoc->Myplane->getpoint().x>0) pDoc->Myplane->setpoint(point.x,point.y); } } 4.10重新开始游戏代码 void CPlaneFightView::On32772() { 在此添加命令处理程序代码 return; } void CPlaneFightView::On32773() { 在此添加命令处理程序代码 return; } 5. 实训中遇到的主要问题及解决方法 此次实训中遇到的最大的问题一共有两个,一个是C++的面向对象的思想和逻辑思路的不熟悉,对于我自己来说,面向对象真的是很难理解,我根本就不明白其中的封装之类的以及多态的思想,致使开始真正的进入实训时真的是一头雾水什么都不会。后来主要是通过看书和看了几个小的网上视频大概的理解了些面向对象的思想和思路以及其好处。 其次就是一些关于C++的语法问题,例如静态成员的声明问题就烦恼了我接近一天,最后还是在同学那里理解到其不仅需要在头文件中声明,其在源文件中也是需要声明的,应为其在头文件中进行声明在源文件中不进行声明则表示其根本就没有被分配内存空间,致使出现错误。这些主要就是靠查找课本以及询问同学得到解决了。 6. 实训体会 通过此次实训让我感触颇多,主要一方面就是自己的文化知识的不够扎实,对于C++的基本的语法都记不牢还需要进行查书,再者就是自己的理解问题,我主要就是把时间浪费在了理解类以及类之间那种消息的传递和封装的问题上,致使自己的进程相对缓慢,并且由于自己对封装的理解的不够透彻,导致代码写的页比较的混论,这就警示我在以后的学习中一定要做到学以精的地步。还有就是通过此次实训让我更加的了解到自己存在的不足之处,例如;自己的马虎,导致一个小小的输入错误,导致出现错误,并且调试也弄不明白是怎么回事,后来发现竟然是变量的混乱造成的,所以在以后的实践中我要更加的仔细,同时我也需要提高自己的实践能力,通过此次实训实在是感觉自己的压力所在,以后一定更要注意在保证自己的基础文化知识学精的同时再学以致用通过具体的实践来提高自己的实践能力。