学习游戏基础编程1:Win32自定义控件

第一次写博客,感觉怪怪的。

我想学习游戏编程,之前也写过简单的2D类型的类似超级玛丽游戏,但是感觉除了在设计思想方面和GUI基本毫无收获,于是准备从头开始,去认识游戏是怎么编成的,虽然我很菜,但是我有信心。

我认为一个游戏首先要具备的就是素材,幸好之前就有好多存货,这次准备的是依然2D的,当然3D的从现在搞有点难度,不过这次的图片是斜45度类型的,相当于2.5D的吧,刚好符合2D->2.5D->3D的路线,废话不多说开始吧。

开始研究Win32的GUI,当然有好多成熟的GUI库,好多是跨平台的,可视化的,不过对于喜欢钻牛角尖的我来说,单纯的组织数据来编写游戏满足不了我,我要从里到外把它摸一遍。直接用Win32API编写界面,嗯,不得不说这个决定是很愚蠢的,因为这相当于要自己砍木做房子,而不是用别人造好的家具。

接下来我看了Directx2D,不兼容XP及更低的OS,无所谓,反正是学习,不过GDI+也不错,看看后面的实际情况吧,如果有严格性能要求的就用D2D。

接下来就是数据的事情了,嗯,首先就是xml文件的操作,感觉xml格式的数据来驱动游戏是个好方法。C中没有xml的标准库,网上搜之发现tinyxml口碑不错,试了下,果然简单实用。学习之。

接下来开始规划,基本的技术要求都有了解,接下来会使细化的具体实现,那才是最难过的时间,要马不停蹄的各种查资料。好吧,问题已经来了,想了好多哦,头疼,先从最简单的开始做起,抛弃那些不断浮现的想法,因为这是不切实际,一口吃不成胖子。我需要一个地图编辑器,参观了war3的地图编辑器,果然牛逼,暴雪品质不是吹出来的,这个地图编辑器只有一个大窗口,左边是地图编辑区,右边有地图缩略图,一个下拉框列表框显示图片组,下面是要选择的图片,菜单栏有文件和帮助,文件包括打开,新建,保存,退出,工具栏和状态栏暂略。

开始了,我的地图编辑器之旅。

好吧,问题接踵而至,我需要显示图片,使用控件,但是Win32没有现成的,只能自定义,额额额,痛苦,期间学习到了不少Win32的控件的知识,感觉自己牛逼了好多。

看了好多文章,也写了几个简单的例子,都感觉不太完美,其实和一个简单windows窗口一样,需要你指定注册窗口类和窗口过程函数。需要注意的是指定WS_CHILD样式。

第一步:注册窗口类

 WNDCLASSEX wc;

  
    wc.cbSize         = sizeof(wc);
    wc.lpszClassName  = szClassName;
    wc.hInstance      = GetModuleHandle(0);
    wc.lpfnWndProc    = CustWndProc;
    wc.hCursor        = LoadCursor (NULL, IDC_ARROW);
    wc.hIcon          = 0;
    wc.lpszMenuName   = 0;
    wc.hbrBackground  = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
    wc.style          = 0;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hIconSm        = 0;
    RegisterClassEx(&wc);
第二步:定义窗口过程函数:
LRESULT CALLBACK CustWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    default:
        break;
    }
 
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
第三步:创建窗口:
HWND hwndCtrl;
  
    hwndCtrl = CreateWindowEx(
                 WS_EX_CLIENTEDGE, // give it a standard border
                 szClassName
                 _T("A custom control"),
                 WS_VISIBLE | WS_CHILD,
                 0, 0, 100, 100,
                 hwndParent,
                 NULL, GetModuleHandle(0), NULL
               );
关键的地方红色标出来了,一个是注册自定义窗口的类名,第二个是指定窗口样式为子窗口。
接下来该怎么做呢?
我需要的编辑地图,因此我要将我选中的地图贴到指定地方,即控件,因此我需要几个变量能让我实现这个控件显示我要的图片。
你可以用C的方式声明一个结构体或者C++的方式定义一个类。
typedef struct
{
  HWND hwnd;
  定义变量用以帮助显示图片
}MyCtrl;
class MyCtrl
{
  定义函数绘制图片
}
关于自定义控件的知识我推荐这篇博文,非常棒!http://www.catch22.net/tuts/custom-controls
又过了几天,总结一下:窗口子类化的知识。
如果是C风格的 可以建一个结构体:里面呢 放上你需要的各种资源如窗口句柄、字体颜色、位图等。另外最好是有注册窗口类、创建窗口、自定义窗口过程、方法,注册窗口类在程序开始时就加上去,免得忘记,创建窗口则是方便提供一个整齐直观的接口对外调用,也不用到处CreateWindow()了,自定义窗口过程是最重要的,因为这是你自己最主要的实现。当然C风格的不如C++那样不容易扩展,适合底层次的封装。当然随手做的小程序可以不用顾忌,反而更容易理解。
如果是C++风格的 就可以用类了,依然里面几个重要的方法必须是静态的。其它倒是差不多,不过可以方便扩展。可以写一个基类,可以用模板来更好的扩展。
里面有个难点:就是如何把窗口句柄和结构体或者类对象关联起来,根据我搜集到的知识来看,最好的方法之一就是:WNDCLASS里的cbWndExtra来存储,另外一种通过GWL_USERDATA来存储,两者都可以SetWindowLong和GetWindowLong来操作,不过前者适合自定义的控件。之后可以在窗口过程函数里操作,CreateWindow()里的最后一个LPVOID lpParam参数,在WM_NCCREATE或者WM_CREATE下的lParam参数,强制转换成LPCREATESTRUCT结构体,这个结构体里的lpCreateParams成员就是之前LPVOID lpParam的值,可以把它放在GWL_USERDATA里,随时启用,如http://bbs.csdn.net/topics/390152857这个例子。也可以在创建窗口的时候就去关联例如这个例子http://blog.csdn.net/fishion/article/details/8985414。当然效率最高的是thunk技术了,不过有兴趣的朋友可以去仔细看下。
方法有很多种,最后的目的都是一样的。学东西要深入浅出,莫钻牛角尖。