游戏开发论坛

 找回密码
 立即注册
搜索
查看: 33749|回复: 7

用窗口模式运行游戏

[复制链接]

20

主题

136

帖子

172

积分

注册会员

Rank: 2

积分
172
发表于 2005-12-2 10:00:00 | 显示全部楼层 |阅读模式
看到有些朋友关心窗口模式的实现,特根据个人实践整理代码出来.
窗口模式前表面的操作范围是整个桌面区域,GetWindowRect(hwnd,&rect);取得实际窗口范围,实际窗口范围包括了我们需要的绘制区和窗口控件,要取得窗口控件的大小,并修正rect.
裁剪只对Blt有效,对GDI装置无效,对表面锁定操作无效,因此所有绘图工作和表面锁定操作应该在后表面进行.

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

#define GSM_CAPTION GetSystemMetrics(SM_CYCAPTION) //标题栏
#define GSM_CXBORDER GetSystemMetrics(SM_CXFIXEDFRAME) //不可调边框
#define GSM_CYBORDER GetSystemMetrics(SM_CYFIXEDFRAME)
#define GSM_CYMENU GetSystemMetrics(SM_CYMENU) //如果有菜单
#define MAXWIDTH 640 //游戏显示区大小
#define MAXHEIGHT 480

※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
                );

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

※主表面函数:
HRESULT MainSurface(HWND hwnd,LPDIRECTDRAW7* lplpdd,LPDIRECTDRAWSURFACE7* lplpddsur,DDSURFACEDESC2* lpddsd)
{
        memset(lpddsd,0,sizeof(DDSURFACEDESC2));
        lpddsd->dwSize=sizeof(DDSURFACEDESC2);
        lpddsd->dwFlags=DDSD_CAPS;
        lpddsd->ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
        DD_Call((*lplpdd)->CreateSurface(lpddsd,&(*lplpddsur),NULL));
        LPDIRECTDRAWCLIPPER lpclip;
        DD_Call((*lplpdd)->CreateClipper(NULL,&lpclip,NULL));
        DD_Call((*lplpddsur)->SetClipper(lpclip));
        DD_Call(lpclip->SetHWnd(NULL,hwnd)); //注意这里
        SafeRelease(lpclip);
        return DD_OK;
}
※次表面函数:
HRESULT BackSurface(UINT nWidth,UINT nHeight,LPDIRECTDRAW7* lplpdd,LPDIRECTDRAWSURFACE7* lplpddsur,DDSURFACEDESC2* lpddsd)
{
        memset(lpddsd,0,sizeof(DDSURFACEDESC2));
        lpddsd->dwSize=sizeof(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));
        return DD_OK;
}

※游戏循环体:

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

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

HDC hdc;
DD_Call(lpddsurback->GetDC(&hdc));
TCHAR strbuf[55];
_stprintf(strbuf,"%s",__T("Just A Test!"));
TextOut(hdc,0,0,strbuf,(int)_tcslen(__T("Just A Test!")));
DD_Call(lpddsurback->ReleaseDC(hdc));

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

5

主题

217

帖子

222

积分

中级会员

Rank: 3Rank: 3

积分
222
发表于 2005-12-2 18:21:00 | 显示全部楼层

Re:用窗口模式运行游戏

这个对3D也有用?

17

主题

165

帖子

167

积分

注册会员

Rank: 2

积分
167
发表于 2005-12-3 11:29:00 | 显示全部楼层

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

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

这个对3D也有用?

这是2D游戏的窗口模式,不过好象没使用裁减来处理窗口的遮挡问题。

14

主题

163

帖子

178

积分

注册会员

Rank: 2

积分
178
QQ
发表于 2005-12-18 03:32:00 | 显示全部楼层

Re:用窗口模式运行游戏

你的代码较麻烦,目前可以参考HOHO3.0的源代码,很简洁。

32

主题

377

帖子

378

积分

中级会员

Rank: 3Rank: 3

积分
378
发表于 2005-12-18 12:10:00 | 显示全部楼层

Re:用窗口模式运行游戏

顶一个,现在很难看到有人谈ddraw窗口模式的处理。

72

主题

447

帖子

454

积分

中级会员

Rank: 3Rank: 3

积分
454
QQ
发表于 2005-12-29 13:31:00 | 显示全部楼层

Re:用窗口模式运行游戏

我没有用过ddraw,直接用的sprite,所以没有感觉要苛意的去设置窗口。

就按照普通的窗口设置好,把游戏绘制在窗口中就可以了啊~~
ddraw好像还要绘制桌面(未被窗口遮挡的部分),好消耗资源啊。sprite感觉不是这样的。只绘制窗口内部的部分。

20

主题

136

帖子

172

积分

注册会员

Rank: 2

积分
172
 楼主| 发表于 2005-12-31 19:35:00 | 显示全部楼层

Re: 用窗口模式运行游戏

我目前的代码已经使用AdjustWindowRectEx来设置 这样只需要在初始化的时候设置,真正调用的使用使用全局变量传过来RECT就完成了
还有我这些代码没有放置后备表面的裁剪区

10

主题

62

帖子

68

积分

注册会员

Rank: 2

积分
68
发表于 2006-4-29 10:26:00 | 显示全部楼层

看了“开发文档”中的帖子,实在忍不住了

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

我目前的代码已经使用AdjustWindowRectEx来设置 这样只需要在初始化的时候设置,真正调用的使用使用全局变量传过来RECT就完成了
还有我这些代码没有放置后备表面的裁剪区


万一用户修改屏幕分辨率呢?那时Windows会修改你的窗口大小的。

每次都需要计算的:
GetClientRect取得窗口客户区RECT
ClientToScreen将窗口坐标转为屏幕坐标
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2026-1-24 08:36

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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