游戏编程代码大全,DirectX_11_游戏编程入门_1

 2023-09-22 阅读 14 评论 0

摘要:第一个DirectX程序 1.创建工程 2.建立窗口程序 3.初始化DirectX 4.怎样清除屏幕 5.怎样显示场景 一、创建工程 1.创建工程:C++建立项目 2.添加窗体代码:main函数 在工程中创建好main函数后,我们就能够添加Win32的具体实现代码来创建空窗体࿰

第一个DirectX程序
1.创建工程
2.建立窗口程序
3.初始化DirectX
4.怎样清除屏幕
5.怎样显示场景

一、创建工程
1.创建工程:C++建立项目
2.添加窗体代码:main函数
在工程中创建好main函数后,我们就能够添加Win32的具体实现代码来创建空窗体,进入主函数入口之后,我们将创建初始化D3D11并且使用D3D渲染窗体画布。

主函数入口点
在main.cpp中需要做的第一件事是包括Win32程序所需要的头文件和定义函数入口点。需要注意的是,Win32窗体应用程序的主函数入口点是WinMain函数(控制台程序的入口点是main函数)。对于现在来说我们只需要在源文件的顶部包括Windows.h头文件即可。在源文件main.cpp的头文件和空的WinMain函数见于程序清单2.1.
清单2.1
空的WinMain函数

#include<Windows.h>
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPWSTR cmdLine, int cmdShow)
{return 0;
}

代码清单2.1能看出我们使用wWinMain代替WinMain。这两个主函数的不同在于wWinMain的第三个参数cmdLine使用的是Unicode编码,而WinMain使用的是ANSI编码,它将会转换Unicode为ANSI。因此导致Unicode字符串中的字符丢失,而使用wWinMain则允许我们正确处理传入应用程序的Unicode参数。

(hinstance表示程序运行的实例句柄,是一个数值,它唯一标识运行中的实例。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给WinMain函数。HINSTANCE是exe映像的虚拟地址,HINSTANCE用于区分进程实例,仅限于没有隔离进程地址空间的16位windows,现在的windows每个进程有自己的地址空间,两个进程的同一个地址可以是不同的东西,此时HINSTANCE不再具有唯一标识运行中的实例的功能,实例就是一个程序。就像qq。你可以开同时开2个qq号,但是你电脑里的qq软件只有一份。这2个qq号就是qq的2个实例,HINSTANCE的本质是模块基地址,他仅仅在同一进程中才有意义,跨进程的HINSTANCE是没有意义)

LPWSTR和LPCSTR是长指针类型,其本质是一个指针,指向一个长字符串

游戏编程代码大全、(w)WinMain函数有四个参数,其定义如下:
HINSTANCE hInstance:应用程序当前实例的句柄
HINSTANCE prevInstance:应用程序的前一个实例的句柄。根据MSDN的文档,此参数将一直是NULL。虽然此参数一直是NULL,如果你想要确定该应用程序是否已经有实例在运行,文档推荐使用CreateMutex函数来创建唯一名字的mutex(互斥体)。当有实例运行时,再次创建mutex,CreateMutex函数将会返回ERROR_ALREADY_EXISTS。
LPWSTR cmdLine(或使用Unicode编码的LOWSTR):应用程序的命令行由程序外部输入。允许你传递命令给程序,例如cmd命令终端,或者是通过快捷方式提供命令参数,等等。
int cmdShow:窗口被显示为哪一个模式的ID号(如最小化、正常、最大化等)

窗口初始化
尽管上述程序能够编译运行,可视由于没有创建窗口,运行时什么也没显示。因此,下一步就是创建Win32窗口。
首先注册一个窗口类并且创建窗口本身。应用程序必须在系统中注册它的窗口,见程序清单2.2.

清单2.2:窗口类的注册和窗口的建立

#include<Windows.h>
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR cmdLine, int cmdShow)
{UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(cmdLine);WNDCLASSEX wndClass = { 0 };wndClass.cbSize = sizeof(WNDCLASSEX); //窗口大小wndClass.style = CS_HREDRAW | CS_VREDRAW; //窗口风格WNDPROC WndProc;wndClass.lpfnWndProc = (WNDPROC)WndProc;//消息处理函数,窗口处理指针wndClass.hInstance = hInstance;wndClass.hCursor= LoadCursor(NULL, IDC_HAND);   //光标的句柄wndClass.hbrBackground = (HBRUSH)(COLOR_CAPTIONTEXT+1);//背景画刷的句柄 wndClass.lpszMenuName = NULL;    //指向菜单的指针wndClass.lpszClassName = "DX11BookWubdiwClass"; //指向菜单的指针if (!RegisterClass(&wndClass))return -1;RECT rc = { 0, 0, 640, 480 };AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);HWND hwnd = CreateWindow("Dx11BookWindowClass", "Blank Win32 Window",WS_OVERLAPPEDWINDOW, 0, 0, rc.right - rc.left, rc.bottom -rc.top,   NULL, NULL, hInstance, NULL);if (!hwnd) return -1;ShowWindow(hwnd, cmdShow);return 0;
}

Win32宏UNREFERENCED_PARAMETER(没有定义的参数)用于消除编译时未被函数使用的参数所产生的警告。虽然这一技巧不是必须的,但是却是一个很好的编程习惯——要求编译源码时产生0警告。这个宏没有做任何事情,VStudio编译器会优化它。
随后处理窗口类中未被使用的参数。窗口类由WNDCLASSEX所定义,包含Win32窗口的各种属性,比如窗口图标,惨淡,该窗口所属的应用程序句柄,鼠标外观等能够在Winuers.h中找到的结构,当然此头文件已经包含在Windows.h下了。
WNDCLASSEX定义如下:

typedef struct tagWNDCLASSEXA {UINT cbSize;/* Win 3.x */UINT style;WNDPROC lpfnWndProc;int cbClsExtra;int cbWndExtra;HINSTANCE hInstance;HICON hIcon;HCURSOR hCursor;HBRUSH hbrBackground;LPCSTR lpszMenuName;LPCSTR lpszClassName;/* Win 4.0 */HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, NEAR *NPWNDCLASSEXA, FAR *LPWNDCLASSEXA;

该结构的成员定义如下:
cbSize:该结构所占的字节数
style:用于定义窗口的外观
lpfnWndProc:著名的窗口回调函数(窗口过程), 任何来自于操作系统的事件通知都将调用此函数。 这里我们设置的 WndProc 函数将稍后介绍。 它其实是一个函数指针。
cbClsExtra:分配给该窗口结构额外的字节数。
cbWndExtra:分配给该窗口实例额外的字节数。
hInstance: 该窗口类的包含窗口过程的程序实例句柄。
hIcon:程序显示的图标的资源 ID 号。 如果为 NULL,则使用默认图标(例如,微软 Word 软件的文档左上角
的 W 图标)。
hCursor:鼠标形状的资源 ID 号。 本书中我们使用标准的箭头鼠标(游标)形状。
hbrBackground:用于绘制窗口背景的背景画刷句柄。
lpszMenuName:菜单,以 null 结束的字符串的资源名字。
lpszClassName: 以 null 结束的你所创建的窗口类名,最大长度是 256 字符。
hIconSm:窗口小图标句柄(例如在任务栏上的程序图标)。

DirectX6。窗口结构的大部分成员由Win32编程处理。
创建好WNDCLASSEX结构后,我们调用函数RegisterClassEx()来注册窗口类,该函数以创建好的窗口类结构地址做为参数来完成注册。如果返回值是0,则表示注册失败,因此需要仔细查看窗口类的各个属性值,保证它们都是有效,我们假定这不会出现大的问题。
其下一步就是完成创建实际的窗口。首先调用AdjustWindowRect来计算我们所希望的窗口尺寸,窗体类型决定了我们需要的窗口的真正尺寸。观察大部分的Win32窗口程序,都有一个非客户区的空间,如标题栏,程序的边框等。如果要确定窗体的具体尺寸,必须注意客户区和非客户区。
AdjustWindowRect函数首先采用一个矩阵(lpRect)来定义窗口区域的尺寸,左上角是窗口的起点,右下方向代表宽高。此函数也使用窗口将被创建的风格标记,并且最后bool标记表明窗口是否有菜单,此标记影响非客户区。该函数就是使用上述的是三个参数就算出整个窗口的尺寸。
接下来调用Win32函数CreateWindow来创建窗口。在清单2.2我们调用的是CreateWindowA,该函数接受ANSI字符串。而CreateWindowW则接受Unicode字符串。如果使用后一个版本,需要在字符串前添加L标识表明该字符串是Unicode编码(如:L”hello,你好”就算Unicode字符串)。

函数 CreateWindowA 的参数定义如下:
lpClassName:窗口类名字(使用与窗口类结构相同的名字)。
lpWindowName:窗口标题栏名称。
dwStyle:窗口风格标识。
X:窗口的水平位置。
Y:窗口的垂直位置。
nWidth:窗口的宽度
nHeight:窗口的高度
hWndParent:窗口的父亲句柄(如果该窗口是弹出式或者子窗口)。
hMenu:窗口的菜单资源句柄。
hInstance:程序的实例句柄
lpParam: 传递给窗口的数据, 用于窗口过程的处理(在窗口过程部分会讨论到)。

该函数的返回值是一个非空的句柄,如果创建成功,我们能够传递窗口句柄和命令显示标记参数(nShow、cmdShow,是WinMain函数的最后一个参数)来调用函数ShowWindow显示窗口。

创建窗口后,应用程序就开始它的工作了。Win32 GUI程序是事件驱动类型的程序,意思是当一个事件发生后,程序接收到他的通知(事件通知由OS传递给程序),采用一些行动来响应该通知。该程序一直运行,直到退出事件的发生。例如,Microsoft Word软件启动时,一个“creat”事件发生,程序完成载入动作。当用户在工具栏、菜单等区域点击鼠标时,就出发一个事件,OS发送给程序去处理。如果在打开文件按钮上出发鼠标点击事件,则将会显示允许用户打开文件的对话框。许多应用程序都是基于事件驱动的。
在视频游戏中,应用程序是实时的,以为这无论一些事件是否发生,都不会阻止程序在其生命期内执行一些任务。如果在游戏控制器上用户按下按钮,它会被游戏循环中的更新阶段所检测到,游戏再来响应该事件。如果没有事件发生,游戏也一直不断渲染当前的游戏状态,执行逻辑的更新,查找并且响应网络数据,播放声音等等。

实时和事件驱动的程序都一直运行直到用户退出为止。这里介绍用程序循环的概念,程序循环就是一个无限的循环,直到用户跳出该循环为止。由接受WM_QUIT事件(Win32的退出消息)来发生结束指令,假如在主菜单中设定了用户按下Esc键产生该事件,或者你设定它退出的任何其他方式。这里设定,往后所有Demo退出都以按下Esc键退出,或者点击窗口右上角的“X”按钮。
清单2.3展示了我们在此书中还没有联系 D3D 或者其他 Demo 的,使用程序循环的一个例子。 在清单 2.3 中的
注释,稍后将由与 D3D 关联的代码所替代。 如果我们实现了状态管理系统,用于游戏菜单和游戏接口或者其他的,
我们将在它本身的循环中初始化一次 Demo 和退出。 每次运行时,状态管理不允许初始化和关闭状态超过一次,因
此它工作得很好。 在 www.UltimateGameProgramming.com 网站有一些游戏菜单的材料,这些高级主题不属于本书的范围。
清单 2.3程序循环

include

#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmd, int nShow)
{WNDCLASSEX cls;cls.cbSize = sizeof(cls);cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);cls.hCursor = LoadCursor(NULL, IDC_ARROW);cls.style = CS_HREDRAW | CS_VREDRAW;cls.lpfnWndProc = WndProc;cls.hInstance = hInstance;cls.lpszMenuName = NULL;cls.lpszClassName = "DX11BookWindowClass";if(!RegisterClassEx(&cls)) return -1;RECT rc = {0, 0, 640, 480};AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);HWND hwnd = CreateWindow(cls.lpszClassName, "Blank Win32 Window",WS_OVERLAPPEDWINDOW, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
0, 0, hInstance, 0);if(!hwnd) return -1;ShowWindow(hwnd, nShow);//Demo InitializeMSG msg = {0};while(msg.message != WM_QUIT){if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}//Update//Draw}//Demo Shutdownreturn static_cast<int>(msg.wParam);
}

游戏编程入门书籍。窗口过程
在我们能够编译和运行我们的程序之前的最后一部分就是所提供的窗口过程,也就是窗口过程函数。清单2.4代码的前面部分有该函数的前置声明,在WinMain函数中被赋值给WNDCLASSEX结构的一个指针成员。窗口过程函数是回调函数,意味着我们的程序中当获得消息后就用该函数来处理。Blank程序Demo的窗口过程函数见于清单2.5.
清单2.5:Blank窗体Demo的窗口过程函数

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hDC;
switch(message)
{
case WM_PAINT:
hDC = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}

窗口过程函数返回LRESULT类型并且有回调CALLBACK修饰。此函数的命名遵循普通函数命名标准,以后统一使用WndProc这个名字。该回调函数接受参数窗口的句柄来调度该窗口的消息,无符号整形消息代号,两个可携带额外信息的参数(wParam 和 lParam)。最后两个参数用于补充的数据,在回调函数中处理消息需要更多的数据时。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/82375.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息