《Windows游戏编程⼤师技巧》三、Windows⾼级编程Windows编程很绝的地⽅在于:你不⽤了解太多细节,就可以完成很多⼯作。
使⽤资源
资源就是你的程序代码结合在⼀起的多块数据,可以被程序本⾝在运⾏时加载。
资源应当也放在程序的.EXE⽂件中的原因是:
1.同时包含代码和数据的.EXE⽂件更容易发布。
2.外⼒不容易任意删改程序的数据⽂件(如.BMP和.WAV⽂件)。
对于想编译进程序中的数据类型没有限制,下列这些预定义的资源类型就可以
满⾜⼤部分需要:
图标 - ⼩的位图⽂件
光标 - ⿏标指针的位图
字符串 - 可以硬编码在代码中,也可以集中放在这
声⾳ - ⼤部分Windows程序都使⽤.WAV格式
位图 - 这是标准的位图,使⽤.BMP扩展名
对话框 - 也可以作为资源来存储
图元 - ⼀系列图像操作记录的回放
要添加资源⽂件,必须有⼀个以ASCII形式的资源描述⽂件.RC。编译过程如下:
下⾯是如何在.RC脚本⽂件中定义⼀个ICON资源:
windowicon ICON star.ico (使⽤字符串)
124 ICON ship.ico (使⽤数字)
使⽤字符串定义时会产⽣歧义,windowicon可能是个字符串也可能是个#define定义的符号常量。
所以还需要⼀个.H⽂件来解析符号索引。
RESOURCES.H的内容:
#define ID_ICON1 100
#define ID_ICON2 101
#define ID_ICON3 102
RESOURCES.RC的内容:
#include "RESOURCES.H"
ID_ICON1 ICON star.ico
ID_ICON2 ICON ball.ico
ID_ICON3 ICON cross.ico
现在,将RESOURCES.RC和.ICO⽂件添加到⼯程,并在程序中#include RESOURCES.H。
若使⽤字符串定义,则:winclass.hIcon = LoadIcon(hInstance, "icon_name");
若使⽤符号索引,则:winclass.hIcon =LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON1));
注意第⼀个参数不再是NULL⽽是hInstance。
其他资源也都是类似这样定义和使⽤的。
光标:LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR1));
字符串表: LoadString(hInst, IDS_STRING109, string3, 20);
GDI简介
应该了解GDI,以便知道如何在不使⽤DirectX的情况下如何在Windows环境绘制各种图形。
⽽理解WM_PAINT消息对于标准的GDI图形和Windows编程来讲是⾮常重要的,因为⼤部分Windows程序的显⽰都围绕该消息。例外是游戏编程中DirectDraw或Direct3D负责图形绘制。
PAINTSTRUCT ps; // used in WM_PAINT
HDC hdc; // handle to a device context
case WM_PAINT:
{
// simply validate the window
hdc = BeginPaint(hwnd, &ps);
// do all your painting here
EndPaint(hwnd, &ps);
// return success
return (0);
}
参看下⾯图⽰,当⼀个窗⼝被移动、改变⼤⼩或被其他窗⼝“弄脏”时,该窗⼝的⽤户区的
部分或全部需要重画。这时,WM_PAINT消息就被发送了。
对BeginPaint()和EndPaint()函数的调⽤可以完成⼀系列任务。⾸先,它们使⽤户区有效;
其次,它们⽤该窗⼝创建时参照的Windows类中定义的背景刷来填充该窗⼝的背景。
你只能访问实际上需要刷新的该窗⼝⽤户区的⼀部分。⽆效矩阵区域的坐标都保存在
BeginPaint()函数返回值PAINTSTRUCT的rcPaint字段中。如果要访问整个⽤户区的话,
这就是⼀个问题。解决⽅法是通过GetDC()直接获得图形设备描述表。
但BeginPaint()-EndPaint()会向Windows发消息指⽰窗⼝有效,⽽GetDC()-ReleaseDC()不会,所以WM_PAINT消息将⼀直不停地传递下去,因为必须使该窗⼝有效。因此在ReleaseDC()
后还要调⽤ValidateRect()。
PAINTSTRUCT ps;
HDC hdc;
RECT rect;
case WM_PAINT:
{
// simply validate the window
hdc = GetDC(hwnd);
// do all your painting here
ReleaseDC(hwnd, hdc);
// get client rectangle of window
GetClientRect(hwnd, &rect);
// validate window
ValidateRect(hwnd, &rect);
// return success
return(0);
}
注意GetClientRect是⽤来获取⽤户矩形区域的坐标。每个窗⼝都有两套坐标系:
mousemove是什么键
Windows坐标系和⽤户坐标系。区别见下图:
你很可能会说:“⾮得这么⿇烦吗”是的,⾮得如此,因为这是Windows。哈哈!
本书的⼤多数例程⾥,将在WM_PAINT消息以外的地⽅使⽤GetDC()-ReleaseDC(),BeginPaint()-EndPaint()只⽤于WM_PAINT消息句柄中。
基本⽂本显⽰
Windows有最复杂且最强悍的⽂本渲染系统。当实际运⽤在实时游戏中时,⽤GDI⽂本
引擎输出⽂本就显得太慢了,还是要亲⼿设计基于DirectX的⽂本引擎。但先了解下有助于
调试和输出。
输出⽂本有两个常⽤函数:TextOut()和DrawText()。TextOut()是⼀个寒酸的⽂本输出函数,⽽DrawText()则像凌志汽车⼀样豪华。我经常使⽤TextOut()因为它运⾏⽐较快。
case WM_PAINT:{
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
char buffer[50];
static int counter = 0;
sprintf(buffer, "WM_PAINT called %d times ", ++counter);
TextOut(hdc, rect.left, p, buffer, strlen(buffer));
DrawText (hdc, TEXT (“Hello text”), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
}
========================================================== 2012年4⽉22⽇ 更新
补充学习处理重要事件:Window操作、键盘操作、⿏标操作。
1.Window操作
WM_CLOSE消息在WM_DESTROY和WM_QUIT之后发送,它表⽰⽤户正试图关闭窗⼝。
如果在WinProc()⾥仅return (0),那么⽤户不能关闭窗⼝。WM_SIZE消息对于窗⼝游戏
⾮常重要,当窗⼝尺⼨改变时,必须调整图像显⽰来适应。
2.键盘操作
在Windows环境下,可以以多种⽅式访问键盘消息:
2.1 通过WM_CHAR消息:保存产⽣的ASCII码,如'a'或'A',字处理程序要关⼼这个。
2.2 通过WM_KEYDOWN/UP消息:保存产⽣的扫描码,即键盘上每⼀个按键的编码,
如ESC键VK_ESCAPE。游戏只需关⼼WASD移动,F开⽕⽽不必关⼼产⽣的是⼤写字符
还是⼩写字符,所以不必关⼼WM_CHAR消息。
2.3 通过调⽤GetAsyncKeyState():在状态表中跟踪该键的最后已知状态,使⽤它的
妙处是它与事件循环没有耦合,可以在任何地⽅测试按键。
3.⿏标操作
⿏标移动事件WM_MOUSEMOVE。lParam保存⿏标位置,wParam保存按键状态。
case WM_MOUSEMOVE:
{
int mouse_x = (int) LOWORD(lParam);
int mouse_y = (int) LOWORD(lParam);
int buttons = (int) wParam;
if (buttons & MK_LBUTTON)
...
if (buttons & MK_RBUTTON)
...
} break;
⿏标只是移动没有按键产⽣的事件。
case WM_LBUTTONDBLCLK:
{
int mouse_x = (int) LOWORD(lParam);
int mouse_y = (int) LOWORD(lParam);
...
// tell windows you handled it
return (0);
} break;
4.⾃⾏发送消息
⾃⾏传递消息有两种⽅法:
SendMessage()向窗⼝传递⼀个要求⽴即处理的消息。
PostMessage()将消息发往窗⼝的消息队列。
为什么要⾃⾏发送消息?因为Window的设计者希望你这样做,这也是窗⼝环境下的⼯作原理。下⼀章中学习按键控件时将会看到,发送消息是和控件窗⼝交流的唯⼀途径!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。