在命令行上玩出花:InfantGameEngine

前言

InfantGameEngine,婴儿级游戏引擎,虽然它只能显示简单的游戏画面。但它可以支持你写非常复杂的游戏逻辑。

=======================================================

Tip:源码已经放在github上了,建议参照源码阅读~

项目地址:https://github.com/TOXICAKE/InfantGameEngine.git

觉得有趣的话记得给一颗星XD

开始

储存字符

显示在屏幕上的每一个字符都具有多个属性,所以可以用结构体来记录每一个字符。这样就引出了**实体(Entity)**这个概念,每一个字符都是Entity类的实例,称作一个实体,然后用链式结构关联每一个实体。这样只需要遍历就可以取到所有的实体,以及它们其中的数据。

刷新机制

每帧都刷新显示所有字符是不可能的,所以应该采用局部刷新的方法。假如一个实体向右移动一格,那么就是在右侧输出这个实体的字符,并在原来的位置上输出被遮挡的字符。局部刷新机制

碰撞机制

实体应该具有一个参数**碰撞(Collision)**,两个有碰撞实体彼此不能穿过,两个实体间如果有至少一方是无碰撞的则它们彼此可以穿过。这就是基本的碰撞机制。

简单演示一下碰撞机制

实体组

显然,我们不能总是让开发者以实体为单位去开发游戏,例如马里奥是32*32像素的,程序移动马里奥是以整个马里奥为单位去移动的,我们也应该向开发者提供以组为单位的开发方式。我选用了二级链表来实现,即实体组之间连接,每个节点又是新的实体链的头节点。实体组的数据结构

交付

为了使游戏显示效果尽可能的好,刷新应该在移动后进行,所以刷新应该交付给各个会产生实体位置移动的函数。

碰撞检查也是发生在移动过程中的,也应该交付给各个会产生实体位置移动的函数。

实体移动到新位置时,应该要把新位置上的实体保存下来(如果有)。但除了在移动时要保存,在创建新实体时也要保存。

基本功能

实体移动 En_Move

实体的移动是引擎最基本的功能,包括的内容很多,但是逻辑并不复杂。接受的参数应该是实体的编号(id),运动方向(direction),距离(distance)。

首先是检查对应方向上的可移动距离。如果移动的实体本身的碰撞属性是off,则不需要考虑与其他实体的碰撞问题,只用检查移动完是否在画布内即可。如果碰撞属性是on,则循环检查时就要同时考虑检查位置上的实体碰撞属性,如果同为on,则可移动距离就是到这个实体的距离。

计算出可移动距离,如果比distance大,则可以移动distance那么远,否则的话移动到最大可移动距离停下。实体移动演示

构成实体组 AddEnToGr

实例化一个实体组对象后,使用这个函数将一个实体加入到组中去,代码也很简单,就是普通的在实体链后面加一个节点而已。

实体组移动 Gr_Move

实体组的移动其实就是对每个实体进行实体移动而已,但实际上的代码逻辑要稍微复杂一点。

首先循环计算每一个组内实体的可移动距离,再求出其中的最小值。这个最小值就是这个实体组实际上可以移动的距离。实体组移动演示

但是,如果之间调用之前写好的实体移动函数则会出现刷新显示上的问题。

因为是顺序结构,所以实体组中的实体也是按序移动,顺序与每条AddEnToGr执行顺序一致,这样就导致如果显示位置在前(沿移动方向)的实体移动顺序排在后面,就会遮挡先前移动好的实体。如下图所示,按ABC顺序添加进组中的三个实体,向右移动一格,最后画面上只会剩下C。

bug

解决办法就是等所有实体移动完后再刷新遮挡的实体,最后刷新移动后的实体。

实体组旋转 Gr_Spin

旋转也应该是引擎提供的功能。开发者提供旋转中心和旋转方向,就可以直接以组为单位旋转。可以简单的分为几步来实现,计算所有实体旋转后应该在的位置,然后检查移动路径上是否有阻碍,如果有,则不能旋转。确定旋转后位置的算法,(我用象棋棋盘找到的,并不复杂)。在算法上,第一步是确定实体所在的象限,再在象限内判断实体在45度线的那半边。还有特殊的实体恰好在分界线上的情况。下图是我的演草纸,动手画图找到规律就可以了。

演草纸

这部分代码比较费神,实际上最后的代码应该可以优化,但是我已经没有心情去做了。

API的设置

我在开发好基本功能后就去写了小demo来测试,最后写了“七巧板”来做最终的测试,中间的api也是越加越多,除了实体的信息要有api来提供以外,总的实体数目,组的个数还有组内实体总数也都需要提供。还要可以多种方式查询,比如获得实体可以通过实体编号,也可以通过组和组内实体编号,还可以通过画布的坐标。

实际使用

它的实际使用效果很不错,因为我们在开发时提供的功能比较完善,没有过多的限制,并且是直接的api调用编程,比较灵活。

开发过程中最重要的是实体的管理,如果实体没有管理好,整个代码看起来就会相当糟糕。

实体就是“实际”存在的意思,他具体是什么由程序员的代码来决定。例如你可以在实体类中增加一个变量Key,程序员在设计游戏时就可以给key赋值,例如1代表构成主角的实体,2代表按钮,3代表门。

测试程序和测试源码都可以在github上找到。

=======================================================

后记

你大概不会真的动手去写一个,也可能会觉得它没什么用。我们是直接接触框架的一代,这些东西除了作为上学时的作业,几乎毫无用处,我们上面在讨论的东西,也是之前雅达利思考过的东西,他们当时的开发环境还要更为恶劣一些。

命令行也可以做出很有趣的游戏,画面并不是游戏的唯一要素。

大灾变:劫后余生

当然还有著名的生命游戏。

谢谢你花时间阅读这篇博客。:)

在评论区留个脚印吧~