ege vs2010 扫雷程序代码代码,求大神!!!

本文来自互联网感觉内容很好,收藏于此文章末尾有原作者信息,如转贴请保留


本文献给使用Nokia Symbian 60 SDK各个版本开发游戏软件的程序员。虽然本文主要是针对游戏软件但昰大部分内容对一般应用软件也同样适用。


上的文章和SDK我也没有看过任何关于Symbian的书籍。只是偶然的我在天津猛犸游戏公司()认识并接触了Symbian。我从零起步写出了一个蹩脚的Symbian游戏引擎并在3650、7650上开发了一些游戏。所以我对Symbian的掌握完全是出于自己的猜测和理解虽然本文缺乏权威,但至少都是经验之谈容易理解。


Symbian游戏是运行在手机上的游戏它不能干扰手机正常的通讯功能,对操作系统和其它应用程序必須友善而在首次编写Symbian C++游戏时,我遇到了无数奇怪的问题其中大部分问题出在内存极端不足,打开太多应用程序屏幕保护探出,接到短信、电话等特殊情况下

其实如果养成严谨的代码风格,进行足够的错误处理大部分问题本可以避免。为了解决它们我很是花了一番功夫,所以在此把我的一些教训、经验写出希望大家能避免犯同样的错误。

如果你不是业余爱好者而是为一个认真的开发商工作,特别是如果你的产品需要通过Symbian Signed认证()你就必须更加小心的对待本文提出的问题。

Symbian Signed是一个针对Symbian应用程序的认证想要通过它,你的应用程序必须通过一系列严格的测试认证对应用程序的文件管理、内存使用、系统事件响应、网络、资费和私人数据等都有一定的要求。如果想了解Symbian Signed认证的详细内容可以去它们的网站下载白皮书。


虽然我们都知道任何一个new (ELeave)或者带有L后缀的函数都可能抛出异常但是很多业余嘚爱好者还是会忽视Symbian C++中异常处理的重要性。虽然有些函数只有在极其罕见的情况下才会抛出异常但不是危言耸听,如果你不写代码捕捉並处理它们应用程序就会遇到"系统错误"。

普通C++使用throw抛出异常异常抛出后,栈会不停回滚直到遇到最近一层catch为止。Symbian C++中的异常处理不使鼡try-catch和throw但是它的处理机制和标准C++很是类似,区别仅仅是它只能抛出一个整数错误码而不是一个任意对象。

我将从异常的抛出、捕捉、处悝三方面讲解这部分内容

Symbian C++中,有下面几种情况下会抛出异常:

使用静态函数User::Leave抛出异常这个函数就是最基本的异常产生函数。下面讲的其它抛出方式都可以转化为User::Leave

调用带有L后缀的函数。Symbian系统的命名规范中要求每一个可能Leave的函数都要有后缀L。包含有带L的内层函数调用的外层函数也必须加上L这类函数中最常见的就是NewL, NewLC和ConstructL这个规范比你想象的要重要。因为它给其他程序员一个暗示提示他们对这些函数進行保护。

类似标准C++的catch语句Symbian C++的TRAP关键字可以对一个可能产生异常的函数进行保护,并且捕获到异常值比如:

// 捕捉到了一个异常,在这里添加处理异常的代码

类似的TRAPD省去了你声明一个局部变量的麻烦头两行代码可以简写成:

对于不同的异常当然有不同的处理方法(废话:-))。我们以最常见的捕获到代表内存不足的KErrNoMemory异常为例讲解

注意在Container,AppUi等类的构造过程中你不需要加入对内存不足的保护。因为这一切系统巳经为你做好了系统会弹出一个对话框报告内存不足。根据你的操作系统版本不同这可能是中文的,也可能是英文或者其它语言的洳果你不信,可以在AppUi或者Container的 ConstructL中写一行User::Leave(KErrNoMemory)试试看我试验的结果如下:

除了上面说的特殊情况,你可以简单的弹出一个对话框告诉用户没有足够的内存运行程序,并且安全的关闭程序比如我的游戏程序就是这样处理的:


当然,你也可以制作一个精美的图片来报告内存不足等待用户按任意键再退出。不过载入这个图片也可能会失败所以至少在这个图片成功载入之前,你还是需要系统对话框来报告的

值得┅提的是,你不一定需要退出程序或者你可以稍后重试申请内存,幸运的话没准第二次就能成功。这是因为Symbian系统会在内存不足时自动關闭一些应用程序我觉得这是Symbian系统一个比较奇怪的设计。通常应用程序在AppUi的HandleCommandL中会响应EEikCmdExit消息并且调用CAknAppUi::Exit( )函数(如下代码)。这使得应用程序可以在应用程序管理器中用C键结束掉这也使得Symbian操作系统有机会在内存不足时通过这个渠道自动关闭一些应用程序。

坦白说我没有尝试過重试申请内存这个办法不过我想是可行的。

1.3.4.栈回滚和对象的安全析构

上面说到在遇到某些异常时你可以选择弹出对话框并且结束程序,其实这会比你想象的要困难一些因为C ++可不像Java那样有托管堆进行垃圾收集。不过好在C++栈会自动回滚栈上的对象会被销毁。如果你此時调用CAknAppUi:: RunAppShutter( )结束程序那么AppUi,Container的析构函数会依次被调用引起你自己创建对象的析构函数也依次被调用。那么堆上的对象也要被销毁可是,請记住异常随时随处可能发生,使对象处于一种"半构造"的状态此时析构函数被调用可能会造成对无效指针的访问错误。请看下面这个唎子它犯了两个常见的错误:

下面我们分析一下可能遇到的问题:

首先,在函数NewL中self指针没有被保护,试想如果self->ConstructL( )一句抛出异常那么这個self指针指向的对象就没有return给外界(也就是AppUi),这个对象就永远"丢失了"造成了内存泄露。正确的做法是使用CleanupStack对它进行保护CleanupStack至少能保证在程序退出时压入其中的对象都能销毁。

但是注意此处还有一个微妙的内存泄露。仔细看看CleanupStack::PushL( )的声明:

如果传入的指针是CBase指针那么CBase的虚析構函数(virtual ~CBase( ))就能保证对象在销毁时正确的调用析构函数。可是本例中BadExample不是从CBase中派生那么对象只能做很有限的销毁,根本不会调用析构函數所以,如果ConstructL是由于第二个内存申请m_pBuf2失败那么m_pBuf申请的内存就永远不会回收。所以正确的做法是让

其次,我们并没有为 m_pBuf和m_pBuf2赋初值在Release蝂中他们的值是随机的。那么如果m_pBuf2的申请失败,析构函数还是会执行delete m_pBuf2试图删除一个无效指针。正确的做法是在构造函数中为m_pBuf和m_pBuf2赋初值NULL因为标准C++规定,delete一个空指针不做任何操作不过实际上,如果对象从CBase派生这一步是没有必要的,因为CBase能保证派生类的成员变量在构造時自动清零

最后,动态的使用DeleteBuf和RebuildBufL是不安全的如果你先用DeleteBuf删除了这个对象,那么m_pBuf就是一个坏指针可是紧接着的RebuildBufL可能会失败。此时如果析构函数被调用还是会产生delete无效指针的错误。正确的做法是在DeleteBuf 中,把m_pBuf设为NULL

总结上面说到的几点,完整的安全的代码是:

1.4.安全的图像引擎

Symbian C++游戏的2D图像显示部分一般由下面几个类组成:

图像: 封装了一个CWsBitmap是基本的图片资源。支持图像之间的各种贴图和混合操作

双缓冲: 一個和屏幕分辨率、色深相等的图像。

直接写屏支持: 复合一个CDirectScreenAccess对象实现MDirectScreenAccess接口。负责直接写屏的安全处理比如来电、屏保时适时的停止和開启直接写屏与游戏逻辑。

绘图类: 负责在图像中绘图它不是对Gc的封装,而是通过直接修改图像内存区进行绘图

位图字体类: 使用预先创建的位图资源写字。如下图就是一个预先创建的位图资源优点是速度快,缺点是无法支持大字符集合比如中文。

字体缓冲区类: 还是使鼡Gc的DrawText函数绘制文字但是同时用一张位图作为一个缓冲区存储最近绘制的文字。既能支持大字符集合速度也很快。

如果需要学习图形和矗接写屏的基础请参考Programming Games in C++ v1.0()。本文主要针对图像类和直接写屏类讲几个容易被忽略的问题

1.4.1.图像类的直接内存访问

贴图是2D游戏最主要的畫面操作。为了实现快速的贴图或者实现某种混合效果,就不能再使用CFbsBitGc的BitBlt或者BitBltMasked进行贴图而必须自己得到图片的内存地址,直接读写其Φ的数据在读写图片内存地址的过程中,有几点需要加以注意

首先,只有当源图片和目标图片色深相等时才更容易进行贴图操作。所以再载入图片的过程中,我习惯把非4k色的图片转化为4k色之所以选择4k色是因为它也是后台缓冲区的色深。下面的代码通过转换可以保證iImage是4k色的图像

其次,Symbian系统在内存匮乏时会进行碎片整理所以如果简单的用CFbsBitmap::DataAddress获取内存首地址并开始读写,那么可能在你读写的过程中圖片已经被悄悄的移动了位置,你读写的就是一块无效的内存区域解决这个问题的办法是在获取首地址前,必须先锁定图像内存区域茬高版本的60系列SDK 中(比如2.0,2.1)有LockHeap和UnlockHeap函数可以完成这个操作。但是在低版本的SDK中(比如0.91.0),这两个函数是私有的我们必须通过TBitmapUtil锁定内存。但是不一定必须使用TBitmapUtil的SetPixel和GetPixel函数进行位操作下面是最基本的没有关键色和Alpha通道的简单贴图代码。

// 其它情况有关键色等等.

最后告诉大镓几个优化的小窍门:

使用While循环直接把指针的比较作为循环结束条件。不要再多用一个整数来控制循环

贴图是个两重循环,如果你的代碼需要判断是否支持关键色和Alpha通道等尽量把判断外移到循环之外。每个象素都进行好几个if判断的开销太不值得比如上面的代码,处理朂简单的情况时while循环内一个if都没有。

4k色时RGB内存排列如下图。所以未被使用的4位正巧可以用来存储alpha通道

.4.2.直接写屏和特殊系统事件

接口函数。可是具体在这两个函数中做什么SDK没有过多的介绍。我在此说一下我的做法如果你合理的处理了这两个函数,就可以轻松应对来電、屏保、程序切换等事件

我们先说AbortNow,它的处理比较简单你之需在其中停止驱动游戏逻辑的计时器(一般是个CPeriodic对象),停止声音模块(一般是一个CActive任务)就可以了

值得费些力气的是Restart函数,它并不是在应用程序回到前台并且可以进行全屏直接写屏时才被回调。所以不能在此时武断的恢复游戏逻辑开始游戏。

)恢复直接写屏但是必须给这个函数加上TRAP保护。因为它很可能抛出KErrNotReady异常如果遇到这个异常,那你就直接返回好了因为直接写屏此时并不能开始。接下来你需要检查一下绘图区域看是否整个屏幕都可以被使用。如果不是那也無需启动游戏逻辑,只需要用最后保留的后台缓冲区的内容更新直接写屏区域即可第三种情况,如果直接写屏成功启动并且整个屏幕嘟可以被绘制,才启动游戏逻辑启动声音等其它模块。

CSimpleMixer它实现CAudioGenerator接口。因为CMdaAudioOutputStream是一个单一的流式播放器所以需要写一个混音器进行波形混合。这里波形混合就是简单的数据相加混音器有许多的声道(channel)。每个channel记录了其中的CAudio指针和当前播放位置

CAudio。包含一个音频缓冲区對每个声音文件,我们还需要一个类把它载入到内存缓冲区中

我不会在此讲解如何实现音频播放,那需要单独的一篇文章如果你也使鼡这种方法实现声音播放,我只想在此和大家讨论两个问题

需要学习声音基础的话,可以参考(可惜我当时学习声音时那篇文章和代碼找不到了)

1.5.1.声音的关闭和开启

因为整个音频系统是一个拉的结构,音频流从混音器那里拉数据混音器从音频缓冲区中拉数据。所以呮要把 CMdaAudioOutputStream和写数据的CActive对象delete掉,声音播放就全部停止了在我的实现中,也就是delete CAudioStreamPlayer对象即可再想要开启声音,只需要重新创建这个对象

这个實现的好处是程序的其它部分不需要保存声音是否开启这个状态。因为CAudio和CSimpleMixer对象是存在的CAudio就可以把自己插入到Mixer的channel中,觉得自己好像在播放┅样其实因为CAudioStreamPlayer根本没有从Mixer向外拉数据,声音设备是完全停止的

但是在恢复声音播放时有一点需要注意,恢复前需要清空混音器中的声喑数据因为经过了长时间的运行,混音器中的各个channel中已经塞满了各种声音如果此时突然打开,会传出各种延迟了的杂音

比如MaoscPlayComplete函数,昰在音频停止播放时被调用停止播放的原因可能是多种多样的。我们都知道要处理KErrUnderflow这个情况这个错误吗意味着混音器没有及时的供给咜音频数据。此时需要重新启动声音流但是还有一些情况比如KErrDied和KErrInUse很容易被忽略。KErrDied发生在接听电话时此时声音线程已经死了,那么就需偠重建整个音频系统KErrInUse发生在收到短信时,此时声音设备被抢占用来播放短信提示音。此时你也需要重建整个声音系统但是此时不能竝刻重建,否则还是一样的结果你应该等待几秒钟之后才重建它。

上面说的重启声音流和重建声音系统深度不同重启声音流在稍后的玳码中可以看到。其中RunAudioL向音频流写入了第一个声音缓冲区重建声音系统在我的实现中就是指先delete 再NewL创建CAudioStreamPlayer对象。

这三个错误的处理代码如下:

经过上面的处理我的程序已经可以安全的应对来电、短信、切换程序等特殊情况了。


本文来自CSDN博客转载请标明出处:

一个控制台俄罗斯方块C++源代码以忣C/C++控制台界面编程资料 [问题点数:40分结帖人u]

确认一键查看最优答案?

本功能为VIP专享开通VIP获取答案速率将提升10倍哦!

本版专家分:10060

本版專家分:10060

哪位兄弟、老师能够改改程序

本版专家分:10060

哪个IDE没有断点调试功能?

本版专家分:10060


本版专家分:10060

好jiht594把代码由单文件改成几个类嘚头文件和实现文件,并增加了注释程序背景色改为喜庆的红色,不过其它效果没有改动用VC 2010 Express可以编译。

本版专家分:10060

有谁能把方块由單色改为彩色吗

本版专家分:10060

匿名用户不能发表回复!

一个控制台俄罗斯方块C++源代码以忣C/C++控制台界面编程资料 [问题点数:40分结帖人u]

确认一键查看最优答案?

本功能为VIP专享开通VIP获取答案速率将提升10倍哦!


哪个IDE没有断点调试功能?

好jiht594把代码由单文件改成几个类的头文件和实现文件,并增加了注释程序背景色改为喜庆的红色,不过其它效果没有改动用VC 2010 Express可鉯编译。

有谁能把方块由单色改为彩色吗

匿名用户不能发表回复!

我要回帖

更多关于 扫雷程序代码 的文章

 

随机推荐