您的位置:首页 > 编程语言

Windows编程 从消息窗口到基本窗口 游戏循环窗口框架的简单实现

2016-08-24 17:17 471 查看
版本:VS2015 语言:C++

 

本来想昨天写个消息窗口的内容,讲一些好玩的东西,不过没有时间了,就放到一起了。

 

今天正好把书的第二章看完了,感觉良好,Windows的编程确实难度要高,一下子会有一大堆的参数概念,但随着书本深入了解每个参数的含义,Windows编程大致的一些思路基本就出来了。

 

题外话,这本书绝对神书,游戏编程者都应该去看看,仅仅两个章节我就对整个游戏的循环有个大致的了解了,还有各类事件是如何进行处理的,从两个章节来看我第一次用Java编的贪吃蛇简直是渣渣,什么都没有,勉勉强强能够运行罢了。

 

首先来介绍一下一个最简单的窗口,打开VS2015,新建工程,把多余的代码删除,只留下一个返回的操作,然后在wWinMain函数中写下这样一行代码:

int i = MessageBox(NULL, TEXT("HELLO"), TEXT("TITLE"), MB_OKCANCEL | MB_ICONERROR);

运行效果:

 


 

红叉、HELLO、确定取消,该有的都有了。

1.第一参数hwnd:是父窗口的句柄,因为没有父窗口代表桌面,所以设置为NULL

2.第二参数lptext:正如所见是文本的内容
3.第三参数lpcaption:标题文本
4.第四参数utype:消息窗口的类型,就是有哪些按钮,我这边就设定了确定和取消两个按钮,并且如果点击确定和取消,外部的变量i还会获取到对应的值,有兴趣可以断个点看看
 
很简短对吧。关于类型能取一些什么值,我就不详细罗列了。
 
在正式玩基本窗口之前还有个好玩的东西就是MessageBeep,上面的是创建一个消息窗口,而这个是提示一个声音:
MessageBeep(MB_OK);	//win10中警告声音都一样了。。。


嗯,试一下就有声音了。注释的意思是不管你设置成什么参数,都是那个声音。怎么形容呢,反正起到了提示玩家的作用。
 
OK,用Ctrl+K,松开K再按一下C注释一下代码,我们开始正式学习Windows基本窗口的程序了。让我学一下红孩儿,直接发代码,在代码上注释:
// Win32Project1.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Win32Project1.h"

static int windowNum = 0;	//当前窗口的计数

// 消息处理函数,相当于cocos中的callback
LRESULT CALLBACK WindowProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM IParam)
{
switch (msg)
{
case WM_CREATE:	//创建消息
{
//初始化需要的资源
}
break;
case WM_DESTROY:	//WM_DESTROY是一个窗口销毁的消息,而WM_QUIT是退出应用程序的消息,也就是说一个应用程序可以包含0、1个或多个窗口
{
//窗口数量为0的时候发送结束应用程序的消息
if(0 == --windowNum)
PostQuitMessage(0);
}
break;
default:
DefWindowProc(hwnd, msg, wParam, IParam);	//自动处理其他的消息
}
return (1);
}

// 主函数,程序入口
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR    lpCmdLine,
_In_ int       nCmdShow)
{
// 来个消息框
//int i = MessageBox(NULL, TEXT("HELLO"), TEXT("TITLE"), MB_OKCANCEL | MB_ICONERROR);

// 来个声音
//MessageBeep(MB_OK);	//win10中警告声音都一样了。。。
//MessageBeep(0xFFFFFFFF);
//MessageBeep(MB_ICONASTERISK);
//MessageBeep(MB_ICONHAND);
//MessageBeep(MB_ICONQUESTION);

// 开始创建一个基本的窗口

// 创建窗口类
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = NULL;// CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;	//窗口的样式:改变宽度刷新、改变高度刷新、分配设备描述表、双击信息
wndclass.lpfnWndProc = WindowProc;	//回调函数
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	//图标
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);	//光标
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	//窗口背景
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TEXT("MyFirstWindow");	//窗口的名字
wndclass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);	//小应用图标
if (!RegisterClassEx(&wndclass))
return 0;

// 创建窗口,上面的窗口类是一个模版,可以根据上面的模版创建多个窗口,但请注意第二个参数
HWND hwnd = CreateWindowEx(NULL,//WS_EX_TOPMOST,	//窗口特性,注释里设置为永远在最上方显示
TEXT("MyFirstWindow"),	//窗口名称,一定要和窗口类的lpszClassName对应
TEXT("TITLE"),	//标题
WS_OVERLAPPEDWINDOW | WS_VISIBLE,	//窗口的样式
0, 0,	//左上角坐标
800, 600,	//宽高
NULL,	//父窗口句柄,如果是桌面则为NULL
NULL,	//菜单窗口句柄
hInstance,	//应用程序实例
NULL	//高级特性
);
if (!hwnd)	//创建失败返回
return 0;
++windowNum;	//窗口数量加1

ShowWindow(hwnd, nCmdShow);	//显示窗口
UpdateWindow(hwnd);	//刷新窗口

MSG msg;	//消息缓存

// 进入主循环
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))	//有消息事件,注意最后一个参数,如果设置为PM_NOREMOVE的话不会销毁消息队列中的消息
{
/* 这边详细说一下GetMessage和PeekMessage的区别:
* 1.首先说明,使用GetMessage是实现不了像游戏循环一样的效果的
* 2.GetMessage像是事件触发一下,有了消息马上运行;而PeekMessage会反复的检查消息队列
* 3.GetMessage,返回true代表消息不为WM_QUIT(退出应用程序的消息),返回false代表消息是WM_QUIT
* 4.PeekMessage,返回true代表有消息,false没有消息,像游戏这样每帧需要刷新的使用这个是最好的
*
*/

if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);	//转译消息
DispatchMessage(&msg);	//将消息发送给WindowProc函数处理
}
else	//没有消息
{
//GameMain()	//进入游戏的主循环
}
}

return msg.wParam;
}

最终结果:
 


 
嗯,看到这里想必大家对游戏需要怎样一个窗口循环都有所了解了吧。最好是把上面代码给打一遍,好记性不如烂键盘嘛。
 
在这一章的结束,书的作者说你已经成为Windows专家了,我当时内心只浮现了四个字——神TMD。不同同样想把这句话送给学完上述程序的玩家们,恭喜你已经完成了Windows的教程了!
 
至于作者的问题,创建两个窗口,只有在关闭两个窗口后才会退出应用程序。很简单,在我的程序中有个静态变量来表示当前窗口的数量,在关闭窗口后判断一下是否为0,再决定是否要关闭应用程序。
 
有想了解相关编程的玩家们,希望能跟我一起学习,能有个关注是最好的了,哈哈。我会隔几天发一下自己的学习总结,直到这本书学完。
 
总结(创建Windows窗口的步骤):
1.WNDCLASSEX创建模版的窗口类
2.CreateWindowEx创建窗口,需要注册别忘了
3.编写主循环
4.写回调函数
 
书上有一个写的很好,消息是这样往下传的:
PeekMessage -> TranslateMessage -> DispatchMessage -> 你的回调函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: