我整理了一些关于软考的项目学习资料+视频(附讲解~~)和大家一起分享、学习一下:
https://d.51cto.com/bLN8S1
传送门 简介小工具实现简易引擎KeyCode的内容EngineConfugureGameEngine构建KeyCode.java的小工具配置解析器实现接口java beans主体注册器解析器一些方法接口和通用类点阵地图模板配置类引擎类具体游戏实例障碍物系统障碍物类工具类障碍物池游戏实例配置类引擎类尾声控制台部分配置类菜单打印工具引擎类源码分享简介
我原本想通过Java做一个小游戏合集,但目前只有俄罗斯方块是完整做好的。其实就小游戏而言,除最顶层的逻辑略有不同以外,很多底层逻辑是通用的,所以我想通过这个俄罗斯方块小游戏跟大家分享我对游戏引擎和面向对象的理解。
首先先展示下成品:
因为演示的时间比较长,文件比较大,我故意抽了些帧,游戏实际上还是很流畅的。
对于游戏引擎而言再简陋,让帧率 可调和稳定的基本功能还是要有的。
源码分享在文章最后。
小工具
通过演示的画面大家可以看到我是直接双击运行jar文件而不是通过命令行java -jar name.jar来运行。这是因为我用C语言写了一个小工具。其底层其实还是java -jar name.jar。但是它使得runnable jar都可以被直接双击运行,方便许多。在这里我先分享下那个小工具:
把这个小工具输出为.exe。以visual studio为例,
生成→生成解决方案就可以得到.exe文件
成功提示的上一行说明了目标文件被输出到了哪里。
接下来直接对着jar文件双击
在弹出这个提示时选择我们刚才制作好的小工具(我这是JarRunner.exe)并点击左下角的始终,以后runnable jar就都可以直接双击打开了。
实现
简易引擎
游戏依赖于一定的框架环境会使得后续的代码更加简洁,逻辑更加清晰,所以这里先实现一个简单的游戏引擎。
引擎模块的文件结构如上图。
因为Java没有直接把KeyCode和按键关联的API,所以需要用一个KeyCode类来专门记录,以便后续使用。当然这不可能是手敲出来的,能够直接CV最好,但笔者在开发时没有找到能够直接CV的全面代码,只找到了全面的形式化描述。我后面会讲述怎么通过工具类把一些形式化描述转换为这个文件。此外这个模块还需要一个引擎类和配置类作为所有引擎实例和配置实例的基类。往往一个引擎类需要对应一个配置类作为构造函数的参数去配置它。所以在当前项目中:一个引擎实例往往由引擎类和配置类两个文件组成,他们的基类是这里的GameEngine和EngineConfugure。
KeyCode的内容
以下是KeyCode的具体内容,有需要的可以直接从我这里复制。
EngineConfugure
EngineConfugure描述了游戏实例的最基本属性:最大帧率、窗口尺寸和窗口是否允许调整大小。将来这个类将作为GameEngine构造函数里必要的参数之一。
GameEngine
GameEngine的作用是主要模仿Unity实现一个对awake、start和update函数的简单调度,这里只是调度模式模仿Unity,在具体实现上是有着天差地别的,有兴趣的读者可以自行研究。并且封装了一个简易的事件系统。
具体代码如下(讲解看注释):
至此,能够调度游戏循环、具有简单事件系统的简易游戏引擎就完成了。
构建KeyCode.java的小工具
身为程序员我们要养成自己用制作小工具的习惯。现在来通过一个工具类实现把一段对于KeyCode的形式化(不是用代码的)描述转换为KeyCode.java文件里的代码。
首先大佬博客里有对KeyCode的形式化描述。如:
现在通过一个工具类KeyCodeUtil把它给转化为代码描述。
把有关描述文件KeyCodeStatement放在容易找到的地方,我这里和KeyCodeUtil放在同一个文件夹下。
把大佬博客里的东西CV进Statement后还得略作修改,最后修改为如下所示:
描述中的大小写无所谓,后期由程序来保证最终结果的规范性。
工具类的运行结果:
把结果拷贝进KeyCode类。
配置解析器实现
本项目采用通过解析配置文件conf.xml的方式实现项目配置。
解析器文件结构:
接口
interfaces下放的是这个模块会用到的接口。
StepGoable接口是用于描述某种以固定帧率为时间间隔推进游戏的引擎实例的的配置类要实现的接口,我们接下来要做的俄罗斯方块就满足那个模型。因为方块可能是每10帧或者20帧下落一层。之所以不把帧率调低而每帧下落是出于事件捕获考虑,因为封装事件系统是每帧响应一次的。如是做可以使得方块在一次下落的时间内可以进行多次的移动和变形操作,更加符合需求。
SetCallback是用来描述在解析过程中修改对象值的回调的方法接口。
java beans
beans下是储存解析结果的java bean,同时也是解析规则的指定者。
所有具体java bean继承于com.test.gameengine.confreaders.beans.EngineConfugure。而com.test.gameengine.confreaders.beans.EngineConfugure又继承自com.test.gameengine.EngineConfugure。
主体
confreader目录下是解析器主体,负责注册和解析配置。为什么需要注册呢?因为我没有找到让Java像其他语言一样反射获取整个package下所有类信息的方案,所以就没有办法通过像规定特定包下的都为配置java bean,或者采用注解来标识的方法实现知道谁是配置的java bean。所以在解析前要先注册谁是配置java bean。以明确解析规则。
注册器解析器至此,配置解析器已经成功实现。
一些方法接口和通用类
在开始实现具体的游戏实例前再对一些接下来会用到方法接口和通用类作下介绍。
描述没有返回值传1个参数的回调。
描述有返回值传0个参数的回调。
描述有返回值传1个参数的回调。
以上的方法接口的设计也是参照C#/Unity的UnityAction<…>和Fun<…>
描述一个整数区间的类。
点阵地图模板
接下来正式开始实现俄罗斯方块的引擎实例。
我的本意是开发一些列小游戏的,所以我在游戏引擎基类→具体引擎实例之间加入了实例模板这一层结构。使得相似的逻辑可以被多个实例引用避免 冗余和多次编写带来的不良后果。
因为这个项目里的俄罗斯方块是基于点阵地图的,所以这里先实现一个点阵地图的实例模板。实例模板和引擎实例一样由配置类和引擎类组成。
配置类
引擎类
具体游戏实例
和实例模板一样,具体实例也主要由配置类和引擎类组成他们在本质上是一样的,实例模板实现的功能还是比较抽象,具体实例则具体到某个游戏的实现了。除此以外,我们把每次落下的方块叫做障碍物,出于描述游戏有哪些障碍物的需求,还需要一个障碍物类和障碍物池以构建障碍物系统。我们发现在构建障碍物池是需要用到一些繁琐的赋值。因此我们可以通过一个工具类把0101的形式化描述给转换为赋值语句。
障碍物系统
障碍物类工具类工具类会用到的描述形如:
命令说明:
#naXXX表示最后结果中的变量名为XXX。
#si表示障碍物规模即边长,出于正确性考虑我们约定障碍物的描述都为正方形。
#de表示要定义新的障碍物。
还有一个这里没有出现的命令。
#asX表示复制索引为X障碍物作为自身内容。
注:
#de和#as都是构建性的语句都会占有一个索引,也就是说#as也可以复制另一个#as的内容。
就实例描述而言,会得到结果:
游戏实例
配置类相对于点阵地图模板的配置类只是多了个拦截解障碍物配置和实现了StepGoable接口。
引擎类尾声
控制台部分
现在整个游戏已经呼之欲出啦。最后制作下控制台部分,即开始是让选游戏那部分。这里出于验证引擎系统的通用性将其视作一个没有窗口的引擎实例。
配置类因为控制台引擎更不没有窗口,所以不需要专门弄一个配置,直接使用配置的基类配置下最基本的最大帧率就行了。其实有没有这一项配置也不重要,这里是为了用实践验证引擎通用性故意为之,其实完全可以选择更加简单的方案来实现。
菜单打印工具这样的东西叫菜单:
因为我的本意是做一系列小游戏,可能后期会有打印很复杂的菜单的需求,所以这里将菜单打印功能封装起来,使其为打印大规模菜单提供便利。
引擎类源码分享
为了节约大家的下载次数,分享在 蓝奏云网盘,密码:6666。
整理的一些关于软考的项目学习资料+视频(附讲解~~),需要自取
https://d.51cto.com/bLN8S1
本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
赞 收藏 评论 举报相关文章