编程初学者:游戏编程起源(初学者)Ⅳ



串表

串表是我最喜欢资源类型正象你所想:个充满庞大表格串表有很多用处你可以用它存储你文件名称游戏中人物对话消息框中文本菜单中文本等等在资源脚本里建立串表很容易就像这样:

STRINGTABLE
{
// entries go here
}

串表由几部分组成:个标识数字;紧跟着个逗号;然后是加了双引号串本身串表里串被允许使用溢出符号
注意串表本身并没有标识符所以每个只能有串表个简单串表可能象下面这个样子:

// program information
STRINGTABLE
{
1, \"3D Space Game v1.0\"
2, \"Written by The Masked Coder\"
3, \"(C) 2000 WienerDog Software\"
} 从串表里将使用——你可能猜到了——LoadString这是它原形:

LoadString(
HINSTANCE hInstance, // handle to module containing resource
UINT uID, // resource identier
LPTSTR lpBuffer, // poer to buffer for resource
nBufferMax // size of buffer
);

返回实数是数量不包括空它将被赋值到数据段缓冲区中去相当于长度如果你个空串或者失败都将返回0下面来看看具体参数:
HINSTANCE hInstance:同以前你所有操纵项目句柄
UINT uID:你想要数码标识符
LPTSTR lpBuffer:指向接收指针
nBufferMax:缓冲区字节长度如果被长度大于缓冲区长度串将被按照缓冲区大小缩减
例如“WienerDog Software’s copyright”信息代码应该如下:

char buffer[80];
LoadString(hinstance, 3, buffer, (buffer));

尽管在资源脚本中串使用数字声明而不是标识符但我通常在使用串表时习惯于在头文件中用#定义声明数字针对上面代码我可能加行:

# ST_WIENERDOGCOPYRIGHT 3

这样用LoadString代码更容易读懂也使你思路更加清晰但也并不是意味着你必须为串表里串都定义个常量标识符串表相当大时或者你感觉记不清时就应该定义常量标识符我通常在每个常量标识符前面加上个前缀ST_具体ST_FILENAMES作为存储文件名称索引ST_DIALOGUE作为人物对话索引等等

☆ 菜单
这是我们要讲最后个Windows资源当然不是为了凑数才讲窗口菜单条紧接在标题栏下发显示这个菜单有时被称为“主菜单”或“顶层菜单”菜单通常在建立窗口类时被还记得吗?上章中窗口类建立过程中有这样行:
sampleClass.lpszMenuName = NULL;
如果你正在建立个窗口并希望有菜单你就得需要用到菜单资源脚本文件可能要复杂点儿但下面是个最基本框架:

[identier] MENU
{
POPUP [menu name]
{
MENUITEM [item name], [identier]
}
}

[identier]标识符是你知道:串或个数字常量在MENU大括号中可以有个或者几个POPUP(弹出式)菜单个都有个下拉菜单[menu name]中填入菜单名称在POPUP大括号中可以有个或者多个菜单条[item name]中填入菜单条名称后面必须跟着个数字常量标识符(所谓数字常量标识符就是用#定义过标识符如:# MENUID_NEW 101)如果你还想在菜单里建立热键就要用(&)符号在你想成为热键前加上&例如你想用Alt+F代替用鼠标点击File按钮你就应该写成 &File 菜单名称都要用双引号引上看看下面例子就更清楚了:

MAIN_MENU MENU
{
POPUP \"&File\"
{
MENUITEM \"&New\", MENUID_NEW
MENUITEM \"&Open...\", MENUID_OPEN
MENUITEM \"&Save\", MENUID_SAVE
MENUITEM \"Save &As...\", MENUID_SAVEAS
MENUITEM \"E&xit\", MENUID_EXIT
}

POPUP \"&Help\"
{
MENUITEM \"&Contents\", MENUID_CONTENTS
MENUITEM \"&Index...\", MENUID_INDEX
MENUITEM \"&About\", MENUID_ABOUT
}
}

你还可以在POPUP下建立子菜单你自己琢磨吧我就不讲了我们还得往下进行获得菜单资源句柄我们需要用LoadMenu原形如下:

HMENU LoadMenu(
HINSTANCE hInstance, // handle to application instance
LPCTSTR lpMenuName // menu name or menu-resource identier
);

现在你应该已经熟悉这些参数了个参数是你例子句柄第 2个是你菜单资源标识符如果你使用了数字常量作为标识符别忘了使用MAKEINTRESOURCE这个宏转换下哦!现在你有两个思路方法为窗口创建菜单个思路方法是在创建窗口类时直接设置:

sampleClass.lpszMenuName = LoadMenu(hinstance, MAKEINTRESOURCE(MAIN_MENU));

第 2个思路方法是在设置窗口类时让lpszMenuName等于NULL以后再加入菜单当你要建立两个独立菜单而又不想定义区别窗口类时这个选择是很有意义你需要用SetMenu():



BOOL SetMenu(
HWND hWnd, // handle to window
HMENU hMenu, // handle to menu
);

如果创建菜单功能实现了将返回TRUE否则返回FALSE参数是很容易理解:
HWND hWnd:是你所要创建菜单那个窗口句柄也就是你在CreateWindowEx时产生那个窗口句柄
HMENU hMenu:识别菜单使用它形式是:hMenu=LoadMenu(hInstance,菜单标识符)所以它得到是LoadMenu()返回菜单句柄如果给它赋值NULL指定窗口菜单将被移除
资源是个好东西它使我们很容易就生成了菜单但是当我们点击了菜单上选项将会发生什么呢?答案是Windows将会发出个WM_COMMAND消息给再让Windows作出相应反应让我们具体看看吧!

☆ 控制菜单事件
你可能记得Windows消息都是通过CALLBACK控制通常它是这个样子:WindowProc或类似样子我们在上章中用到是这个样子:MsgHandler原形如下:

LRESULT CALLBACK MsgHandler(
HWND hwnd, // window handle
UINT msg, // the message identier
WPARAM wparam, // message parameters
LPARAM lparam, // more message parameters
};

个菜单消息被送到msg将等于WM_COMMAND所选择菜单项目将被包含进wparam这就是为什么菜单标识符不能是原因它需要适合wparam参数更特别菜单标识符只占用wparam低位字WPARAMLPARAM等都是32位分高、低位字变量Windows提供了宏LOWORD()和HIWORD()分别来提取变量中低位字和高位字原形如下:

# LOWORD(l) ((WORD) (l))
# HIWORD(l) ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))

LOWORD实际情况是由于简单定义为WORD就自然取得了低端16位HIWORD把高端16位向右移然后同0xFFFF的间了逻辑“和”(AND)确保把高于16位字节变为0可能你不太熟悉>>和<<操作符号它们是位移操作符“<<”操作符把变量中个字节中数字向左移动“>>”就是向右移动例如我们有个16位变量x值是224 2进制表示为0000 0000 1111 0100下面是个有关位移例子:

x = 244, y;
y = x << 4;

Contents(内容) of x: 0000 0000 1111 0100
Contents (内容)of y: 0000 1111 0100 0000

总的使用LOWORD宏你得到了wparam低端字也就是说你得到了被选择菜单ID(标识符)所以在你MsgHandler你应该这样做:

// handle menu selections
(msg WM_COMMAND)
{
switch (LOWORD(wparam))
{
MENUID_NEW:
// code to handle File->New goes here
;
MENUID_OPEN:
// code to handle File->Open goes here
;

// the rest of the option handlers go here

}

// tell Windows you took care of it
(0);
}

当然还有些其它资源类型如加速表(快捷键)、HTML页、WAV文件等但我想以上这些是最有用最要紧学习在结束的前我还要告诉你Windows编程大强力特色——定制自己资源类型

☆ 定制资源
标准资源给我们带来了很大方便但不仅仅是这些标准类型你还可以创建自己资源类型资源可以是你希望任何种数据使用自己定制资源需要多付出点劳动你必须手工定位和读取资源数据比想象要容易你已经习惯了定义资源格式:

[identier] [resource type name] [filename]

[resource type name]资源类型名称是让你命名还是举例介绍说明吧:假设我们要用到plconfig.dat文件作为资源它包含化游戏人物必需信息我们将把它定义为CHARCONFIG资源类型脚本文件应该是这个样子:

DATA_PLAYERINIT CHARCONFIG p1config.dat

很简单是不是?现在你已经拥有了数据(plconfig.dat)你还必须分 3步使个指针指向资源数据这包括我们还没有提到过需要让我们起解决我们必须FindResource去发现资源原形如下:

HRSRC FindResource(
HMODULE hModule, // module handle
LPCTSTR lpName, // poer to resource name
LPCTSTR lpType // poer to resource type
);

返回值是个资源信息块儿句柄如果失败返回NULL参数意义如下:
HMODULE hModule:HMODULE相当于HINSTANCE不要问我为什么换了另个名字你只要把你例子句柄传送给它就好了你不需要什么类型转换它们是相同
LPCTSTR lpName:这个是资源标识符如果你使用了数字常量作为标识符别忘了使用MAKEINTRESOURCE
LPCTSTR lpType:这个是资源类型你需要把你定义资源类型名称串传递给它我们是CHARCONFIG
方式如下:

HRSRC hRsrc = FindResource(hinstance, MAKEINTRESOURCE(DATA_PLAYERINIT), \"CHARCONFIG\");



这是信息块儿所在资源句柄步是要得到指向数据指针需要把句柄传递给LoadResource数据这将产生个资源本身句柄下面是原形:

HGLOBAL LoadResource(
HMODULE hModule, // resource-module handle
HRSRC hResInfo // resource handle
);

返回类型HGLOBAL是个普通句柄类型是相对于我们说过那些HBITMAP或HICON等句柄类型如果失败将返回NULL参数解释如下:
HMODULE hModule:老东西例子句柄
HRSRC hResInfo:把FindResource得到句柄传递给它
现在我们有了资源句柄就可以得到指向数据(自定义)指针了这需要LockResource来完成原形如下:

LPVOID LockResource(HGLOBAL hResData);

仅仅把LoadResource得到句柄传递给它就万事大吉了如果返回值是NULL介绍说明失败否则我们就得到梦寐以求指针!现在我们可以自由得处理数据了注意:返回类型是LPVOID(相当于void*)所以若你想把指针指向队列符号你还要注意转换成类似BYTE*型哦!现在我们完成了所有步骤这里我将展示给你个指针指向特殊资源例子:

UCHAR* LoadCustomResource( resID)
{
HRSRC hResInfo;
HGLOBAL hResource;

// first find the resource info block
((hResInfo = FindResource(hinstance, MAKEINTRESOURCE(resID), \"CUSTOMRESOURCETYPE\")) NULL)
(NULL);

// now get a handle to the resource
((hResource = LoadResource(hinstance, hResInfo)) NULL)
(NULL);

// finally get and a poer to the resource
((UCHAR*)LockResource(hResource));
}

☆ 整理总结
好了以上就是有关资源部分Windows编程比想象容易吧学了这么多好像还是不能做什么所以我将向你介绍些基本Windows图形设备接口你就可以利用我们所学过所有东西作点作品出来了



Tags:  网络游戏的起源 网络游戏起源 游戏的起源 编程初学者

延伸阅读

最新评论

发表评论