网页功能: 加入收藏 设为首页 网站搜索  
游戏鼠标操作的思考
发表日期:2006-08-23作者:[转贴] 出处:  

      常规的游戏都是在进行屏幕更新的时候再进行鼠标绘制,一旦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

我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 游戏鼠标操作的思考
本类热点文章
  DirectInput里的键盘鼠标的应用
  一个中文输入的类
  掌握DirectX和DirectInput力反馈游戏杆
  格斗类游戏的键盘处理
  游戏鼠标操作的思考
  DX下VC6.0中文輸入問題
  使用系统输入法
  DirectInput 键盘编程入门
  DirectX下软件鼠标的实现
  DirectDraw 与 DirectInput 的游戏编程..
  DirectInput 鼠标编程入门
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2024 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00379