游戏开发论坛

 找回密码
 立即注册
搜索
查看: 1615|回复: 0

MessageBox, Modal, MainLoop...如何决断

[复制链接]

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
发表于 2008-9-16 15:21:00 | 显示全部楼层 |阅读模式
>>本文用词说明

  模态对话框:意思众所周知,在实现上,可以用局部消息泵,或状态变量(状态机)
    注意:在本文中,提到模态对话框,不一定就是局部消息泵,也可为状态变量(状态机)

  局部消息泵:游戏主循环之外的其他消息循环代码段,比如MsgBox内部,或你的工程的UI中的某处。
  注意:在主循环之外,即使调用了和主循环一样的消息函数,比如while(pMyDlg->IsVisible() && False==g_bExit) MyMainMsgFunc(); 这也叫做局部消息泵!
  
  消息函数:对一个Frame的处理,包括对消息,输入,更新,和渲染的调用。

***此处省略关于使用MessageBox,局部消息泵等等的过程中常遇到的恶心问题,不清楚的不妨跟帖询问***


>>对于工程的消息循环框架的选用,如何轻松地作出决断?

1问题的根源在于,所采用的消息泵,而不是何种品牌的对话框。这就是说,当不存在局部消息泵的时候,完全可以采用任何win32的对话框等。

2尽量不要使用局部消息泵,而应当采用状态变量(状态机)来实现模态对话框,除非,模态对话框的流程很复杂(如一连串的问与答)。

3如果必须要使用局部消息泵时,要尽量调用,和工程的主循环同样的函数。换言之,在一个工程中,尽量只调用同一个消息函数。(对于win32的一些对话框,你不能直接以模态方式调用他们,而应当以非模态显示它们并且采用你自己的消息函数;对于你封装的底层类库,则用回调函数即可)。

4如你所知,在游戏逻辑中不应使用局部消息泵而应采用状态变量(状态机)。所以,如果你没有完全分离界面和游戏逻辑,那么就根本不要考虑在工程中用局部消息泵。

>>是否应当为游戏封装一个虚拟的环境?即,将Confirm Exit的MessageBox放在游戏之外

上面的条目1已经很好地回答了该问题。问题的根源在于消息泵,而不是对话框的品牌,即,封装一个虚拟环境根本不能摆脱掉问题(即便是做游戏机平台的开发!)。因为,你可以为游戏提供一个虚拟的环境(即游戏不知道调用MessageBox的时候游戏是完全暂停的,只有不影响逻辑的底层win32消息被需要以及一个静止的画面被重绘)。但是,在这个虚拟环境中的游戏,仍然需要一些模态对话框,甚至Confirm Exit往往也是游戏自己绘制的对话框,而不是win32的。

>>对以上几点的质疑

Q采用了上述方法后,关于模态对话框,状态变量(状态机)增多了,这似乎挺麻烦不是吗?

A那么,让我们不理会上述条目2试试看。但是条目3和条目4,作为一个良好的程序,是起码的。

(为了直接说明问题,下列代码不进行什么封装)
while(MyDlgABC->IsVisible() && False==g_bExit)
    MyMainMsgFunc();
运行程序会发现,在模态对话框显示的时候,整个游戏照原样运行着----这不是我们期望的----我们需要游戏中的大部分功能暂停。所以,无论如何,需要一个状态变量(状态机)
比如像这样的g_pDoingModal = True;或者一些更加复杂的状态设置等。

既然横竖都需要状态变量(状态机)的话,换言之横竖都少不了这个麻烦事,那么,索性不采用局部消息泵算了,比如,把g_pDoingModal = True;替换为g_pState = State_MyDlgABC;
(不过这样会使得MyMainMsgFunc的代码变长,所以推荐封装状态机类,而不是直接用状态变量)

此外,也不是说局部消息泵就没有用处了,比如在UI中实现一个复杂的流程,我想很多人一定不愿意放弃局部消息泵,比如(简化了的代码):
g_pDoingModal = True;
while(MyDlg_Step1->IsVisible() && False==g_bExit)
    MyMainMsgFunc();
while(MyDlg_Step2->IsVisible() && False==g_bExit)
    MyMainMsgFunc();
... ...
while(MyDlg_StepN->IsVisible() && False==g_bExit)
    MyMainMsgFunc();
g_pDoingModal = False;
说个题外话,纯粹的UI中可以这么写,但游戏逻辑可千万不要这样啊!(参见条目4)

我们回到刚才的质疑上,假如现在我们连条目3也不理会。
while(MyDlgABC->IsVisible() && False==g_bExit)
{
    这里写这个对话框专用的键盘鼠标处理代码;
    MyUpdate();
    MyRender();
}
在模态对话框显示的时候,我们需要游戏中的大部分功能暂停(键盘鼠标处理和一部分逻辑的更新),但往往不需要所有东西暂停(因为那样很无聊!比如,场景中的细微的动画效果仍然继续等!)----要做到这一点,只有设置状态变量(状态机)----你不可能在这里重写所有的更新代码(那么多模块需要Update!)。就是仍然要像这样:g_pDoingModal = True;
既然横竖都需要状态变量(状态机)的话,换言之横竖都少不了这个麻烦事,那么,索性不采用局部消息泵算了。

假如现在我们连条目4也不理会?实际上条目4涉及到游戏逻辑,那不是本文的话题。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-21 07:41

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表