
让我们先引用下三傻大闹宝莱坞里的一个我很喜欢的场景.
我们如何定义什么是机器呢
实际上游戏引擎也一样,能够减少游戏开发难度和成本的东西,都可以叫游戏引擎,也就是说,这个东西到底算不算游戏引擎,并没有一个严格的定义.
不过,在聊游戏引擎到底是如何减少游戏开发难度这个问题上,实际上是一个无比庞大的课题,以至于笔者无法在一个简短的回答中将它阐述清楚,因此本文也只能简略的对一些常用的功能及设计做一些抛砖引玉,蜻蜓点水式的概述.尽管现在有非常多优秀的令人震惊的游戏引擎,开发出了众多在画面与游戏性上令人赞叹的作品,但现在,我们还是需要回到最原始的黑白LCD时代,回顾那些早期的经典游戏.
幸好,这并不是一个多么复杂的话题,例如经典的俄罗斯方块和贪吃蛇等游戏,其实都并不复杂,对于一个编程的新手,在学习了一门编程语言后,都很容易能够将它们做出来.我们以一个贪吃蛇为例
例如下面的代码,就是一个C语言实现的贪吃蛇的实现代码,它的实现非常简单.只需要平台能够提供一个绘制矩形的功能(由PainterEngine提供),同时提供上下左右的按键功能提供就可以实现了.
它的实现方式简单粗暴,为了方便说明,你可以看到我将游戏地图中的每一个格子都标上了一个数字,其中-2表示边界的墙体,0表示可以移动的格子,-1表示食物,而大于0的数字,表示蛇的身体,每次蛇吃到了食物,身体头部的最大值都会加上1,最后我们整理好这个逻辑关系,将地图上的每一个格子按照格子里的数字绘制出来就可以了.
当然,在红白机年代,俄罗斯方块,贪吃蛇,打方块带给了我们无穷的快乐,但游戏不可能一直停留在"贪吃蛇"时代,随着硬件性能的提升,游戏也随之发展,当然,游戏也是循序渐进的,不可能昨天贪吃蛇还在流行今天就能玩上巫师系列.
这里我们来讲一个经典的游戏魔塔,它的逻辑实现仍然很好理解
可以看到,游戏的画面丰富了起来,但如果你仔细思考一下,实际上这个游戏的基本逻辑并没有比贪吃蛇复杂多少,整个游戏画面仍然是一个一个小格子组成的,也就是说,我们仍然是使用一个数字来表示这个格子到底显示的是什么东西,之后,无非是将绘制一个矩形的做法换成了绘制一个贴图(tile),他们分别代表着门,怪物,钥匙等数据.
同时,游戏数据也变得更加的多元化起来,例如现在我们有了战斗系统,有了解谜设计,有了关卡切换,随着硬件资源的进步,我们有了更多的计算及内存资源来完成那些更加复杂的计算.这个时候,我们将所有的代码写在一块,相对于贪吃蛇而言,它有了更多的系统,当然其中最为进步的,就是贴图系统的引入,当然,魔塔并不是最早的贴图游戏,像超级玛丽,魂斗罗....
包括你所看到的大部分的红白机游戏,实际上都是贴图系统的产物,贴图游戏是如此的常用,以至于它出现在几乎所有的游戏当中,因此,早期的游戏硬件实际上将贴图系统直接设计到了硬件中,以让系统能够更加高效的绘制游戏中的贴图,我们甚至可以这么说,一个早期的专门为了制作游戏的硬件工具已经诞生了,那么它可以算是最早的"游戏引擎"了.
既然已经说到了贴图系统,我们就有必要更进一步了,我们必须承认一个事实,游戏大部分都是连续不断的动画----一个能够随着玩家输入而产生不同动画结果的"动态视频",而一个最简单的动画实现,就是将贴图一张一张的显示出来,以显示这种动画的效果,例如,下面的动画实际上是6张图片连续播放的结果
要让2D游戏变得更加生动,这种逐帧动画的形式,变得广泛应用起来,包括你现在所看到的大部分2D游戏(3渲染2的除外),都或多或少有使用这种逐帧动画形式,包括你所见的"饥荒","死亡细胞"
但即使是2D的逐帧动画,也并不是那么好管理的,例如,你需要决定每一帧间隔是多少,需要决定哪一部分需要循环,循环多少次等问题,为此,你可能需要设计一个动画描述的脚本系统,来控制逐帧动画的播放形式,例如之前我们聊到的"狐狸动画",实际包含了"走","跑","跳上","跳下"等动画形式,笔者使用一个叫2dx script的动画脚本来描述它
你可能已经感觉到很满足了,逐帧动画的灵活度极高,几乎能实现你想要实现的任何动画形式.当然,它也被应用在了绝大部分的2D游戏中,但逐帧动画的缺点也非常明显,它太耗费太耗费美术资源了,你想想,光一个不到半秒的动作就需要绘制6帧贴图,对工作量和硬件内存都是不小的负担
那么,接下来我们学习了生物的运动规律,比如,我们人的运动是由我们骨骼与肌肉限制的,那么,是否是说,我们只需要关注骨骼的运动规律,然后旋转贴在骨骼上的图片,就能够生成一个看上去合理的动画了.这也就是2D动画的更进一步,骨骼动画
例如,下面演示的是一个2D的骨骼动画系统生成的2D动画(PainterEngine Live2D)
因此,动画的生成由一张一张的手工制作变成了骨骼矩阵的级联运算,相对于逐帧动画大大减少了美术的工作量.
可见,仅仅只是贴图已经越来越不能满足游戏的需要了,我们需要把贴图的方式进一步玩出花,就需要更多的设计与封装,实际上,我们将已经凉凉的Flash称作一个游戏(动画)引擎,绝对不能说错!无数多的flash小游戏诞生于此,flash毫无疑问的,提升了游戏的开发效率
那么除了动画之外,我们还有没有办法能进一步提高游戏开发效率呢
关于这一点,面向对象的开发思想给了无数游戏引擎设计者启发,大多数的游戏是计算机对人类逻辑和世界的模拟,大多数情况下,我们可以将游戏中的每一个对象进行区分处理,那么,我们只需要设计游戏对象就可以了
简单来说,游戏就像个大舞台,而游戏设计者是一个大导演.他需要做的是告诉每个演员自己应该做什么,然后让演员们一个一个上台表演,这样,一场游戏就像是一场舞台剧的表演过程.就像下图中的狐狸跳游戏,狐狸是一个对象,天上飞的鸟也是对象,仙人掌和树桩是对象,天上的云朵也是对象,甚至连背景的地板也是一个对象,你可以在这个链接中玩到这个游戏
而说到这一点,不得不谈谈游戏对象设计中最普遍的设计框架,初始化,更新,渲染
其中,初始化完成对象的一系列参数设置,资源绑定等操作,更新一般用于计算对象的一些物理参数,比如更新速度,坐标,HP值,响应触发事件(trigger)等操作,渲染则是将物理数据绘制成图形数据
如果你细心的话,你可以发现,即使是简单的贪吃蛇游戏,在上面的代码中,也遵循着这样一种设计框架.
当然,如果要步入实用阶段,这方面的细节和设计要复杂的多,例如这种对象设计框架往往需要有一个事件管理机制,例如下面是一个关于这个的简单例子,物理引擎计算后,发现对象A与对象B碰在了一起,那么,事件管理机应该生成一个碰撞事件告诉对象A和B,关于这个和我们现实的世界又有所不一样,一般情况下,游戏对象不会去主动感知碰撞之类的信息,不会主动感知其它的对象(否者这容易让整个游戏设计变得混乱复杂),物理计算由物理引擎进行管理或部分接管,如果有碰撞事件的发生,应该由事件管理机通知碰撞的对象,然后对象再响应对应的时间,这样我们就能用
对象A:当碰撞上了B,A应该加血50
对象B:当碰撞上了A,应该销毁
这样一种触发器的机制来完成游戏对象的设计
可以看到,除了贴图之外,我们需要在这个功能的基础上设计更多的功能,在目前来看,对于纹理绘制,光栅化操作之类的比较耗时的操作,往往都有硬件加速,而在此基础上的动画实现,则由软件进行负责,因此目前我们往往会进一步进行区分渲染器,游戏引擎等
当然,一个成熟商业游戏引擎有的东西,还有很多很多没有讲到,这里展示的仅仅是冰山中的一角,总的来说,游戏引擎是游戏开发者对经验的总结,对于那些重复的,经常用得到的工作,引擎设计者往往会将这些工作做好并封装,下次开发游戏要用的时候,直接拿出来用就行了,而不管它是游戏引擎还是别的什么封装库也好的最终目的也只有一个,为了提高生产力,加快开发效率.因此,游戏引擎并没有一个明显的定义.就像上面的贪吃蛇,如果你包装一下然后说我做了个能做贪吃蛇的游戏引擎,似乎也没什么问题,虽然可能会让一些人嗤之以鼻:就这玩意也能算游戏引擎?,但如果你换成约翰卡马克,做了一模一样的事情,然后再宣称这是游戏引擎,那这些人还敢说个不字么.
所以别纠结那么多,不管用什么做游戏,能用,好用就行了
附上自己设计的引擎:
