游戏窗口模式:用窗口模式运行游戏

看到有些朋友关心窗口模式实现,特根据个人实战整理代码出来.
窗口模式前表面操作范围是整个桌面区域,GetWindowRect(hwnd,&rect);取得实际窗口范围,实际窗口范围包括了我们需要绘制区和窗口Control控件,要取得窗口Control控件大小,并修正rect.
裁剪只对Blt有效,对GDI装置无效,对表面锁定操作无效,因此所有绘图工作和表面锁定操作应该在后表面进行.

※预定义文档:
取出系统信息,实际客户区是窗口大小扣去窗体Control控件占用区
#SafeRelease(lpx)(lpx!=NULL){lpx->Release;lpx=NULL;}//释放Macro
#DD_Call(callcode)(FAILED(callcode))DD_FALSE//DXMacro

#GSM_CAPTIONGetMetrics(SM_CYCAPTION)//标题栏
#GSM_CXBORDERGetMetrics(SM_CXFIXEDFRAME)//不可调边框
#GSM_CYBORDERGetMetrics(SM_CYFIXEDFRAME)
#GSM_CYMENUGetMetrics(SM_CYMENU)//如果有菜单
#MAXWIDTH640//游戏显示区大小
#MAXHEIGHT480

※WinMain:
不包含最大化和可调边框
hwnd=CreateWindow(
__T(appname),
__T(wndname),
WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED,//注意这里
CW_USEDEFAULT,
CW_USEDEFAULT,
MAXWIDTH+(GSM_CXBORDER<<1),//注意这里
MAXHEIGHT+GSM_CAPTION+(GSM_CYBORDER<<1),//注意这里
GetDesktopWindow,
NULL,
hinst,
NULL
);

化:
主表面lpddsur/ddsd,次表面lpddsurback/ddsdback
次表面大小符合游戏区大小
DD_Call(DirectDrawCreateEx(NULL,(void**)&lpdd,IID_IDirectDraw7,NULL));
DD_Call(lpdd->SetCooperativeLevel(hwnd,DDSCL_NORMAL));//注意这里
DD_Call(MainSurface(hwnd,&lpdd,&lpddsur,&ddsd));
DD_Call(BackSurface(MAXWIDTH,MAXHEIGHT,&lpdd,&lpddsurback,&ddsdback));//注意这里

※主表面:
HRESULTMainSurface(HWNDhwnd,LPDIRECTDRAW7*lplpdd,LPDIRECTDRAWSURFACE7*lplpddsur,DDSURFACEDESC2*lpddsd)
{
mem(lpddsd,0,(DDSURFACEDESC2));
lpddsd->dwSize=(DDSURFACEDESC2);
lpddsd->dwFlags=DDSD_CAPS;
lpddsd->ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
DD_Call((*lplpdd)->CreateSurface(lpddsd,&(*lplpddsur),NULL));
LPDIRECTDRAWCLIPPERlpclip;
DD_Call((*lplpdd)->CreateClipper(NULL,&lpclip,NULL));
DD_Call((*lplpddsur)->SetClipper(lpclip));
DD_Call(lpclip->SetHWnd(NULL,hwnd));//注意这里
SafeRelease(lpclip);
DD_OK;
}
※次表面:
HRESULTBackSurface(UINTnWidth,UINTnHeight,LPDIRECTDRAW7*lplpdd,LPDIRECTDRAWSURFACE7*lplpddsur,DDSURFACEDESC2*lpddsd)
{
mem(lpddsd,0,(DDSURFACEDESC2));
lpddsd->dwSize=(DDSURFACEDESC2);
lpddsd->dwFlags=DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
lpddsd->ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_VIDEOMEMORY|DDSCAPS_LOCALVIDMEM;
lpddsd->dwWidth=nWidth;
lpddsd->dwHeight=nHeight;
DD_Call((*lplpdd)->CreateSurface(lpddsd,lplpddsur,NULL));
DD_OK;
}

※游戏循环体:

RECTrect;//这个是主表面区域
GetWindowRect(hwnd,&rect);//取得整个窗口区域
rect.leftGSM_CXBORDER;//修正到主表面区域
rect.topGSM_CAPTION+GSM_CYBORDER;
rect.right-=GSM_CXBORDER;
rect.bottom-=GSM_CYBORDER;
RECTrectback={0,0,ddsdback.dwWidth,ddsdback.dwHeight};//这个是次表面区域

........//实际在次表面绘图操作

HDChdc;
DD_Call(lpddsurback->GetDC(&hdc));
TCHARstrbuf[55];
_stprf(strbuf,"%s",__T("JustATest!"));
TextOut(hdc,0,0,strbuf,()_tcslen(__T("JustATest!")));
DD_Call(lpddsurback->ReleaseDC(hdc));

DD_Call(lpddsur->Blt(&rect,lpddsurback,&rectback,DDBLT_WAIT,NULL));
切操作在次表面进行,完成后全部Blt到主表面.

Tags:  窗口化运行游戏 窗口模式运行 游戏窗口运行 游戏窗口模式

延伸阅读

最新评论

发表评论