C++游戏之创建第一个窗体程序(一)

       说起游戏,大家都不陌生,大家很快就能想到LOL,DNF,QQ炫舞啊等一系列热门网游,那么它们是如何开发出来的呢?不得不说,这里面涉及到的东西太多太多,其中有:计算机图形学,计算机物理,计算机碰撞检测,计算机多媒体处理,计算机网络技术等。那么如今游戏开发都用什么语言呢?当然非C++莫属,为什么呢?不解释,好了,我们就从最简单的图形GDI开始吧(什么是GDI?下一章介绍)。 (PS:本文内容均为个人理解学习,获取有误 - - !)

   

        做游戏首先得有一个窗体吧,那么这节我们就简单的来创建一个窗体吧,怎么创建呢?可能你会想到MFC,但是这里我们不用它,为什么呢?因为它包含了很多对于游戏来说没有用的东西,影响效率。那么我们该怎么创建呢?


        我们先来认识一下主函数吧,你可能马上会想到int main(){}函数,但是这里不是,他是windows窗体,所以主函数为WinMain函数,该函数的功能是被系统调用,作为一个32位应用程序的入口点。

//WinMain入口函数 
//第一个参数为当前窗体实列
//第二窗体为父窗体实列
//第三个参数为传递给应用程序的命令行参数
//第四个参数指明窗口如何显示
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrivInstance,LPSTR lpCmdLine,int nShowCmd)
{}



创建一个窗口的步骤如下:
第一步:设计窗体
第二步:注册窗体
第三步:创建窗体
第四步:显示与更新
第五步:窗体消息队列
第六步:窗体过程函数


一,设计窗体:

	WNDCLASSEX wndClass = {0};//描述窗口的结构体,{}表示初始化这个结构体的一个参数,就像创建一个对象需要new一样,不然就变成声明了
	wndClass.style = CS_HREDRAW | CS_VREDRAW;//窗体被上下左右拉伸时重新绘制
	wndClass.cbSize = sizeof(WNDCLASSEX);//结构体大小
	wndClass.cbClsExtra = 0;//类的附加内存,一般为0
	wndClass.cbWndExtra = 0;//窗体的附加内存,一般为0
	wndClass.hInstance = hInstance;//窗体的实列
	wndClass.hIcon = (HICON)LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);//窗体的图标文件,必须为ico格式的
	wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);//窗体的光标
	wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);//窗体的背景颜色
	wndClass.lpszClassName = L"wndClass";//结构体名称
	wndClass.lpszMenuName = 0;//指定菜单资源的名字
	wndClass.lpfnWndProc = WndProc;//窗体的过程函数


二,注册窗体

        通过RegisterClassEx函数来注册我们已经设计好的窗体,注册成功返回true,失败时,返回false

//注册窗体,如果注册失败,返回-1
if (!RegisterClassEx(&wndClass))
{
	return -1;
}


三,创建窗体

       通过CreateWindow函数来创建窗体,创建成功,返回HWND窗口句柄,失败,返回NULL

	HWND hWnd = CreateWindow(L"wndClass",//结构体的名称,也就是Name属性
		L"This is a Windows!",//窗体的标题
		WS_OVERLAPPEDWINDOW,//窗体的层叠样式,通常为<span style="font-family: Arial, Helvetica, sans-serif;">WS_OVERLAPPEDWINDOW</span>
		CW_USEDEFAULT,//窗口位置,X坐标,可以给具体的的值,一般为CW_USEDFAULT即可
		CW_USEDEFAULT,//窗口位置,Y坐标,可以给具体的的值,一般为<span style="font-family: Arial, Helvetica, sans-serif;">CW_USEDFAULT即可</span>
		800,//窗口的宽
		600,//窗口的高
		NULL,//窗体的父窗体,为NULL,意思就是如果一个窗体打开两次,那么第一次的就是父窗体
		NULL,//<span style="font-family: Arial, Helvetica, sans-serif;">窗体的菜单资源,这里给NULL,表示没有</span>
		hInstance,//窗体的实列,直接给WinMain函数里面的参数就行了
		NULL);//附加参数,为NULL就好了

四,显示与更新

       通过前面的步骤,我们已经可以显示窗体了,通过ShowWindow函数,它有两个参数,第一个是窗体的句柄HWND,第二个也就是显示状态,这个参数直接给WinMain函数里面的参数就行了。通过UpdateWindow更新窗体,它有一个参数,即窗体句柄HWND

<pre name="code" class="cpp">	//显示与更新
	ShowWindow(hWnd,nShowCmd);
	UpdateWindow(hWnd);
 

五,窗口消息队列

        顾名思义,它是用来获取窗体的操作信息的,比如拖动,重绘,键盘,鼠标的操作等信息。通过PeekMessage函数读取消息队列,它有5个参数

	//读取窗体消息队列
	MSG msg = {0};//描述消息队列的结构体
	while (msg.message!=WM_QUIT)//判断是否退出程序,如果没有退出,就一直循环读取消息
	{
		if (PeekMessage(&msg,//存消息信息的结构体
			0,//窗体的句柄,0表示获取所有消息
			0,//消息最小值,为0即可
			0,//消息最大值,为0即可
			PM_REMOVE)//读取后,如果存在,发送消息,并移除该条信息
			)//读取消息
		{
			TranslateMessage(&msg);//将虚拟键消息转换为字符消息
			DispatchMessage(&msg);//把这个消息发给窗口程序
		}
	}


六,窗口过程函数

        前面有了消息队列,那么读取的消息在哪里处理呢?比如拖动,重绘,键盘按下,鼠标点击等,对,就是这个过程函数,它是负责处理消息队列发送过来的消息的。


//窗口过程函数处理
//第一个参数,窗体的句柄
//第二参数,消息ID(比如重绘,键盘按下等)
//第三个参数与第四个参数为附加消息
//通常我们通过第三个参数可以知道用户按下了某个键,或抬起某个键
//第四个参数通常用作取鼠标的XY坐标
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wparam,LPARAM lparam)
{
	switch(message)//根据消息ID判断需要处理的消息
	{
	case WM_PAINT://重绘窗体
		ValidateRect(hWnd,NULL);//使整个窗体的无效区变成有效区,第一参数为窗体句柄
		                        //第二参数为NULL,表示所有区域,也可以是Rect的一个结构体,来限定窗体的有效区的区域
		break;
	case WM_DESTROY://窗口的关闭消息
		PostQuitMessage(0);//退出程序
		break;
	default://如果没有需要处理的消息,就调用默认的过程函数
		return DefWindowProc(hWnd,message,wparam,lparam);
	}
	return 0;
}

有了以上步骤,一个窗体就算是完成创建了。下面是完整代码:


#include <Windows.h>

//过程函数的声明
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wparam,LPARAM lparam);
//入口函数 
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrivInstance,LPSTR lpCmdLine,int nShowCmd)
{
	//设计窗体
	WNDCLASSEX wndClass = {0};
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = (HICON)LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE);
	wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wndClass.lpszClassName = L"wndClass";
	wndClass.lpszMenuName = 0;
	wndClass.lpfnWndProc = WndProc;

	//注册窗体
	if (!RegisterClassEx(&wndClass))
	{
		return -1;
	}

	//创建窗体
	HWND hWnd = CreateWindow(L"wndClass",
		L"This is a Windows!",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		800,
		600,
		NULL,
		NULL,
		hInstance,
		NULL);

	//显示与更新
	ShowWindow(hWnd,nShowCmd);
	UpdateWindow(hWnd);

	//读取窗体消息队列
	MSG msg = {0};//描述消息队列的结构体
	while (msg.message!=WM_QUIT)//判断是否退出程序,如果没有退出,就一直循环读取消息
	{
		if (PeekMessage(&msg,//存消息信息的结构体
			0,//窗体的句柄,0表示获取所有消息
			0,//消息最小值,为0即可
			0,//消息最大值,为0即可
			PM_REMOVE)//读取后,如果存在,发送消息,并移除该条信息
			)//读取消息
		{
			TranslateMessage(&msg);//将虚拟键消息转换为字符消息
			DispatchMessage(&msg);//把这个消息发给窗口程序
		}
	}

	UnregisterClass(L"wndClass",hInstance);
}

//窗口过程函数处理
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wparam,LPARAM lparam)
{
	switch(message)//根据消息ID判断需要处理的消息
	{
	case WM_PAINT://重绘窗体
		ValidateRect(hWnd,NULL);
		break;
	case WM_DESTROY://窗口的关闭消息
		PostQuitMessage(0);
		break;
	default://如果没有需要处理的消息,就调用默认的过程函数
		return DefWindowProc(hWnd,message,wparam,lparam);
	}
	return 0;
}


运行效果图:







评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值