笔者个人的想法,是打算将这个系列的文章写成通用性的,不局限于某一种语言,也不局限于某一种引擎,但是水平有限,预计是达不到这个效果。以下仅以C++来举例,如果其他的语言,思想应该是大同小异的。
首先,游戏程序有它的特殊性,决定了它的主体代码应该是一个死循环。类似于这样
1 int main()
2 {
3 while(1);
4 return 0;
5 }
当然,可能有些时候,程序的入口可能不是这样的形式。
而不论是什么类型的游戏,有几个基本的模块:显示,控制。声音之所以不在这里,是因为笔者遇到的游戏引擎,声音这一部分都是托管式的,就是只要调用了开始播放音乐的函数后,它就会一直播放,只需要在特定的时候调用它的停止函数,它就会停止,所以声音部分可以融合在控制模块里。游戏在开始之前,可能需要从硬盘加载一些常用的素材,进行一些变量的初始化。根据以上两点,之前的程序就可以改成这样
int main()
{
LoadRes();//加载资源
InitVar();//初始化变量
while(1)
{
DrawGame();
ControlGame();
}
return 0;
}
这里,各位如果对FPS有特定的需要,也可以加入对时间的控制。这里也不在赘述了。以上就是一个一般的单机游戏框架了,笔者在入门初期所编写的游戏程序,最开始的框架也是这样。但是后来受到别人的启发,其实可以将显示模块和控制模块分在两个线程里,这样对游戏的效率有很明显的提升。代码如下
int main() { LoadRes(); InitVar(); unsigned ret; _beginthreadex(0,0,ControlGame,NULL,0,&ret); while(1) { DrawGame(); //ControlFps(); } return 0; }
关于多线程的问题,大家可以去求助搜索引擎,这里暂时不赘述。
这样的框架是笔者本人一直在使用的框架。但是笔者最近受到网络游戏C\S模型的启发,觉得如果在单机游戏中将控制模块和键盘鼠标输入模块分开,各自都执行在各自的线程中,会是一个更高效的框架。比如在某一个动作之后,有很多数据的改变,如果两个模块独立,可以避免此时由于进行数据的更新而造成的无法响应输入的问题。而两个线程之间维护一个消息队列,由输入模块不停地向控制模块传递消息,使得控制模块也可以响应输入所带来的影响。代码如下
int main() { LoadRes(); InitVar(); unsigned ret1; _beginthreadex(0,0,ControlGame,NULL,0,&ret1); unsigned ret2; _beginthreadex(0,0,Input,NULL,0,&ret2) while(1) { DrawGame(); //ControlFps(); } return 0; }
这样将输入模块和控制模块分开的做法,笔者也没有在单机游戏上使用过,希望大家有想法可以跟我讨论。
这篇就到这里,预计以后几篇分别就每个基本模块进行详细介绍。
浙公网安备 33010602011771号