飞机空战V11修改优化篇.docx
- 文档编号:3245226
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:12
- 大小:1.35MB
飞机空战V11修改优化篇.docx
《飞机空战V11修改优化篇.docx》由会员分享,可在线阅读,更多相关《飞机空战V11修改优化篇.docx(12页珍藏版)》请在冰豆网上搜索。
飞机空战V11修改优化篇
飞机空战V1.1
二:
修改优化篇
/*-----------------------------------------------------------------------------------------------------------------------------*Author:
Sunsu
*E-mail:
641655502@
*Date:
2013-02-01
-----------------------------------------------------------------------------------------------------------------------------*/
前言:
前面今天已经实现飞机空战的基本对战功能,我方战机可以与敌机进行正常对战,可以设置我方战机和敌机的生命值,实现游戏难度的增加。
问题的发现:
破程序竟然占了将近27M内存,肯定要优化了。
1.
游戏运行一段时间后不能运行了,程序崩溃退出了,这是什么问题呢,很郁闷呢,仔细想想了,看了下CPlaneDoc类
原来这样,数据的存储我都是来组织的,这样就有一个大问题,数组的大小是固定的,程序一旦运行,系统就分配给数组固定大小的内存,不可以扩展,这样当敌机的数量超过了100架,或者我方战机和敌机发了超过了1000发子弹的话,数组将会溢出,出现越界访问问题,程序自然退出了。
好了,知道了问题就对症下药了,优化数据结构,换用可动态增长的数组和链表存储结构,我首先想到的是C++的库函数里的CArry类,查看了MSDN,用法还就简单,还有Example
用法还就简单,#include
不用不知道,一用吓一跳,报了一大堆错,看了半天发现,貌似在使用自定义的类作为其数组元素时,类中必须有合适复制构造函数和重载的=运算符,麻烦了,还是自己封装把,自给自足,就用链表把,以前上数据结构课程时经常用,熟悉。
分析一下类需实现的功能,具有自动数组元素自动收缩功能,当一个数组元素删除时,后面的元素能自动向前缩进,可以动态增加元素,重载[]运算符,可以计算数组元素的个数,
类设计如下:
采用模版编写,增强了类的可复用性,因为需要不同类型的数组元素。
两点说明:
1.类设计好后,使用时编译器报了一大推莫名其妙的链接错误,编译没有问题,链接出问题了,查了查资料,由于本人采用的是VC6.0编译器,此编译器比较老,所以不支持模版分离编译,即模版类的声明和定义必须放在一个文件里,不能分开放在头文件和源文件中,这个问题以前在大一时就遇到过,当时还有同学讨论了好长时间,时间久了,忘记了,没有及时吸取教训,导致这次在这个问题上有浪费了好长时间。
。
2.重载operator[]时的时候,应该返回数组元素本身值的引用,这样才可以直接对元素本身的数据成员进行修改。
类设计完成后,修改CPlaneWarDoc类中的数据成员,采用自定义的类组织数据。
这样敌机,敌机子弹和我方子弹的数量就可以动态添加和删除了,当敌机和子弹移动出了窗口界面显示范围就将其删除,节约内存。
2.
还有个问题,就是图片的显示问题。
我们为每个实例都设置了一个数据成员,用来存储图片,这个成员是从基类CWarObject继承而来的,这样就导致一个问题,每个敌机都是一样的,敌机的每个子弹的显示图片也是一样的,我方子弹也是一样,这样为每个角色实例都设置一张图片,是不是太浪费内存了,可不可以用类的静态成员来保存图片数据成员,因为类的静态成员是属于类自身的,不属于某个具体实例,这样在内存该类的所有实例共享同一张图片,节约了系统资源。
因为静态成员是属于类自身的,所以必须要重新设计基类和继承的子类了,因此基类不能再有m_Image成员,必须将m_Image设置为子类的数据成员。
可是每个角色的图片又不一样,敌机和我方战机显示图片并不一样,之前CPlane类的设计是为了更好的体现复用性,所以敌机和我当战机都是CPlane的实例。
所以必须重新设计飞机和子弹类,从基类派生出各自自己的专属类。
敌机子弹类:
我方战机子弹类:
敌机类:
我方战机类:
3.
重点说说屏幕界面绘制的问题。
这是V1.0版本中使用的界面屏幕绘制代码部分。
程序中多次使用InvalidateRect(LPCRECTlpRect,BOOLbErase=TRUE)来通知屏幕更新视图,MSDN对这个函数的解释:
参数lpRect指定了屏幕更新区域,下一次发送WM_PAINT消息时,这个CRect矩形区域将会增加到屏幕的更新区域中,显然使用这个函数比使用Invalidate(BOOLbErase=TRUE)这个函数效率高。
但是这样导致了一个问题,多次使用InvalidateRect(LPCRECTlpRect,BOOLbErase=TRUE),
如果bErase为TRUE,还是会导致屏幕在局部矩形区域不断擦出背景,不断重画,如果背景与所画图形差别较大,将会产生严重的闪烁,定时器时间间隔越短,屏幕局部闪烁越厉害,导致程序运行不流畅,影响对游戏的操作。
前面讲过可以通过使用双缓冲来实现屏幕绘制。
何为双缓冲,通俗讲就是把所有的绘制代码现在内存里画好,然后再一次性输出到屏幕,每次都这样,由于人眼视觉暂留原理,玩家将看到的连续的画面切换。
我们平时看岛国动漫火影或海贼,动漫放的非常流畅,没有一点闪烁,电影也是,动漫和电影都是一帧一帧不断替换的,每一帧之间相差特别小,所以这样观众肉眼看不出停顿,观察到的是一段段移动流畅的视频,基于这个原理,我实现的游戏界面绘制也是这个原理,不管屏幕背景画刷如何,每次更新时,都不需要擦出背景,直接现在内存中画,画好了一次性输出到屏幕覆盖先前屏幕上的图像,由于图像之间差别不大,所以看不出停顿现象。
基于这个原理,我们为CPlaneWarView类添加一个CDCm_MemDC数据成员,初始话为内存DC,在OnDraw()函数里直接现在内存m_MemDC里画好图像,在一次性输出到屏幕DC。
OnDraw()函数代码部分:
这样使用双缓冲技术优化界面显示还带来另一个好处,将屏幕绘制功能和定时器游戏角色位置移动控制功能完全分离,逻辑上代码会更清晰,定时器里不需要计算出最小绘制无效矩形,减少CPU负荷,一举多得。
呵呵。
4.开启多线程。
虽然在前面我们利用了双缓冲技术,是屏幕绘制代码和角色状态控制代码有了更好的逻辑独立性,但这仅仅使程序的代码功能更加模块化。
仔细分析看看,屏幕绘制代码的执行和角色控制代码的执行还是同步的,并没有达到异步执行,我们在前面定时器消息相应函数里做的是计算角色状态信息的工作,既然是计算,完全交与辅助线程去做,充分利用线程并发执行的优势,使主线程负责屏幕绘制,辅线程负责角色状态计算,使程序并发执行,加快程序运行速度。
这样的话就完全没有必要相应WM_TIMER消息了,创建一个线程执行函数DWORDWINAPIRoleControl(LPVOID)初始状态为挂起状态,再用PeekMessage()为辅线程创建消息队列用于和主线程通信。
这样就可以不需要定时器了,当我方战机炸毁的时候主线程想辅助线程发送WM_QUIT消息就可以终止辅助线程的执行。
到这里,优化阶段工作已经基本完成。
附上效果图:
内存占用减小到7M多,看来优化代码还是很有必要的。
(游戏运行流畅,无丝毫闪烁)
游戏暂停状态:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 飞机 空战 V11 修改 优化
![提示](https://static.bdocx.com/images/bang_tan.gif)