下载 >  开发技术 >  C++ > 基于C++开发的射击游戏

基于C++开发的射击游戏 评分:

用DDraw实现射击游戏说明文档 要点一:画图自动切割 IDirectDrawSurface7::BltFast()方法中没有自动切割功能,即当画图元素超出窗口以外时不会自动切割,DDraw选择自动忽略不画,造成一旦超出窗口,画图元素会突然消失。 解决这一问题的方法是手动切割,代码如下: //自动切割 RECT scRect; //存放当前窗口大小区域 ZeroMemory( &scRect, sizeof( scRect ) ); GetWindowRect( GetActiveWindow(), &scRect ); //防止图片左上角超过窗口左上角 if ( x < 0 ) { m_rect.left -= x; x = 0; } if ( y < 0 ) { m_rect.top -= y; y = 0; } //防止图片右下角超过窗口右下角 x = x > scRect.right ? scRect.right : x; y = y > scRect.bottom ? scRect.bottom : y; m_rect.right = x + m_rect.right - m_rect.left > scRect.right ? scRect.right - x + m_rect.left : m_rect.right; m_rect.bottom = y + m_rect.bottom - m_rect.top > scRect.bottom ? scRect.bottom - y + m_rect.top : m_rect.bottom; 只需将上述代码加在CGraphic::BltBBuffer() 中的m_bRect = m_rect; 前即可。 要点二:背景的滚轴实现 画背景可以分为以下三种情况: 情况一:背景图片与窗口等高 情况二:背景图片高度小于窗口高度 情况三:背景图片高度大于窗口高度 上述讲解图与代码相对应地看,有助于容易理解。 另外,要点一实现之后,由于已经可以自动切割,画背景可以用其它方法。 要点三:精灵图的实现 在游戏中,如RPG游戏中的人物图、射击类游戏的飞机、爆炸等,叫做精灵图。 精灵图实际上是将所有帧的图片放在一个文件中,游戏时靠一个RECT来控制画图像文件中的哪一部分,进而控制游戏显示哪一帧图,只需控制好RECT的位置即可。如下图: 控制RECT的四个角的坐标的移动,有以下代码: if (m_timeEnd – m_timeStart > 100) //只有到了100ms之后才绘图 { m_ImageID++; if(m_ImageID - m_beginID >= num) { m_ImageID = m_beginID; //最后一帧的下一帧是第一帧 } m_timeStart = timeGetTime(); } int id = m_ImageID++; SetRect(&m_rect, 41 * id, 0, 41 * (id + 1), 41); //飞机精灵图大小是41×41 m_pGraph->BltBBuffer(m_pImageBuffer, true, m_Pos.x, m_Pos.y, m_rect); 这样就实现了精灵动画的效果。 要点四:拿STL进行子弹的实现 子弹的实现可以使用STL中的vector,当按下开火键时发出一颗子弹,就往vector中添加一个结点;当子弹飞出窗口或击中敌机时,再将结点从vector中删除。每帧游戏画面中子弹飞行时只需将vector中的所有子弹进行处理、绘画即可。 参考代码如下: 1.添加子弹 if (g_ctrlDown) //当ctrl键按下时开炮! { m_BulletEnd = m_Gtime->GetTime(); if ((m_BulletEnd - m_BulletStart) * 1000 > 120) //如果连续按着开火键不放,这里控制不会发出太多子弹 { m_BulletStart = m_BulletEnd; MBULLET tmpBullet; tmpBullet.pos.x = m_SPos.x - 1; //记录开火时的子弹位置 tmpBullet.pos.y = m_SPos.y - 26; tmpBullet.speed = 5; //该子弹的飞行速度 m_BulletList.push_back(tmpBullet); //将子弹添加到vector中 } } 2.删除子弹 vector<MBULLET>::iterator itei; //vector迭代器 for (itei = m_BulletList.begin(); itei != m_BulletList.end(); itei ++) //遍历所有子弹 { m_BulletList.erase(itei); //删除这个子弹 itei = m_BulletList.begin(); //删除一个结点后,为避免出错下次就从头检查 if (m_BulletList.empty()) break; //若删除结点后子弹vector已空则跳出循环 } 3.子弹遍历处理 vector<MBULLET>::iterator itei; //vector迭代器 for (itei = m_BulletList.begin(); itei != m_BulletList.end(); itei ++) //遍历所有子弹 { itei->pos.y -= itei->speed; //子弹飞行 } 要点五:碰撞检测 使用Windows API函数RectInRegion: vector<CEnimy>::iterator itei; //vector迭代器 for (itei = m_EnimyList.begin(); itei != m_EnimyList.end(); itei ++) //遍历所有敌机 { HRGN hrgn = ::CreateRectRgn(m_player->pos.x, m_player->pos.y, m_player->pos.x + 41, m_player->pos.y + 41); //得到飞机Region,图宽41高41 SetRect(&m_rect, itej->getPosition().x, itej->getPosition().y, itej->getPosition().x + 50, itej->getPosition().y + 50) //得到敌机rect,敌机宽50高50 if ( RectInRegion(hrgn, &m_rect) ) //两机相撞 { ……………………. //碰撞之后的各种处理 } } 让碰撞更加精确: 使用Windows API函数PtInRegion()和CreatePolygonRgn(),选取主角飞机的三个关键点的坐标放在POINT数组中,并将其作为参数代入 CreatePolygonRgn()中生成HRGN,在子弹与主角飞机做碰撞检测时只需判断子弹的中心点是否在这个Region中即可(PtInRegion())。 注意:CreateRectRgn()与CreatePolygonRgn()等创建Region的函数会占用系统资源,由于游戏的主渲染函数Render()是不断执行的,这样会造成资源浪费,因此在用完之后一定要释放:DeleteObject(region) 要点六:敌机直线飞行 最初想这个问题的时候,以为很好实现,脑子里马上想到 和 了。其实这样实现有问题,当起点和终点的连线斜率不是1或-1时就会出现意想不到的事情了,飞机并没有直接飞向终点,而是以斜率绝对值为1的路径飞过去,再水平或垂直飞向终点。 解决这个问题有几个方法,其中有一个方法是利用计算机图形学上的Bresenhem直线算法。该算法用于计算机画平面上的直线,算法如下: |m|<1的情况 1、输入线段的两个端点,并将左端点存储在(x0,y0)中; 2、将(x0,y0)装入帧缓冲器,画出第一个点; 3、计算常量dx,dy,2dy和2dy-2dx,并得到决策参数的第一个值: d0 = 2dy-dx 4、从k=0开始,在沿线路径的每个xk处,进行下列检测: 如果dk<0,下一个要绘制的点是(xk+1,yk),并且 dk+1 = dk+2dy 否则,下一个要绘制的点是(xk+1,yk+1),并且 dk+1 = dk +2dy –2dx 5、重复步骤4,共dx次。 利用此原理,实践在敌机直线飞行中的代码如下: void CEnimy::Move() { int deltaX = m_targetPos.x - m_pos.x; int deltaY = m_targetPos.y - m_pos.y; // 轨迹斜率 = 0 if ( !deltaX ) { if ( deltaY < 0 ) m_pos.y -= m_speed; else m_pos.y += m_speed; return; } // 轨迹斜率无穷大 if ( !deltaY ) { if ( deltaX < 0 ) m_pos.x -= m_speed; else m_pos.x += m_speed; return; } // 以下是用计算机图形学 Bresenham 算法计算两点间的直线轨迹 if ( abs(deltaX) > abs(deltaY) ) // 轨迹斜率 < 1 { if ( m_bFirstCalculate ) { m_Delta = 2 * abs(deltaY) - abs(deltaX); // d0 = 2 × dy - dx m_bFirstCalculate = false; } // 根据轨迹斜率判断是否要移动 Y 坐标 if ( m_Delta > 0 ) // < 0 时只改变 X 坐标,否则 X、Y 坐标都要变 { if ( deltaY < 0 ) m_pos.y -= m_speed; else m_pos.y += m_speed; m_Delta += 2 * abs(deltaY) - 2 * abs(deltaX); // 计算下一个 dn } else { m_Delta += 2 * abs(deltaY); // 计算下一个 dn } // X 坐标每一帧都要向目标移动 if ( deltaX < 0 ) m_pos.x -= m_speed; else m_pos.x += m_speed; } else // 轨迹斜率 > 1 { if ( m_bFirstCalculate ) { m_Delta = 2 * abs(deltaX) - abs(deltaY); // d0 = 2 × dx - dy m_bFirstCalculate = false; } // 根据轨迹斜率判断是否要移动 X 坐标 if ( m_Delta > 0 ) // < 0 时只改变 Y 坐标,否则 X、Y 坐标都要变 { if ( deltaX < 0 ) m_pos.x -= m_speed; else m_pos.x += m_speed; m_Delta += 2 * abs(deltaX) - 2 * abs(deltaY); // 计算下一个 dn } else { m_Delta += 2 * abs(deltaX); // 计算下一个 dn } // Y 坐标每一帧都要向目标移动 if ( deltaY < 0 ) m_pos.y -= m_speed; else m_pos.y += m_speed; } } 要点七:通过读取配置文件实现敌机的飞行轨迹 不同敌机以不同的轨迹飞行,实现的方法有很多,只要把轨迹上的几个关键点作为敌机的目标点,当到达这个目标点时,把目标列表中的下一个点作为下一个目标点,敌机继续向其飞行,这样就实现了敌机的不同轨迹飞行。但是要想把游戏中所有的敌机都写在代码中会很乱,不容易维护。VC++开发平台提供了两个函数:GetPrivateProfileSectionNames()和GetPrivateProfileString(),用来读取硬盘上的配置文件(.cfg),这样,每一架飞机的初始化信息可以写在.cfg文件中,通过一个循环算法来读取。 1. 函数说明: 这是将.cfg文件中所有的section names读取到一字符数组中: DWORD GetPrivateProfileSectionNames( LPTSTR lpszReturnBuffer, // 用来存放section names 的字符串指针 DWORD nSize, // 字符串的长度 LPCTSTR lpFileName // .cfg文件的路径 ); 这是读取某一section name中的某个字段的值: DWORD GetPrivateProfileString( LPCTSTR lpAppName, // 在这个section name中查找 LPCTSTR lpKeyName, // 要查找的字段名 LPCTSTR lpDefault, // 若查找失败的默认返回值 LPTSTR lpReturnedString, // 存放指定字段名所对应的值 DWORD nSize, // 存放返回值的字符串长度 LPCTSTR lpFileName // 在这个.cfg文件中查找 ); 2. 文件要求: .cfg文件的内容格式如下: [section name] key1=string key2=string 例如,在敌机的配置文件enimy.cfg中可以这么写: [ENIMY01] //这是进度号,不同进度加载不同敌机 tempoid=1 //这是图片号,根据需要加载不同的敌机图片 imageid=0 //这是图片的总帧数 imageframenum=2 //这是图片的宽度 imagewidth=100 //这是图片的高度 imageheight=50 //这是敌机生命值 hp=3 //这是敌机移动速度 speed=1 //这是敌机的初始位置 pos.x=512 pos.y=-50 //有两个目标点,即由两个点决定其轨迹 targetnum=2 //以下是目标点的坐标 targetpos0.x=512 targetpos0.y=192 targetpos1.x=240 targetpos1.y=600 其中,注释可以写入文件中,但不能与即将要读取的数据在同一行。 3. 代码例子: // 读取 CFG 文件中所有的敌机名称 // 读取完后m_sEnimyName中的字符串是每个section name的连接,两两之间用”\0”字符分开,如: // “enimy01.enimy02.enimy03”其中的点就是空字符 GetPrivateProfileSectionNames(m_sEnimyName, sizeof(m_sEnimyName), "data/enimy.cfg"); char *pStr = m_sEnimyName; // 用来保存当前的section name char returnedString[64]; m_iTempo++; // 每发动一波敌机,游戏进度加1 // 从 cfg 文件中找到进度等于 m_iTempo 的敌机 GetPrivateProfileString( pStr, "tempoid", "1", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); // 跳过以前已经加载过的敌机 while ( *pStr && atol( returnedString ) < m_iTempo ) { pStr += strlen( pStr ) + 1; // 这样处理,就能使pStr指向下一个section name GetPrivateProfileString( pStr, "tempoid", "1", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); } // 开始加载敌机 while ( *pStr ) { // 读取敌机的图片ID号 GetPrivateProfileString( pStr, "imageid", "0", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); int imageID = atol( returnedString ); // 读取敌机图片的总帧数 GetPrivateProfileString( pStr, "imageframenum", "2", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); int imageFrameNum = atol( returnedString ); // 读取敌机图片的宽度 GetPrivateProfileString( pStr, "imagewidth", "50", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); int imageWidth = atol( returnedString ); // 读取敌机图片的高度 GetPrivateProfileString( pStr, "imageheight", "50", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); int imageHeight = atol( returnedString ); // 读取敌机移动速度 GetPrivateProfileString( pStr, "speed", "1", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); int speed = atol( returnedString ); // 读取敌机的初始位置 POINT initPos; GetPrivateProfileString( pStr, "pos.x", "50", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); initPos.x = atol( returnedString ); GetPrivateProfileString( pStr, "pos.y", "0", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); initPos.y = atol( returnedString ); // 读取敌机运动轨迹上的各个目标点 int targetNum; // 目标点总数 GetPrivateProfileString( pStr, "targetnum", "1", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); targetNum = atol( returnedString ); POINT *targetArray; // 存放各目标点坐标 targetArray = new POINT[ targetNum ]; // 根据读取的目标点总数分配多少个坐标点 // 读取每一个目标点坐标 for ( int i = 0; i < targetNum; i++ ) { char buf[32]; sprintf( buf, "targetpos%d.x", i ); GetPrivateProfileString( pStr, buf, "0", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); targetArray[i].x = atol( returnedString ); sprintf( buf, "targetpos%d.y", i ); GetPrivateProfileString( pStr, buf, "0", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); targetArray[i].y = atol( returnedString ); } // 根据读取的敌机数据,创建敌机,并放入容器当中 CEnimy tmpEnimy( m_pGraph, m_pEnimyImageBuffer[imageID], 0x00000000, imageFrameNum, imageWidth, imageHeight ); tmpEnimy.Init( initPos.x, initPos.y, speed, targetArray, targetNum ); m_EnimyList.push_back( tmpEnimy ); //发射一架敌机 pStr += strlen( pStr ) + 1; // 取下一个字符串 GetPrivateProfileString( pStr, "tempoid", "1", returnedString, sizeof( returnedString ), "data/enimy.cfg" ); // 属于当前进度的敌机加载完后跳出while循环 if ( atol( returnedString ) > m_iTempo ) break; } // end of while (*pStr)
...展开详情收缩
2013-04-30 上传大小:2.18MB
分享
收藏 (1) 举报

评论 共4条

jasmine0427 代码很详细,又有游戏说明书,学习中
2015-03-14
回复
u014492334 很详细,学习中
2014-05-29
回复
zqm44ff 代码很好,很详细,学习中
2014-02-17
回复
u011244821 我下载了你上传的这个设计小游戏,想自己学习一下。这个游戏的编译环境是?我知道有vc++6.0,那个.bmp格式的图是用什么啊?还有能推荐比较实用的书吗?谢谢你了。
2013-10-08
回复
VS下用C++实现的简单3D射击游戏(附游戏文件与源工程代码)
FPS射击游戏《林海雪原》完整c++源代码

使用的 主要技术有: 1、大面积山脉渲染,使用Heightmap构造地形,7级 LOD 细节精度,地形无限重复循环 。 2、清晰、自然的地表贴图。 3、读取.MD2 、.MS3D 格式的3D模型文件。 4、粒子系统,产生爆炸、炊烟等特效。 5、太阳光晕。 6、使用Blend模拟Brightness/contrast调节图象亮度。 操作控制 可以在GameSetting菜单中设定: 1.视频属性 ( Video Setting ) 1).屏幕分辨率( Resolution ) 游戏率默认为800*600,在任务执行前可改变分辨率,但不会立即生效,只有在初始化任务时才改变分辨率。 2).屏幕

立即下载
射击类小游戏c++源代码

在VC++6.0的环境下,用C++语言利用了EZwin编写的原创射击类小游戏,代码简单,适合初学者了解如何在屏幕上显示图片,加入音乐等问题。

立即下载
C++实现的射击游戏

该游戏,类似于射击游戏,首先,从窗口顶部的随机位置产生随机的分值为:1,5,10,-20的4种运动的位图。窗口下面有一个发送子弹的小人,小人可以左右移动,子弹从小人的位置往上运动,若子弹射中了相应分值的位图,就在总分数加上相应的分值,并在窗口的左上角显示出来。如果按住菜单栏里的退出菜单项,那么就结束整个游戏。用C++原始API实现的。

立即下载
C++简单的飞行射击游戏源码

C++游戏 C++射击游戏 飞行游戏 C++飞行射击源代码 跟打小蜜蜂游戏类似

立即下载
C++ 飞行射击游戏设计全程实录
推荐一个适合零基础开发的射击游戏
【180623】有意思的VC++射击游戏源代码
Problem : 射击
C++编写的射击游戏

C++,射击游戏,游戏中可以用鼠标或键盘操纵射击方向,游戏中只要是为了体现出C++的游戏引擎。

立即下载
C++卡通风格3D射击游戏源码

游戏截图: http://blog.csdn.net/niehanmin/article/details/79342876 C++卡通风格3D射击游戏源码,国外网站无意中看到的,3D卡通风格游戏,基于 3D OpenGL 、 QFusion 引擎开发,支持windows 、linux、MAC OS X。

立即下载
C语言射击游戏练习程序
2D射击类游戏源码下载M.A.R.S(C/C++)
3D枪战射击游戏cs简单版源代码

3D枪战射击游戏cs简单版源代码,本代码用opengl开发,使用vc6.0适用于初学者

立即下载
【题解】射击-C++
飞行射击游戏的C++实现:一次课程作业
经典飞行射击游戏c++源码

经典的飞行射击累游戏,c++源码 弄懂这个对学习c++有很大的帮助!

立即下载
基于c++的格斗游戏

采用c++面向对象的思想设计的格斗类游戏,包括玩家类,继承自玩家类的弓箭手、法师和战士类,以及存放人物道具的背包类。

立即下载
飞行射击游戏(C++附带源代码)

DirectDraw7.0实现 VC++ 6.0环境编译

立即下载

热点文章

下载码下载
做任务获取下载码
取消 提交下载码
img

spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip

资源所需积分/C币 当前拥有积分 当前拥有C币
5 0 0
点击完成任务获取下载码
输入下载码
为了良好体验,不建议使用迅雷下载
img

基于C++开发的射击游戏

会员到期时间: 剩余下载个数: 剩余C币: 剩余积分:0
为了良好体验,不建议使用迅雷下载
VIP下载
您今日下载次数已达上限(为了良好下载体验及使用,每位用户24小时之内最多可下载20个资源)

积分不足!

资源所需积分/C币 当前拥有积分
您可以选择
开通VIP
4000万
程序员的必选
600万
绿色安全资源
现在开通
立省522元
或者
购买C币兑换积分 C币抽奖
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
为了良好体验,不建议使用迅雷下载
确认下载
img

资源所需积分/C币 当前拥有积分 当前拥有C币
3 0 0
为了良好体验,不建议使用迅雷下载
VIP和C币套餐优惠
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
确认下载
下载
您还未下载过该资源
无法举报自己的资源

兑换成功

你当前的下载分为234开始下载资源
你还不是VIP会员
开通VIP会员权限,免积分下载
立即开通

你下载资源过于频繁,请输入验证码

您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:webmaster@csdn.net!

举报

  • 举报人:
  • 被举报人:
  • *类型:
    • *投诉人姓名:
    • *投诉人联系方式:
    • *版权证明:
  • *详细原因: