1、 软件开发生产 实习报告 姓名 李瑜 学号 1201050614 班级 信息管理与信息系统2012-1 项目名称 飞机大战 实习地点 J13-232 实习时间 2014.9.20-2014.9.30 实习成绩 指导教师签字 信息科学与工程学院 2014 年 10 月 15 日 软件开发生产实习报告 1. 实习目的 1.1使学生全面了解软件项目实施的过程,
2、理解软件企业对于程序员的基本素质和技术能力要求。 1.2使学生掌握C++及Window程序设计的基本技术,能够运用MFC技术及其开发环境进行小型项目的开发。 1.3重点培养学生的独立创新精神和查阅资料能力,提高其口头和书面的沟通能力。 1.4使学生掌握快速学习新知识、新技术方法,培养良好的分析问题和解决问题的能力 1.5重点提高学生的编程能力,使学生建立正确的编程理念,养成规范的编程习惯。 2. 实习计划 一、9.20-9.21 1、 认识MFC的基本功能,实现在windows窗体上的贴图功能; 2、 初步利用brush绘制背景的颜色,进而掌握添加背景图片的技术; 3、 设
3、置定时器进行刷屏; 二、9.22-9.25 1、 把握游戏的整体架构,了解各个类之间的继承与多态关系,对父类进行编码; 2、 对游戏对象进行透明贴图,并实现具体的功能; 三.9.26-9.28 1、 建立各个游戏对象的链表,并定义对象; 2、 实现用键盘控制战机的移动,实现战机与战机导弹的链接; 3、 实现其他游戏对象的移动与速度的设定; 4、 实现战机导弹与敌机、子弹与战机矩形区域的重合的功能,并清除链表中需要清除的对象; 5、 释放定时器和内存; 四、9.29-9.30 1、 与游戏的功能与界面进行完善,添加文字显示和生命条等; 2、 对游戏进行调试与改进。 3.
4、实习过程 4.1 技术准备 (1)、透明贴图函数 LoadImage(CImageList& imageList,UINT bmpID,COLORREF crMask,int cx,int cy,int nInitial) //可用于从 BMP 文件加载位图,主要用于将图片放入图像链表imageList中。 m_Images.Draw(pDC,0,m_ptPos,ILD_TRANSPARENT) //此函数主要是将链表中的图像显示在pDC这个句柄中。 (2)、CObList链表 CObList list_ball; //主要是定义一个CObList类的一个链表
5、对象用于存储所有的此种相关对象,易于后续的添加删除和提取数据。 POSITION posball=NULL; //定义指针 posBall=list_ball.GetHeadPosition();//指针读取头结点 pBall=(CBall *)list_ball.GetNext(posBall);//指针读取下一个结点 (3)、设置定时器 定时器告诉WINDOWS一个时间间隔,然后WINDOWS以此时间间隔周期性触发程序。本程序中使用多个定时器,分别控制不同的功能。使用SetTimer()函数设置定时器,设置系统间隔时间,在OnTimer()函数中实现响应定时器的程序。
6、 (4)、双缓冲技术 关于双缓冲技术主要就是利用缓存的原理进行将所有的东西都先存在一个缓冲得虚拟的区域,然后再一次性的将所有的虚拟缓存中的东西都放入实在的存储器中。 (5)、内存释放技术 在此次实训项目中有太多的对象的生成和运用,造成了内存的极度的紧张,当游戏进行到一定的程度的时候就会出现内存溢出现象。内存释放技术的实现主要是通过释放各个满足一定条件的对象和链表来实现的,list_bomb.RemoveAt(B2);//RemoveAt从列表中删除指定位置的元素 delete pBomb;//删除敌机 (6)、获取矩形区域函数 CRect rc; //定义 Get
7、ClientRect(&rc); //获取其矩形区域 获取结果为:rc.Width() //矩形区域的宽度rc.Height() //矩形区域的高度 CRect tmpRect; tmpRect.IntersectRect(&bRect,eRect))//判断两个矩形是否有交接 4.2 项目实施 4.2.1 功能需求 1、 战机数量为1,战机的位置可通过键盘进行控制。可通过空格键控制战机进行发导弹,导弹具有一定的速度。 2、敌机出现的时间和位置均为随机,敌机的速度也是随机的,敌机发射子弹的时间也是随机的,子弹的发射具有延时性,子弹的速度具有随机性。 3、导弹和子弹及敌
8、机碰撞爆炸同时销毁碰撞的物体,战机和子弹及敌机碰撞爆炸同时销毁碰撞的子弹及敌机,战机则判断生命,为0时销毁否则不销毁。与此同时进行分数和生命的变化同时进行文本的显示提示。 4、背景图片的添加。为游戏提供相关背景。 5、主要的攻击规则如下: 敌机可在战机的上方或者下方进行将子弹进行射向战机,同时战机也可根据玩家的指示进行向上或者向下进行发射导弹进行反攻。 6、主要的碰撞规则如下: 1)、导弹和敌机的矩形区域或子弹和敌机的矩形区域相交时,表示其相互发生碰撞表示其相互爆炸,销毁游戏对象。 2)、战机生命为0,战机被炸,战机被销毁,游戏结束。 3)、敌机被炸毁,将其进行销毁同时进行
9、分数的相应的增加,并且出现文字提示。 7、实现对战机的生命的增减,战机基本生命值为5,战机射击增加生命值,当其被击中后其生命就-1,每销毁一架敌机加10分,销毁累计10架敌机,战机的生命值加一,生命为0时游戏结束。 8、实现控制战机速度的功能主要是用于在键盘控制战机位置时。 9、实现双缓冲技术进行解决刷屏时屏闪的问题。 4.2.2 总体设计 1、 系统模块划分 飞机大战游戏主要模块可以说是有几个重要的类组成的。首先是老师给出的CGameObject类,以及在其派生下的BOMB,BALL,ENEMY,MYPLANE等等。如图: 2、主要功能模块 主要功能是在飞机大战View类
10、中,OnTimer函数中实现,将各个类调用,随机产生敌机,子弹的输出,爆炸的实现等等。它的实现图可以如下实现: 4.2.3 详细设计与编码 #include "stdafx.h" #include "飞机大战.h" #include "飞机大战Doc.h" #include "飞机大战View.h" #include"MyPlane.h" #include"explosion.h" #include"ball.h" #include"enemy.h" #include"bomb.h" #ifdef _DEBUG #define new DEBUG_NEW
11、undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif void CMyView::OnDraw(CDC* pDC) { CMyDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); } void CMyView::OnTimer(UINT nIDEvent) { CDC* pDC=GetDC(); CRect rc; GetClientRect(&rc); //双缓存 CDC memDC;//定义一个显示设备对象 C
12、Bitmap bmp;//定义一个位图对象 memDC.CreateCompatibleDC(NULL);//建立与屏幕显示兼容的内存显示设备 bmp.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height()); CBitmap*oldBit=memDC.SelectObject(&bmp); //设置背景图 CBitmap bitmap; CBrush brush; bitmap.LoadBitmap(beijing); brush.CreatePatte
13、rnBrush(&bitmap); CClientDC dc(this); memDC.FillRect(&rc,&brush); CRect rect; GetClientRect(&rect); //------------------------------ static int life=5; static int score=0; /****画战机******************************************/ if(pMyPlane!=NULL) {
14、 pMyPlane->Draw(&memDC,0,rc); memDC.SetBkMode(TRANSPARENT);//透明 memDC.SetTextColor(RGB(255,255,20));//文字颜色 memDC.TextOut(20,150,"分数:"); memDC.TextOut(100,150,itoa(score,new char,10));//itoa:把int转为char字符串 memDC.TextOut(20,180,"剩余生命:"); memDC.TextOut(150,180,itoa(life,new char,
15、10)); //显示生命线 CBrush brush1; brush1.CreateSolidBrush(RGB(255,0,0)); //创建画刷 memDC.SelectObject(brush1); //选择画刷 memDC.Rectangle(rect.Width()/2-100,10, rect.Width()/2+life*60-100, 30); } else { memDC.SetBkMode(TRANSPARENT); me
16、mDC.SetTextColor(RGB(255,255,20)); memDC.TextOut(300,300,"GAME OVER"); } /*******************添加战机导弹************************/ POSITION posBomb=NULL; posBomb=list_bomb.GetHeadPosition(); while(posBomb!=NULL) { pBomb= (CBomb *)list_bomb.GetNext(posBomb); pBomb->Draw(&memDC,0,rc);
17、 } /******************添加敌机*********************/ static int n=0; if(n<=0) { n=rand()%40; list_enemy.AddTail(new CEnemy); } n--; POSITION pEnemy1=NULL,pEnemy2=NULL; pEnemy1=list_enemy.GetHeadPosition();//GetHeadPosition 返回列表中首元素的位置 while((pEnemy2=pEnemy1)!=NULL) {
18、 pEnemy=(CEnemy*)list_enemy.GetNext(pEnemy1); if(!pEnemy->Draw(&memDC,0,rc)) { list_enemy.RemoveAt(pEnemy2); delete pEnemy; } int x=rand()%40; if(x==1) { list_ball.AddTail(newCBall(pEnemy->GetPoint().x+12,pEnemy->GetPoint().y+25,pEnemy->GetMontion())); } } /********
19、添加敌机子弹*******************************/ POSITION posBall=NULL; posBall=list_ball.GetHeadPosition(); while(posBall!=NULL) { pBall=(CBall *)list_ball.GetNext(posBall); pBall->Draw(&memDC,0,rc); } /****************添加爆炸效果**************************/ POSITION posExplo
20、sion=NULL; for(posExplosion=list_explosion.GetHeadPosition();posExplosion!=NULL;)//GetHeadPosition返回列表中首元素的位置 { pExplosion=(CExplosion*)list_explosion.GetNext(posExplosion); //GetNext获取循环遍历中的下一个元素 pExplosion->Draw(&memDC,0,rc); } /*****************战机子弹炸掉敌机***********************/ i
21、f(pMyPlane!=NULL) { POSITION B1=NULL,B2=NULL; B1=list_bomb.GetHeadPosition(); while((B2=B1)!=NULL) //GetHeadPosition 返回列表中首元素的位置 { pBomb= (CBomb*)list_bomb.GetNext(B1); //GetNext获取循环遍历中的下一个元素 CRect bRect = pBomb->GetRect();//获得导弹区域 POSITION E1=NULL,E2=NULL;
22、 E1=list_enemy.GetHeadPosition(); while((E2=E1)!=NULL) { pEnemy=(CEnemy*)list_enemy.GetNext(E1); CRect eRect=pEnemy->GetRect();//获得敌机区域 CRect enRect; //定义一个区域,该区域作用为获得导弹和敌机区域的交集。 if(enRect.IntersectRect(&bRect,eRect)) //若导弹和敌机有交集,删除导弹和敌机,添加爆炸效果 { score+=10;
23、 //添加炸弹效果 list_explosion.AddTail(new CExplosion(eRect.left, eRect.top)); //删除导弹 list_bomb.RemoveAt(B2);//RemoveAt从列表中删除指定位置的元素 delete pBomb; //删除敌机 list_enemy.RemoveAt(E2); delete pEnemy; //生命值与分数换算 static int a; a++; if(a%10==0) {
24、 life+=1;//每击破10架敌机生命数加1 } } } } } /**********************敌机子弹炸掉战机********************/ if(pMyPlane!=NULL) { POSITION bPos1=NULL,bPos2=NULL; CRect mRect = pMyPlane->GetRect();//获得战机区域 bPos1=list_ball.GetHeadPosition(); while(( bPos2 = bPos1 ) != NULL)
25、 { pBall = (CBall*)list_ball.GetNext(bPos1); CRect bRect = pBall->GetRect();//获得子弹区域 CRect tmpRect; if(tmpRect.IntersectRect(&bRect,mRect)) //子弹区域与战机区域相交 { life-=1; //添加炸弹效果 list_explosion.AddTail(new CExplosion(mRect.left,mRect.top)); //删除子弹 list_ball.Re
26、moveAt(bPos2); delete pBall; //删除战机 if(life==0) { delete pMyPlane; pMyPlane=NULL; break; } } } } /*****************敌机与战机相撞****************************/ if(pMyPlane!=NULL) { POSITION bPos1=NULL,bPos2=NULL; CRect mRect = pMyPlane->GetRect
27、);//获得战机区域 bPos1=list_enemy.GetHeadPosition(); while(( bPos2 = bPos1 ) != NULL) { pEnemy = (CEnemy*)list_enemy.GetNext(bPos1); CRect eRect=pEnemy->GetRect();//获得敌机区域 CRect tmpRect; if(tmpRect.IntersectRect(&eRect,mRect)) //敌机区域与战机区域相交 { score+=10; life-=1;
28、 //添加炸弹效果 list_explosion.AddTail(new CExplosion(mRect.left,mRect.top)); //删除敌机 list_enemy.RemoveAt(bPos2); delete pEnemy; //删除战机 if(life==0) { delete pMyPlane; pMyPlane=NULL; break; } } } } //双缓存释放 pDC->BitBlt(0,0,rc.Width(),rc.He
29、ight(),&memDC,0,0,SRCCOPY); memDC.SelectObject(oldBit); memDC.DeleteDC(); bmp.DeleteObject(); CView::OnTimer(nIDEvent); } void CMyView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if(pMyPlane!=NULL) { if(nChar==VK_RIGHT) { pMyPlane->SetHorMotion(1); } if(nChar=
30、VK_LEFT) { pMyPlane->SetHorMotion(-1); } if(nChar==VK_UP) { pMyPlane->SetVerMotion(1); } if(nChar==VK_DOWN) { pMyPlane->SetVerMotion(-1); } } //战机添加导弹 if(pMyPlane!=NULL) { int m; m=GetKey(VK_SPACE); if(m==1) { { list_bomb.AddTail(newCBom
31、b(pMyPlane->GetPoint().x,pMyPlane->GetPoint().y+20)); list_bomb.AddTail(newCBomb(pMyPlane->GetPoint().x+20,pMyPlane->GetPoint().y)); list_bomb.AddTail(newCBomb(pMyPlane->GetPoint().x+40,pMyPlane->GetPoint().y+20)); } } CView::OnKeyDown(nChar, nRepCnt, nFlags); } int flag = 0; void CMy
32、View::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)//释放 { if(pMyPlane!=NULL) { if(nChar==VK_RIGHT) { pMyPlane->SetHorMotion(0); } if(nChar==VK_LEFT) { pMyPlane->SetHorMotion(0); } if(nChar==VK_UP) { pMyPlane->SetVerMotion(0); } if(nChar==VK_DOWN)
33、{ pMyPlane->SetVerMotion(0); } } CView::OnKeyUp(nChar, nRepCnt, nFlags); } int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here //安装定时器 SetTimer(1,30,NULL); //1是定时器的标示
34、符,30ms的间隔,NULL表示让窗体接受消息,不是函数 pMyPlane=new CMyPlane; //显示飞机 CMyPlane::LoadImage(); CBomb::LoadImage(); CEnemy::LoadImage(); CBall::LoadImage(); CExplosion::LoadImage(); return 0; } void CMyView::OnDestroy() { //释放定时器 KillTimer(1); delete pDC; CView::OnDestroy(); }
35、 4.2.4 测试 游戏界面: 1、各游戏对象碰撞检测爆炸模块测试 用例 预期结果 实际结果 问题描述 修改方案 导弹和敌机相撞 导弹和敌机爆炸并被销毁 导弹和敌机爆炸并被销毁 子弹和战机相撞(战机生命变为1) 子弹和战机爆炸并销毁子弹,战机依旧 子弹和战机爆炸并销毁子弹,战机依旧 子弹和战机相撞(战机生命变为0) 子弹和战机爆炸并销毁,战机也销毁 子弹和战机爆炸并销毁,战机也销毁 2、文字显示,游戏结束模块测试 用例 预期结果 实际结果 问题描述 修改方案 游戏开始 显示文字进行提示玩家其得
36、分、生命值和剩余时间等 显示文字进行提示玩家其得分、生命值和剩余时间等 游戏进行中战机或者导弹击毁敌机或者子弹 显示加分的值 显示加分的值 游戏过程中战机被击毁 游戏结束文字提示 游戏结束文字提示 4.总结与建议 通过这次飞机大战的实训,一方面我深刻的意识到了自己所掌握的C++知识还远远不够,基本的语法都记不牢还需要进行查书,致使实训进行的非常缓慢;另一方面,自己对于C++面向对象的思想没有把握好,并且对于封装之类的以及多态的思想也不是真正的理解。通过实训,我还意识到光记住书本的理论知识是远远不够的,要不断的进行实践,只有在不断的敲代码、改错
37、误的反复过程中才能使自己的编程能力得到真正的提升。 在此次实训中,自己的程序只是实现了基本的功能,还可以有其他的扩展功能可进行增加,主要有: 1、给游戏进行增加boss,通过boss的添加进行游戏的关卡和难度的更加进一步的提升。 主要思路是:再增加一个类让它继承敌机类,然后再敌机类的基础上进行增加其生命值和被打死后的得分。当战机得分到达一定的值以后boss出现并进行和敌机一个队伍发射另类的子弹进行攻击战机。 2、给游戏进行增加另类的子弹供boss向战机进行攻击,此类继承敌机的子弹类。 3、进行增加存盘处理,用于暂停功能。通过存盘使玩家可以进行暂停或者人为结束时的继续进行玩。主要思路是:在玩家进行选择暂停或者结束时,系统将当前各个类的对象信息存储在文件中,当玩家选择继续时,系统从文件中读取各个对象的相应信息进行继续进行游戏。






