主题:初到贵宝地,灌一点游戏开发的东东 -- foundera
游戏鼠标操作的思考 出 处:GameRes.com
常规的游戏都是在进行屏幕更新的时候再进行鼠标绘制,一旦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游戏引擎,里面有全部原代码,还有附带的实现例子。
- 相关回复 上下关系8
实现一个非线性的故事 foundera 字3970 2004-06-09 20:56:25
国外专家谈游戏制作 foundera 字14961 2004-06-09 20:55:25
游戏Loading画面的实现 foundera 字1107 2004-06-09 20:42:28
游戏鼠标操作的思考
飞行射击游戏中的碰撞检测 foundera 字5268 2004-06-09 20:28:23
浅谈RSLG类游戏的人工智能 foundera 字6364 2004-06-09 19:41:46
电脑AI浅谈 foundera 字2883 2004-06-09 19:40:11
谈谈模拟足球游戏中人工智能 foundera 字2815 2004-06-09 19:39:38