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



☆ 创建窗口

好消息创建窗口你所要做只是个CreateWindowEx坏消息是这个有好多参数嘿!把刀放下有话好说吗!真不难做事情总得走走形式嘛!以下是原形:

HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // poer to registered name
LPCTSTR lpWindowName, // poer to window name
DWORD dwStyle, // window style
x, // horizontal position of window
y, // vertical position of window
nWidth, // window width
nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu, or child-window identier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // poer to window-creation data
); 首先首先:返回值也就是类型是不是所有创建窗口用类型讨厌样子都感觉亲切了点儿?还没有?不要紧你会习惯肯定比你想象速度要快这里返回类型是HWND个窗口句柄(句柄就是窗口标识符)你将把CreateWindowEx返回值传递给个窗口句柄就像个参数现在我们来琢磨下这些参数很多根据名字就知道它是干什么
DWORD dwExStyle:扩充窗口风格你将很少使用扩充窗口风格所以多数时间你会把它设置为NULL如果有兴趣下帮助文件可以试由WS_EX_打头扩充风格
LPCTSTR lpClassName:还记得你窗口类名称吗?再用
LPCTSTR lpWindowName:将显示在窗口标题栏里简短文字
DWORD dwStyle:窗口风格它将允许你详细描绘你所要创建窗口风格有很多风格你可以利用哦都是以WS_打头你可以利用(|)符号组合利用它们我将在这儿介绍几个常用
◎ WS_POPUP 指定个弹出窗口
◎ WS_OVERLAPPED 指定个具有标题栏和边界重叠窗口
◎ WS_OVERLAPPEDWINDOW 指定个具有所有标准Control控件窗口
◎ WS_VISIBLE 指定时可见窗口
看得出WS_OVERLAPPEDWINDOW是个组合体简单你可以按照如下规律:如果你要创建个可以最大化、最小化、随意改变大小等等地窗口就选择WS_OVERLAPPEDWINDOW;如果你只想要个具有标题栏、可改变大小窗口就选择WS_OVERLAPPED;如果你只想要个光秃秃窗口就选择WS_POPUP;如果你只想显示个黑色大方框可能你要用它写个全屏游戏选择WS_VISIBLE是没错
x,y:你所要创建窗口左上角坐标
nWidth,nHeight:猜也猜到了窗口长和高单位是『象素』
HWND hWndParent:指向父窗口句柄你若想在窗口下再建立个窗口那么第个窗口就叫父窗口咱先建立个主窗口所以设置为NULL也就意味着Windows桌面是父窗口
HMENU hMenu:这是用在窗口上菜单句柄若你学会建立和使用资源即建立自己菜单你可以用LoadMenu自己菜单资源目前咱先设为NULL
HINSTANCE hInstance:是个名柄它指向由Windows传递给WinMain()例子
LPVOID lpParam:对于游戏编程来说没有什么用东西只有简单窗口用到它设置为NULL好了
同志们我们现在万事具备东风也有了我先给个举例:

HWND hwnd;
(!(hwnd = CreateWindowEx(NULL, // extended style, not needed
\"Sample Class\", // identier
\"Sample Window\", // window title
WS_POPUP | WS_VISIBLE,// parameters
0, 0, 320, 240, // initial position, size
NULL, // handle to parent (the desktop)
NULL, // handle to menu (none)
hinstance, // application instance handle
NULL))) // who needs it?
(0);

你可能会在游戏编程中用上这这段代码它是个弹出式窗口注意我用了形式旦CreateWindowsEX()失灵返回个NULL也就意味着如果窗口由于某种原因不能被建立那么WinMain()就被简单返回结束
现在我们学会了足够知识建立个小有功能窗口了还记得我们建立窗口类“sample ”时个指向“CALLBACK”类型指针吗?对是“lpfnWndProc”要想让你窗口真正做点事儿我们还得来处理下它指向“窗口过程”

☆ 显示窗口
CreateWindowEx从内部创建窗口但并不显示它要显示这个窗口必须另外两个:ShowWindow和UpdateWindow个设置窗口显示状态个则更新窗口客户区对于主窗口ShowWindow必须被代码如下:

ShowWindow(hwnd,nCmdShow);

个参数是由CreateWindowEx返回窗口句柄;第 2个参数就是窗口显示模式参数在☆WinMain中提到过就不重复了UpdateWindow代码如下:

UpdateWindow(hwnd);

参数hwnd同ShowWindowhwnd

☆ 消息处理
我已经说过消息在窗口里作用了下面让我们来仔细学习下它处理消息结构如下:

LRESULT CALLBACK MsgHandler( 【有时被命名为WndProc随便你】
HWND hwnd, // window handle
UINT msg, // the message identier
WPARAM wparam, // message parameters
LPARAM lparam // more message parameters
);



这个LRESULT类型要求返回个32位整数实际取值依赖于消息但是这个值很少在应用代码中得到应用以前我们谈到过点CALLBACK协定参数很简单:
HWND hwnd:是接收消息窗口句柄也是由CreateWindowEx()返回句柄
UINT msg:这是个消息标识符都是以WM_打头符号常量意思是“Windows Message”很多这里只介绍些常用:
◎ WM_ACTIVATE:个新窗口被激活
◎ WM_CLOSE:个窗口被关闭
◎ WM_COMMAND:个菜单功能被选择
◎ WM_CREATE:个窗口被建立
◎ WM_LBUTTONDBLCLK:鼠标左键被双击
◎ WM_LBUTTONDOWN:鼠标左键被按下
◎ WM_MOUSEMOVE:鼠标被移动
◎ WM_MOVE:个窗口被移动
◎ WM_PAINT:窗口部分需要重画
◎ WM_RBUTTONDBLCLK:鼠标右键被双击
◎ WM_RBUTTONDOWN:鼠标右键被按下
◎ WM_SIZE:窗口大小被改变
◎ WM_USER:干你想干
WPARAM wparamLPARAM lparam:消息参数它们提供有关消息附加信息这两个值对于每条消息来说都是特定
你要把所有要发生消息都写进代码我想你可能已经累疯了我想我会感谢上帝Windows提供了默认消息处理如果你没有任何特殊消息需要处理了你总是要用DefWindowPorc下面给个最简单例子没有任何特定消息要处理例子:

LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
(DefWindowProc(hwnd, msg, wparam, lparam));
}

简单吧!但通常你都需要处理些自己消息你要写自己代码然后返回0来告诉你干完了下面是个例子当窗口建立时Initialize_Game然后返回0最后告诉自己处理那些默认消息吧:

LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
(msg WM_CREATE)
{
Initialize_Game;
(0);
}

(DefWindowProc(hwnd, msg, wparam, lparam));
}

你很可能需要个“switch”结构来手动完成你想要控制消息然后把剩下交给DefWindowProc去做大功告成前我不得不提醒您件事就是怎样使你消息控制得到响应呢?

☆ 读取消息队列
我先给你个switch结构例子吧:(感性)

LRESULT CALLBACK MsgHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
WM_CREAT:
[化游戏]
0;
WM_PAINT:
[画架飞机]
0;
……………………
……………………
}

(DefWindowProc(hwnd, msg, wparam, lparam));
}

在进入主循环前你需要看看你消息控制(就是你在switch结构里编那些)尤其是还没有用到消息控制是否被机器存了起来以备旦用到马上响应做到正确响应你需要做几件事首先你需要PeekMessage下面是它原形:

BOOL PeekMessage(
LPMSG lpMsg, // poer to structure for message
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax, // last message
UINT wRemoveMsg // removal flags
);

这是个布尔类型也就是不过只有两个值TRUE和FALSE如果有条消息在队列中等待返回TRUE否则返回FALSE参数很简单:
LPMSG lpMsg:这是个MSG类型指针变量如果有消息在等待消息信息将被填入该变量
HWND hWnd:你所要检查消息队列窗口句柄
UINT wMsgFilterMinwMsgFilterMax:索引第个和最后个消息般你都从第个消息开始检索所以把它们都设置为0好了
UINT wRemoveMsg:般来说它有两个指PM_REMOVE或者PM_NOREMOVE使用前者会在消息被读取后从队列中移除后者是继续保留通常我们选择前者PM_REMOVE
真正处理消息时你需要做两件事很简单件是TranslateMessage第 2件是DispatchMessage它们原形很相似:

BOOL TranslateMessage(CONST MSG *lpmsg);
LONG DispatchMessage(CONST MSG *lpmsg);

个是把消息翻译过来第 2个是从MSG结构中相应信息你只需要知道这么多伴随着主循环反复执行如果有消息出现你就这两个MsgHandler会安排好下面是个例子:

(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))【现在有时用GetMessage(&msg,NULL,0,0)】
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

没问题你现在完全可以写个窗口不坏吧?在结束本章前我还有几点要提醒你还记得我们在谈论☆消息时,说要在后面进步讨论它吗?你忘了?我可没有忘记怎样主动向Windows发送消息呢?

☆ 发送消息
有两种办法可以做到PostMessage或SendMessage它们原形很相似:

BOOL PostMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);

LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);



它们参数相同并且和前面讲过MsgHandler()参数功能相同就不重复了我只谈谈它们的间区别
PostMessage被经常用来向队列中加入消息成功返回TRUE否则返回FALSE它只是简单把消息加入到队列中然后返回多数情况下它将返回TRUE
SendMessage则有些区别它并不是把消息加入到队列里而是直接翻译消息和消息处理直到消息处理完成后才返回所以SendMessage比PostMessage有更高应急性你想立刻干事情就应该
消息是DOS和Windows编程的间重要区别标志

流程
在DOS中我们不必担心消息这种东西不必担心多个同时运行但在Windows里你必须考虑这些在Windows平台上编程些区别于DOS下编程地方让我们看看下面这段虚拟代码:

// game loop
do
{
// handle messages here

// ...

// update screen necessary
(_screen)
{
FadeOut;
LoadNewMap;
FadeIn;
}

// perform game logic
WaitForInput;
UpdateCharacters;
RenderMap;

} while (game_active);

假设FadeOut这样工作:当秒内屏幕图象暗淡下来当屏幕完全黑了返回LoadNewMap个新图象;FadeIn使屏幕逐渐亮起来好显示新图象当有键子按下WaitForInput再继续下去这在DOS游戏编程里是合情合理但在Windows下不行
为什么呢?让我们看看新画面诞生过程画面逐渐变黑图片逐渐恢复这大概要2秒钟用户可以等待也可能要移动下窗口只专心图片工作不会对窗口移动作出反应这是很糟糕你干了机器不知道事情这可能导致系统崩溃我们必须要让机器对用户任何操作作出正确反应不多说了总的你要换换脑筋如果你从来就没在DOS下编过那正好你赶上潮流了!

☆ 整理总结
本章我们讲了Windows编程基础虽然只是个空白窗口但包含了最基本东西章我们将学习创建资源和利用资源你就可以用有自己风格光标、图标、声音、菜单等等还要生成个EXE文件呢!
待续



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

延伸阅读

最新评论

发表评论