|

楼主 |
发表于 2006-3-14 09:42:41
|
显示全部楼层
当你加入了上述代码后,让我们一起进入游戏循环!
游戏循环 你也许认为在游戏循环中唯一真正的不同是当你在窗口模式下时把后缓冲区的内容贴到主表面上而不是用翻转(fliping).好,我们就从那里开始.将你的渲染函数也用if 语句分成两部分: if( g_bExclusive ) { // exclusive code } else { // windowed code } g_bExclusive表示什么?这是我们用来追踪当前模式的全局变量! 把你原来独占模式下的渲染代码移植到exclusive code部分,然后在windowed code部分增加一个Blt函数,主表面作为目的表面,后缓冲区作为源表面,如下:
lpddPrimary->Blt(NULL, lpddBack, NULL, DDBLT_WAIT, NULL); 简直和随手拿来一样简单!等等,这语句对整个主表面作图,不只是窗口!我们怎样才能用DirectDraw把整个后缓冲区复制到窗口的窗户区呢?好,这样,我们先得到窗口的客户区,然后把客户区矩形的两个点坐标转换成相对于屏幕左上角的坐标(屏幕坐标),再把这个矩形作为Blt的第一个参数,这里是部分代码: // calculate the client rect in screen coordinates RECT rect; ZeroMemory(&rect, sizeof( rect ));
// get the client area GetClientRect(hMainWnd, &rect);
// copy the rect's data into two points POINT p1; POINT p2;
p1.x = rect.left; p1.y = rect.top; p2.x = rect.right; p2.y = rect.bottom;
// convert it to screen coordinates (like DirectDraw uses) ClientToScreen(hMainWnd, &p1); ClientToScreen(hMainWnd, &p2);
// copy the two points' data back into the rect rect.left = p1.x; rect.top = p1.y; rect.right = p2.x; rect.bottom = p2.y;
// blit the back buffer to our window's position g_lpPrimary->Blt(&rect, g_lpBack, NULL, DDBLT_WAIT, NULL);
在游戏循环中你还有一些要做的是:你不能你像独占模式下一样占着系统不放.当WINDOWS其它应用程序需要资源时,你必需让给它们.因为这是由用户选择决定的,不仅仅取决于操作系统.一个好的窗口应用程序允许用户在窗口间切换,在同一时刻使用多个应用程序.这就是WINDOWS名字的由来吧! 那么,我们怎么做呢?好, 是什么消耗了大部分计算机资源?当然是游戏循环.所以当用户切换出去时我们应该使游戏暂停,当用户切换回来时再自动开始游戏(在像大型多人在线之类的游戏中,这不太可行,你必须想其它办法 提示:你至少可以暂停渲染或只是降低一点速度).不管怎样,想办法暂停游戏循环,我们添加一个变量来追踪游戏状态:是否在运行!
bool bRunGame; 然后,我们在主消息循环(WndProc)中处理一个特定的消息: WM_ACTIVATE.每当主窗口获得或失去焦点时,我们就收到一个WM_ACTIVATE消息.wParam参数表明是获得焦点或失去焦点.设置bRunGame标识如下:
if( LOWORD( wParam ) == WA_INACTIVE ) { // the user is now working with another app bRunGame = false; } else { // the user has now switched back to our app bRunGame = true; } 如何使用这个刚设置的变量呢?每次继续游戏循环前检查此变量,并用以下代码代替你程序中的主消息循环(一般在WinMain函数中);我们看到游戏循环已嵌入到消息循环中(在最后部分): MSG msg; ZeroMemory(&msg, sizeof(msg));
for( ;; ) { if( PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE) ) { // retrieve a message GetMessage(&msg, NULL, NULL, NULL); if( msg.message == WM_QUIT ) break; // only way out of the for( ;; ) loop
// dispatch the message to our WndProc TranslateMessage(&msg); DispatchMessage(&msg); } else { if( bRunGame ) { // game code here } } }
return msg.wParam;
然后把你的游戏代码放入到新增的if 语句中(标有// game code here处),这样就完成了游戏循环部分.哈!现在到了看看如何在运行中改变模式的时候了,相信我,这将是本文中最容易的部分! 在运行时切换模式
啊!真的终于到了切换模式的时候了吗? 好的,我们将使用一个简单的函数来切换模式,它可以在窗口模式和独占模式间自由切换,并设置显示模式(在独占模式下),看: void ChangeDisplayMode(bool bExclusive, int nWidth, int nHeight, int nBPP); 有点简单,不是吗?不,让我来向你解释一下.当你要从独占模式切换到窗口模式时,你这样调用函数:
ChangeDisplayMode(false, 0, 0, 0); // windowed
当你想从窗口模式切换独占模式,或在独占模式下改变分辨率与色彩深度,你这样调用:
ChangeDisplayMode(true, 6 4 0, 4 8 0, 16); // 6 4 0x4 8 0x16 exclusive ChangeDisplayMode(true, 8 0 0, 6 0 0, 32); // 8 0 0x6 0 0x32 exclusive
不错吧!让我们来完善它吧,下面是完整的函数:
ChangeDisplayMode(bool bExclusive, int nWidth, int nHeight, int nBPP) { // destroy any existing surfaces and clippers. DestroySurfaces();
// create new surfaces and change the // cooperative level and display mode CreateSurfaces(bExclusive, int nWidth, int nHeight, int nBPP); }
这就是模式切换! 在DirectX窗口应用程序中有许多技巧来提升性能,也有不少方法使其易于使用.我们的目标是达到达到两者合一.我将在下篇文章中来阐述这方面的问题! 祝好运! 作者 Null pointer
翻译 :炎炎 邮箱 :hbyzd@126.com
|
|