关于如何编写一个游戏,一直没有非常系统和深入的学习.之前的时间一直是在进行无目标的埋头乱看,WINDOW API, GDI, DIRECTX等.但事实上编写游戏需要的知识远比这些更多.
工作以后,由于本身就在游戏公司,并且目前每天的任务量不大,我也就可以腾出时间系统的学习游戏编程了.
从上上个星期开始,我花了10天左右的时间想去编写一个2D的小游戏,泡泡龙.在编写开始前,我以为会非常的简单,因为毕竟不管是WINDOWS API, GDI还是用C++写逻辑我都还是十分熟练的.但是真的开始编写的时候才傻了眼.问题一个接一个.
在编写这个游戏之前,我只编写过像五子棋之类的游戏.也许你听上去觉得五子棋与泡泡龙没什么不同(也许你还会觉得它们俩一样的弱智),可是编写难度却相差了很远.这是因为泡泡龙是视频游戏,而五子棋只用靠事件驱动.
对于一个事件驱动的程序来说,程序画面的绘制控制只是和用户的操作事件有关的,程序的主循环为:
while(GetMessage(...))
{
TranslateMessage(...);
DispitchMessage(...);
}
然后调用窗口的回调函数来进行事件处理,并且进行刷新画面.画面的刷新一般是在WM_PAINT事件里面进行的.
但是对于一个视频游戏而言,这种结构根本无法满足程序的要求.为什么这样说?(你可能有疑问)
视频游戏画面的刷新比事件驱动游戏的画面刷新要多很多,如果使用实践驱动模式,我们就不得不使用时钟函数,这是一种方法.但是这种方式并不是很好.因为我们的游戏循环被放在了事件处理函数中,而这种事件发生的间隔是一个定值,如果在这个时间内没有完成渲染,下个时间内又会开始一个新的桢的渲染,由此以来不可预知的问题就可能发生.
更好的方式是这样的:
将消息循环进行如下的改写
while(TRUE)
{
if(PeekMessage(....))
{
if(msg == WM_QUIT)
return 0;
else
{
消息分发;
}
}
if(渲染间隔没有小于需要间隔)
GameMain(); //游戏过程
else
Sleep(0);
}
如此一来,主循环的任务变成了两部分,首先是去查看有没有消息,但是不会像GetMessage那样阻塞住循环,如果有就分发,如果没有,执行游戏过程(游戏过程中一般都包括了渲染)
值得注意的是,如果渲染的时间间隔已经小于需要的间隔了,就Sleep(0)一下.看过<windows核心编程>的人都知道Sleep(0)可以让线程交出一下控制权,以便系统去调度别的线程.
但是仅仅掌握上面的这些只是开始.当我真的开始编写GameMain()的时候才发现,麻烦才刚刚开始.事实上,GameMain()应该是什么样的结构我该过很多次,都不太好,后来看了下<windows游戏大师编程技巧>才恍然大悟.GameMain()的最好结构应该是一个有穷状态自动机.
该自动机的结构应该大体如下:
初始化 -----> 接受外界输入 ----> 逻辑更新(包括判断) ------>进行渲染 -------> 显示于屏幕
| ^ |
| | |
| ------------------------------------------------
|
|
退出游戏
通过全局的游戏状态来确定GameMain()具体来做什么.
接下来的问题更麻烦一些,下篇再说喽:-)