常规的游戏都是在进行屏幕更新的时候再进行鼠标绘制,一旦FPS降低,鼠标的控制将非常的困难,这点相信大家都遇到过,这次想和大家讨论的就是如何让鼠标操作更贴切,更顺畅。 问题如何解决?相信我们每天在使用windows,windows在磁盘操作,或者CPU繁忙的时候都能保持鼠标的操作顺畅,我们的游戏完全可以学习windows的做法来让我们的游戏鼠标操作更为方便。 我们先来说说windows实现鼠标的做法,按照我的观察,windows的鼠标应该是通过多线程来实现,而且鼠标线程的优先级非常之高,并且鼠标在屏幕上是使用局部更新,知道了原理,我们就可以开始动手实现我们的游戏鼠标了。
首先,我们必须创建出我们可爱的鼠标线程,让我们的鼠标拥有较高的优先级,这样才能最大限度让鼠标灵活,参考如下代码:
// 我们的鼠标线程 DWORD WINAPI ThreadProc( LPVOID lpParameter ) { ... // 实现鼠标更新的部分代码 }
// 创建我们鼠标线程,详细请参考多线程编程文章 thread = CreateThread(NULL, 0, ThreadProc, 0, 0, &g_dwMouseThread); // 提高线程的优先级 SetThreadPriority(thread, THREAD_PRIORITY_TIME_CRITICAL);
这样,我们的线程就创建完毕了,接下来我们来看看如何进行屏幕的局部更新,我们的游戏(2D)一般都是运行在DirectDraw的环境下,要进行屏幕的局部更新我们需要对主表面进行直接操作,可能你会想到,万一我们在进行鼠标更新的同时,游戏主线程也在对主表面进行如页面翻转等操作,一但这样,这将产生无法预料的结果,为了避免这种情况的产生,我们还必须进行双线程的同步处理,说了那么多废话,来看看我们如何实现:
// 用来标记鼠标进程是否进行 bool g_bMouseThreadRun = true;
// 用来处理同步,此类属于MFC线程处理部分,具体请参考MSDN CCriticalSection critsection;
// 鼠标处理实现线程部分 DWORD WINAPI ThreadProc( LPVOID lpParameter ) { // 进行鼠标线程的内部循环处理 while(g_bMouseThreadRun) { // 为了能进一步节省鼠标线程所消耗的系统资源 // 我们使用了DirectInput的鼠标事件响应操作 // 具体实现参看DirectInput的鼠标处理部分 DWORD dwResult = WaitForSingleObject(g_hMouseEvent, INFINITE);
if(dwResult == WAIT_OBJECT_0) // 有鼠标事件发生 { // 重新获得鼠标的位置信息
// 此处非常重要,用来作为与屏幕刷新的同步处理 // 这里将线程锁定,使主线程无法进行屏幕刷新操作 critsection.Lock();
if(检测鼠标位置是否有更新) { // 恢复原鼠标位置的图象 bakbuffer <- save back image // 保存鼠标将绘制部分的背景图象 save back image -> bakbuffer // 在新位置绘制鼠标 draw mouse image }
// 释放线程 critsection.Unlock(); } }
}
完成了我们的鼠标线程,接下来我们来设计我们的屏幕刷新部分,此处要注意两个问题,一个是与鼠标进程一样的同步问题,还有就是实现对局部更新时的背景图象保存缓冲的更新,一但屏幕刷新,背景难免会产生变化,那此时我们在鼠标线程中所保存的局部图象数据(bakbuffer)将是无效错误过时的数据,所以,我们必须对局部图象保存数据进行与背表面(BackSurface)进行匹配处理,并且将鼠标图象绘制到屏幕上,参看如下:
// 屏幕刷新函数 HRESULT Present() { // 同上,为了满足同步需要 // 如果有其它线程调用了Lock(),那此处将处于等待状态 // 直到其它线程Unlock(),此函数才将返回。 critsection.Lock();
// 对鼠标线程所保存的局部图象数据(bakbuffer) // 进行与背景的匹配操作 save BackSurface image -> bakbuffer
// 绘制鼠标到屏幕上,防止鼠标被背景覆盖
... // 屏幕刷新部分
// 恢复线程锁定 critsection.Unlock(); }
关于线程的释放,这里我们只需要简单的将g_bMouseThreadRun这个全局变量设置为false,这样线程就能自动退出,不过注意,为了防止鼠标线程还未退出,主线程已经将部分关键数据释放造成错误,最好能让主线程停止一会,以便鼠标线程的正确退出。
最后,我们来谈谈这种方法的利弊,优点很明显,可以让鼠标操作更为顺畅,缺点,使编程复杂化,而且多少会影响些主线程的性能。
说了那么多,有兴趣的朋友可以去下载我的HoHo游戏引擎,里面有全部原代码,还有附带的实现例子。 http://hoho.gameres.com
(文章中全部均为伪代码,只作为说明使用)
CopyRight 中国游戏开发技术资源网 sea_bug 您可以任意转载,但未经许可不可用于商业目的,转载必须保留此声明。2002/3/4
|