📄 chapter9.txt
字号:
{
if (ModeList[i].bpp == (int)GameBPP &&
ModeList[i].w == GameSize.cx &&
ModeList[i].h == GameSize.cy)
{
break;
}
}
}else
{
for (i=0; i<NumModes; i++)
{
if (ModeList[i].w == GameSize.cx &&
ModeList[i].h == GameSize.cy)
{
break;
}
}
}
if (++i >= NumModes)
{
i = 0;
}
Msg("ModeList %d %d",i,NumModes);
GameMode.cx = ModeList[i].w;
GameMode.cy = ModeList[i].h;
GameBPP = ModeList[i].bpp;
bStretch = FALSE;
InitGame();
}
break;
在收到VK_F6的消息后,程序设立一个初值为0的变量,并以该变量为存放显示模式列表的数组的下标,然后令其自加直至找到一个与当前模式相同的。然后令其自加1,取以该值为下标的元素为显示模式,最后重新初始化游戏。
5.F7的作用是改变颜色数。
case VK_F7:
GameBPP = GameBPP == 8 ? 16 : 8;
InitGame();
break;
6.F8的作用是决定是否使用拉伸算法。
case VK_F8:
if (bFullscreen)
{
bStretch = !bStretch;
InitGame();
}
else
{
RECT rc;
GetClientRect(hWnd, &rc);
bStretch = (rc.right != GameSize.cx) ||
(rc.bottom != GameSize.cy);
if (bStretch = !bStretch)
SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
else
SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);
AdjustWindowRectEx(&rc,
GetWindowStyle(hWnd),
GetMenu(hWnd) != NULL,
GetWindowExStyle(hWnd));
SetWindowPos(hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
这部分的运行过程为:若为全屏模式则对 bStretch取非,然后初始化游戏。若为窗口模式,则取得当时窗口的特征,以确定bStretch的值,然后从新显示窗口。
7.F9的作用是取消使用软件模拟并逐个使用已有的驱动程序
case VK_F9:
DevIndex ++;
bUseEmulation = FALSE;
if (DevIndex >= MaxDevIndex)
DevIndex = 0;
ExitGame();
DDDisable(TRUE); // destroy DirectDraw object
InitGame();
break;
第七节 其他消息
case WM_DISPLAYCHANGE:
break;
case WM_CREATE:
break;
这两个消息收到后,将不做任何反应。
case WM_SETCURSOR:
if (bFullscreen && bIsActive)
{
SetCursor(NULL);
return TRUE;
}
break;
该信息在光标随鼠标的移动而输入未被捕获时发出。
由于本游戏不需鼠标,故在随后的检测是否是全屏模式或是被激活的语句,获得肯定的答案后,将光标从屏幕上删除。
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
if (bPaused)
{
char *sz = "Game is paused, this is not a bug.";
TextOut(ps.hdc, 0, 0, sz, lstrlen(sz));
}
EndPaint( hWnd, &ps );
return 1;
该消息在请求重新绘制应用程序窗口是发出 。
程序在接收到这个消息后就调用BeginPaint()为hWnd所指的窗口作好绘画准备。然后判断游戏是否暂停,若是则向屏幕输出Game is paused, this is not a bug.最后调用EndPaint()
case WM_DESTROY:
hWndMain = NULL;
lastInput=0;
DestroyGame(); // end of game
DDDisable(TRUE); // destroy DirectDraw object
PostQuitMessage( 0 );
break;
该消息在要撤消某窗口时向该窗口发送。
在收到这个消息后程序令指向窗口的句柄为NULL,对游戏的刷新单元的下一次输入设为0,然后清除游戏及游戏工所占的内存。
第八节 刷新游戏单元
在讨论完窗口过程后,我们应开始介绍这个游戏的消息循环部分了。在这个游戏的消息循环部分中大部分在第二章 windows编程基础中已经谈到过了,所以在这里我们将只介绍刷新游戏单元和重画游戏单元部分。在消息循环中程序是调用函数ProcessFox(SHORT sInput)来进行这两部分的工作的。在ProcessFox(SHORT sInput)函数中,先对游戏是否正在运行或恢复游戏运行是否成功作了一个检测,然后就先调用ProcessInput(sInput)函数进行刷新游戏单元部分,再调用NewGameFrame()进行重画游戏单元的工作。下面就让我们先看看刷新游戏单元部分吧。
这一部分的运行过程为:
1.狐狸的行为刷新
首先取得当前狐狸的的速度、行为和方向。然后检测是否获得狐狸的位置或输入是否是4209,若检测的表达式为TURE则输入为0,即没有输入,若为FLASE则开始对各种输入进行响应。在响应的过程中程序先对狐狸的当前状态进行判断,然后根据狐狸的当前状态决定下一帧狐狸的基本状态。比如“↓”键或小键盘的“2”被按下时的响应过程为
case KEY_DOWN:
if( foxAction == STOP )
{
break;
}
else if( foxAction == STILL )
{
SetSpriteAction( hFox, CROUCH, SAME );
}
else if( foxAction == WALK )
{
SetSpriteAction( hFox, CROUCHWALK, SAME );
}
break;
在“↓”键被按下时,如果狐狸的动作是在急停的,则跳出;如果狐狸是静止的,则狐狸蹲下不动;若狐狸是在移动,则狐狸的行动改为爬行。
在对输入的初步处理后,程序便结合狐狸行为的其他属性,确定下一帧狐狸的状态。在这里同样是用switch——case语句和大量的if——else语句完成的。
2.熊和苹果的行为刷新
这两部分的运行过程实际上是一致的,都是首先进行碰撞检测,然后再根据检测结果决定角色新的行为属性。
第九节 重画游戏单元
这部分的工作是由NewGameFrame()完成的。这个函数首先调用SetSpriteX() 、SetSpriteY()两函数设定角色的新位置,再调用SetPlaneVelX()和SetPlaneX()函数设定三层背景的移动速度和下一帧的位置。然后通过检测bTransDest的值决定是先将角色的位图粘贴到Backbuffer还是先将背景的位图粘贴到BackiBuffer,
最后调用函数gfxSwapBuffers()进行页面翻转将后备缓冲区中的图显示到屏幕上。该函数是这样实现的:
BOOL gfxSwapBuffers( void )
{
if( bFullscreen )
{
if( bStretch )
{
gfxStretchBackbuffer();
}
if (nBufferCount > 1)
return gfxFlip();
else
return TRUE;
}
else
{
return gfxUpdateWindow();
}
它的运行过程是这样的:在全屏模式下且使用拉伸算法时用gfxStretchBackbuffer()对后备缓冲区和拉伸缓冲区之间进行blt操作,然后在有一个以上(不含一)的后备缓冲区时用gfxFlip()调用IDirectDrawSurface_Flip( lpFrontBuffer, NULL, DDFLIP_WAIT )进行一次页面翻转操作将后备缓冲区中的图显示到屏幕上。如果是窗口模式下,则通过gfxUpdateWindow()调用IDirectDrawSurface_Blt( lpFrontBuffer,&rcWindow,lpBackBuffer,NULL,DDBLT_WAIT,NULL)直接将后备缓冲区中的内容blt到主缓冲区中。这样就完成了重画游戏单元的任务了。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -