从零开始手敲次世代游戏引擎(七) - 知乎
从零开始手敲次世代游戏引擎(七)

从零开始手敲次世代游戏引擎(七)

那么首先让我们从最熟悉的Windows开始我们的图形编程支线任务。
想象一下在现实生活当中,如果我们想要画画,需要准备一些什么东西。在计算机领域,这个过程也是很相似的。因为当计算机从CUI(就是文字界面)转向GUI的时候,拓荒GUI的那些先驱们,也是参考着生活进行设计和编程的。
显然,我们首先需要有一块画布。在Windows系统当中,就是需要创建一个窗体。相信看这篇文章的很多人都写过Windows应用,而且是GUI应用。用Visual Studio生成一个windows应用,会自动生成创建这个窗体的代码。甚至,如果使用UWP,那么窗口对我们来说更像一张网页。然而这不是我想要介绍的方法。
我想要介绍的是使用windows系统API,也就是俗称win32 API(64位windows的API仍然称为win32 API)的方式创建窗口。之所以这么做,是为了最小限度的依赖Visual Studio以及相关的库,也是为了便于与其它系统的类似API作个比较。
好了,让我们开始。首先依然是做个记录点:

[tim@iZ625ivhudwZ GameEngineFromScratch]$ git checkout -b article_7
Switched to a new branch 'article_7'

然后新建一个Platform目录,用于存放和平台相关的代码。

[tim@iZ625ivhudwZ GameEngineFromScratch]$ mkdir Platform
[tim@iZ625ivhudwZ GameEngineFromScratch]$ cd Platform

在Platform下面新建Windows目录,用于存放Windows平台相关代码:

[tim@iZ625ivhudwZ Platform]$ mkdir Windows 
[tim@iZ625ivhudwZ Platform]$ cd Windows

新建helloengine_win.c,敲入如下代码:

// include the basic windows header file
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
                         UINT message,
                         WPARAM wParam,
                         LPARAM lParam);

// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR lpCmdLine,
                   int nCmdShow)
{
    // the handle for the window, filled by a function
    HWND hWnd;
    // this struct holds information for the window class
    WNDCLASSEX wc;

    // clear out the window class for use
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    // fill in the struct with the needed information
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = _T("WindowClass1");

    // register the window class
    RegisterClassEx(&wc);

    // create the window and use the result as the handle
    hWnd = CreateWindowEx(0,
                          _T("WindowClass1"),    // name of the window class
                          _T("Hello, Engine!"),   // title of the window
                          WS_OVERLAPPEDWINDOW,    // window style
                          300,    // x-position of the window
                          300,    // y-position of the window
                          500,    // width of the window
                          400,    // height of the window
                          NULL,    // we have no parent window, NULL
                          NULL,    // we aren't using menus, NULL
                          hInstance,    // application handle
                          NULL);    // used with multiple windows, NULL

    // display the window on the screen
    ShowWindow(hWnd, nCmdShow);

    // enter the main loop:

    // this struct holds Windows event messages
    MSG msg;

    // wait for the next message in the queue, store the result in 'msg'
    while(GetMessage(&msg, NULL, 0, 0))
    {
        // translate keystroke messages into the right format
        TranslateMessage(&msg);

        // send the message to the WindowProc function
        DispatchMessage(&msg);
    }

    // return this part of the WM_QUIT message to Windows
    return msg.wParam;
}

// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    // sort through and find what code to run for the message given
    switch(message)
    {
        // this message is read when the window is closed
        case WM_DESTROY:
            {
                // close the application entirely
                PostQuitMessage(0);
                return 0;
            } break;
    }

    // Handle any messages the switch statement didn't
    return DefWindowProc (hWnd, message, wParam, lParam);
}

好了,让我们来用Clang对它进行编译。注意这是一个Windows程序,所以你需要在Windows里面编译它。并且,因为我们用到了一些Windows平台的接口,需要链接相关的库:

C:\Users\Tim.AzureAD\Source\Repos\GameEngineFromScratch\Platform\Windows>clang -l user32.lib -o helloengine_win.exe helloengine_win.c

编译成功的话,会出现一个helloengine_win.exe

C:\Users\Tim.AzureAD\Source\Repos\GameEngineFromScratch\Platform\Windows>dir
 驱动器 C 中的卷是 OS
 卷的序列号是 38A2-CBDD

 C:\Users\Tim.AzureAD\Source\Repos\GameEngineFromScratch\Platform\Windows 的目录

2017/08/21  08:20    <DIR>          .
2017/08/21  08:20    <DIR>          ..
2017/08/21  08:10             3,163 helloengine_win.c
2017/08/21  08:21            73,216 helloengine_win.exe
               2 个文件         76,379 字节
               2 个目录 885,621,440,512 可用字节

执行它,我们就可以看到我们的窗体啦!


接下来再玩些别的酷酷的东西。在Linux上面交叉编译它(把代码Commit/Push到Github上面,然后在Linux上面把代码再Pull下来。不会的网上搜一下Github/Git教程。)

[tim@iZ625ivhudwZ GameEngineFromScratch]$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 5 (delta 1), reused 5 (delta 1), pack-reused 0
Unpacking objects: 100% (5/5), done.
From github.com:netwarm007/GameEngineFromScratch
   264a4aa..5587a7d  article_7  -> origin/article_7
Updating 264a4aa..5587a7d
Fast-forward
 Platform/Windows/{helloworld_win.c => helloengine_win.c} | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 rename Platform/Windows/{helloworld_win.c => helloengine_win.c} (97%)
[tim@iZ625ivhudwZ GameEngineFromScratch]$ cd Platform/Windows/
[tim@iZ625ivhudwZ Windows]$ ls
helloengine_win.c
[tim@iZ625ivhudwZ Windows]$ docker run -it --rm -v $(pwd):/usr/src tim03/mingw64
docker@691b5f941825:/$ cd /usr/src
docker@691b5f941825:/usr/src$ ls
helloengine_win.c
docker@691b5f941825:/usr/src$ x86_64-w64-mingw32-gcc -o helloengine_win.exe helloengine_win.c
docker@691b5f941825:/usr/src$ ls
helloengine_win.c  helloengine_win.exe
docker@691b5f941825:/usr/src$ exit
exit

这个程序,当然,这样直接是没有办法在Linux上执行的,因为它是一个Windows程序。但是,我们可以使用wine来执行它。wine是一个在Linux上面模拟Windows系统接口的执行环境,可以用了执行Windows程序。当时开发wine的主要目的,就是在Linux上面跑只有Windows版本的游戏。

不过需要注意的是,要执行图形界面程序,我们必须在Linux的桌面环境下(也就是不能在TTY环境下)。切换到桌面环境(不会的请自己在网上搜索Linux基本教程),打开终端仿真窗口,执行下面的命令(如果没有安装wine,请用yum或者apt命令安装):

tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Windows$ wine helloengine_win.exe


(-- EOF --)

参考引用:

  1. infernodevelopment.com/
  2. Windows API - Wikipedia
  3. Windows API Index



本作品采用知识共享署名 4.0 国际许可协议进行许可。

编辑于 2018-03-04 16:32