zoukankan      html  css  js  c++  java
  • 提炼游戏引擎系列:初步设计引擎

    前言

    本文为后续引擎提炼定下了一个大致的方向,没有给出完整的引擎架构。这就够了!让我们在具体开发过程中再来从底向上设计吧!

    本文目的

    1、进行引擎提炼的前期规划,明确引擎提炼的整体流程和引擎的非功能性需求。
    2、从炸弹人领域模型中提炼出精简的领域模型,作为炸弹人的参考模型。
    3、从炸弹人参考模型中提炼出抽象的领域模型,作为引擎的初步领域模型。

    本文主要内容

    前期规划

    开发流程

    引擎提炼的整个流程如下图所示:

    说明

    • 回顾炸弹人游戏
    介绍炸弹人游戏的基本情况,回顾炸弹人游戏的设计

    • 初步设计引擎
    给出引擎的初步设计,从炸弹人领域模型中提炼出一个精简的领域模型,作为炸弹人的参考模型,再从中提炼出一个抽象的领域模型,作为引擎的初步领域模型

    • 第一次迭代
    参考引擎的初步领域模型,从炸弹人参考模型中提炼出对应的通用类和基础的引擎框架,使引擎具备游戏入口、预加载、主循环、层、精灵、动画、事件管理等基本功能,并将炸弹人游戏改造为基于引擎实现,通过测试。
    • 第二次迭代
    进一步提炼炸弹人类和引擎类,提炼通用模式,消除引擎中的用户逻辑,进行引擎的整体梳理和修改,对应修改炸弹人游戏,通过测试。

    本文进行“回顾炸弹人游戏”和“初步设计引擎”这两个步骤。

    引擎非功能性需求

    1、可测试性
    引擎是一个可复用的组件,应该保证正确和可测试。
    方案:编写全覆盖引擎的单元测试。
    炸弹人游戏有完整的单元测试,可以将其修改为引擎的单元测试。

    注:本系列不会讨论测试。
    2、可扩展性
    本系列提炼的引擎还不完善,后续会加入更多的功能,因此引擎需要具有灵活的架构,满足开闭原则,方便以后的扩展。
    引擎应该支持插件化开发,独立功能的模块可以作为通用插件从引擎中独立出去,由用户选择是否引入到引擎中。
    方案:基于高内聚低耦合的总体思想,使用面向对象思想,复用炸弹人游戏中可扩展性的模块,从中提炼引擎,保持良好的引擎架构。

    3、可读性
    引擎应该具备良好的可读性,易于后续开发时理解之前的设计,方便他人理解引擎的实现。
    方案:
    (1)保持代码整洁
    (2)只保留必要的注释
    (3)编写必要的文档
    (4)通过良好的命名和测试用例来辅助读者理解代码
    (5)代码风格应该统一

    回顾炸弹人设计

    本节会介绍炸弹人游戏的基本情况,让大家有个整体印象。

    炸弹人系列博文

    炸弹人游戏开发系列

    炸弹人源码下载

    炸弹人源码下载

    炸弹人外部依赖

    在炸弹人游戏中,我使用了以下的库:
    第三方库
    • jQuery
    使用它的选择器,进行dom操作。
    • progressBar
    这是一个jQuery的进度条插件,我用它来显示预加载图片的进度。
    • jasmine
    这是一个测试框架,使用它可以进行Javascript单元测试。
    我的库
    • YOOP(命名空间:YYC.Class、YYC.AClass、YYC.Interface)
    这是我的Javascript的oop框架。具体可参见发布我的Javascript OOP框架YOOP
    • 图片预加载控件PreLoadImg(命名空间:YYC.Control)
    • 工具库YTool(命名空间:YYC.Tool)
    我的工具方法库。
    • jsExtend
    Javascript原生对象扩展,对js的String和Array对象进行了扩展。
    • 模式库(命名空间:YYC.Pattern)
    包括创建对象模式的命名空间方法namespace和观察者模式的Observer.js

    炸弹人的概念层次结构

    炸弹人领域模型

    炸弹人游戏的领域模型如下图所示:

    查看大图

    初步设计引擎

    本节提出了我在实践过程中总结的引擎设计原则,以及炸弹人的参考模型和引擎的初步领域模型,为后面的引擎提炼打下了基础。

    引擎设计原则

    1、引擎不应该依赖用户,用户应该依赖引擎

    引擎应该保持通用性,不应该包含用户逻辑。

    2、尽量减少引擎依赖的外部文件
    因为:
    (1)增加引擎的不稳定性
    依赖的外部文件变化时,引擎也需要对应修改。
    (2)外部文件不一定完全适合引擎
    外部文件不是基于引擎开发的,可能需要对其进行改造,从而适合引擎的需要。但是由于外部文件不稳定或者对外部文件实现不了解等原因,想要针对引擎的具体情况进行改造比较困难。
    (3)加大用户负担
    引擎可能只需要使用外部文件的一小部分,但是却需要引入整个外部文件,这会增加引擎的整个文件大小,加大用户负担。

    所以:
    (1)如果必须要依赖,也尽量依赖自己开发的库,而不要依赖第三库。
    (2)第三方库可以作为插件引入到引擎中,由用户自行选择。
    (3)可考虑将第三方库改造为引擎的内部库。
    a.如果引擎依赖的是自己开发的、没有发布的库,则可以直接引入,作为引擎的内部库
    因为自己开发的、独立发布的库需要独立变化,不应该与引擎绑到一起。
    b.如果引擎只依赖第三方库的部分内容,则可将依赖的第三方库的最小集提取为引擎的内部库。

    3、引擎应该具有很好的可扩展性
    这里可扩展性包括两个方面:引擎可扩展性和用户可扩展性。
    (1)引擎可扩展性
    在前面的非功能性需求中已经说过了,引擎应该具有灵活的架构,方便以后的扩展。
    (2)用户可扩展性
    用户可扩展性指用户可以插入自己的逻辑到引擎中,实现引擎的变化点。

    4、尽量减少用户负担
    引擎应该实现底层逻辑,用户只负责实现业务逻辑。
    引擎应该尽量封装高层API,提供给用户使用,减少用户的工作量。

    代码组织方式

    文件组织方式一般有两种:
    1、使用js模块加载器(如sea.js)。在沙箱环境中,将需要引用的文件加载进来,然后通过局部变量名来使用。
    2、使用命名空间。

    因为:
    (1)引擎文件数量不是很多,还不需要用模块加载器。
    (2)如果使用模块加载器,则引擎必须依赖模块加载器,用户使用引擎时也必须按照模块加载器的方式来引用引擎文件,这样会增加复杂度,加大用户负担。

    所以引擎采用命名空间的方式来组织文件,引擎的顶级命名空间为YE。

    引擎名

    该引擎命名为YEngine2D。

    代码结构

    炸弹人和引擎代码结构如下图所示:

    • Content
      炸弹人游戏的资源文件
      • Image
        图片资源文件
    • Scripts
      js文件
      • bomber
        炸弹人js文件
      • myTool
        工具
        • frame
          框架文件
        • pattern
          模式文件
        • tool
          工具文件
      • plugin
        外部插件
      • yEngine2D
        引擎文件
    • Views
      页面

    思考

    1、炸弹人改造为基于引擎实现后,是否需要通过炸弹人的单元测试?
    因为:
    (1)在提炼引擎的过程中,引擎变动频繁,引擎变动会导致使用引擎的炸弹人变动,对应的炸弹人单元测试也会可能跟着变动。这样就需要经常修改单元测试,工作量太大。
    (2)我不会二次开发炸弹人游戏,不需要维护炸弹人的单元测试。
    (3)本系列的重点是提炼引擎,应该把精力都集中在引擎上。
    综上所述,只对引擎进行单元测试,而不再维护炸弹人的单元测试,改为直接通过浏览器运行炸弹人游戏来进行运行测试。

    2、引擎应该是通用的,还是只针对“炸弹人游戏”所属的RPG类型?
    因为提炼引擎的目的是为了更快地开发游戏,不仅仅只有RPG类型,也包括其它类型的游戏,所以应该提出一个通用的引擎。
    然而本系列并不能提出一个完全通用的引擎,因为我是从炸弹人游戏中提炼引擎的,该引擎只能保证适应炸弹人这种RPG类型的游戏。提炼通用引擎是一个长期任务,目前我只能在提炼引擎时尽可能地消除炸弹人游戏的用户逻辑,提高通用性。在以后的实践中,需要将该引擎尽可能多地应用到不同类型的游戏中,这样才能最终得到一个通用的游戏引擎。

    领域模型分析

    炸弹人参考模型

    对炸弹人的领域模型进行精简,去掉具体的实现类,只保留必要的、能体现整个概念层次结构的和游戏框架的类:

    精简后的领域模型即为本系列的炸弹人参考模型。

    引擎初步领域模型

    对炸弹人参考模型进行抽象,提出抽象角色类(一个角色类可代表多个具体类,如DataOperate类,在炸弹人游戏中代表了MapDataOperate、GetPath等类),作为引擎的初步领域模型。

    • Config
      全局配置类,存放游戏中的常量、枚举值、配置信息。

    • LoadResource
      加载资源的类,负责加载各种资源

    • Main
      入口类,是整个系统的入口,负责启动游戏,页面只与该类耦合,该类是整个系统的入口。

    • Director
      游戏主逻辑类,负责游戏的统一调度。

    为什么命名不沿用炸弹人的“Game”?
    因为“Game”这个名字范围太大,不能突出“统一调度”的职责,因此命名为“Director”更为合适

    • Scene
      场景类,为集合类,从炸弹人的LayerManager抽象而来,负责管理场景。

    在炸弹人游戏开发中,我从“如何统一调度各个层”的逻辑出发,提出了层管理类LayerManager。
    现在可以进一步抽象,提出“场景”这个概念,游戏中可能包含多个场景(至少一个),场景类Scene与“场景”是1对1的关系,Scene不仅负责统一调度场景内各个层,还应该包含与场景的相关的属性和方法。

    • Hash
      具有哈希结构的集合类。

    • Layer
      层类,为集合类,负责层内精灵的统一管理。

    该类对应“分层渲染”的概念,一个Layer对应一个画布canvas。

    • Collection
      具有线性结构的集合类。

    • Sprite
      精灵类。
      每一个单独的个体都是一个精灵类。如玩家、敌人、炸弹等,与该个体密切相关的属性和方法都放到该类中。

    • AI
      人工智能类,负责实现人工智能算法,具体可以包括寻路算法、敌人的移动模式和行为设置等。

    • Factory
      工厂类,负责创建类的实例,封装类的创建逻辑。

    • Animation
      帧动画控制类,负责控制帧动画的播放。

    • DataOperator
      数据操作类,负责对数据进行读、写操作。

    • Data
      数据类,保存游戏数据

    • EventManager
      事件管理类,负责事件的监听和移除。

    最新的引擎版本

    有兴趣的话您可以看下最新的引擎版本(这个不是本系列博文提出的引擎版本,而是最新修改后的引擎版本):
    发布HTML5 2D游戏引擎YEngine2D

    参考资料

    炸弹人游戏系列

    上一篇博文

    提炼游戏引擎系列:开篇介绍

    下一篇博文

    提炼游戏引擎系列:第一次迭代

  • 相关阅读:
    matlab矩阵中如何去掉重复的行;如何找到相同的行,并找到其位置
    Coursera 机器学习 第9章(下) Recommender Systems 学习笔记
    机器学习基石笔记1——在何时可以使用机器学习(1)
    Coursera 机器学习 第9章(上) Anomaly Detection 学习笔记
    matlab安装过程的被要求的配置程序
    jdk环境变量配置
    Coursera 机器学习 第8章(下) Dimensionality Reduction 学习笔记
    Coursera 机器学习 第8章(上) Unsupervised Learning 学习笔记
    Coursera 机器学习 第7章 Support Vector Machines 学习笔记
    linux服务器---squid限制
  • 原文地址:https://www.cnblogs.com/chaogex/p/4152381.html
Copyright © 2011-2022 走看看