游戏设计模式读书笔记:组件模式

Posted by 蔡华的博客 on August 28, 2017

为什么是组件

意图

  • 允许单一的实体跨越多个领域而不会导致这些领域彼此耦合。

实体-组件-系统(ECS)

  • 组件模式在游戏中常见的体现就是ECS

为什么是组件

  • 在游戏开发中一个实体会有多个不同的功能,比如音频的播放、动画功能、渲染、物理、输入等等,如果所有的功能都按照类的形式写到一个类文件中会非常的庞大且不易维护。
  • 将不同类型的功能切分成不同的组件,既是对结构的优化也是实现了功能的复用。

为什么不是类的继承

  • 因为可能一个实体的在继承多个父类(C++,但是C#这样的语言在语法上就不行)时出现重复继承的问题。比如实体的父类的父类出现重复的问题。

模式

  • 单一实体跨越了多个领域。为了保持领域之间相互分离,将每部分代码放入各自的组件类中。实体被简化为组件的容器。

何时使用

  • 组件通常在定义游戏实体的核心部分中使用。
  • 有一个涉及了多个领域的类,而你想保持这些领域互相隔离。
  • 一个类正在变大而且越来越难以使用。
  • 想要能定义一系列分享不同能力的类,但是使用继承无法让你精确选取要重用的部分。

一些问题

  • 组件之间的通信问题
  • 组件的获得需要先获取实体,才能获得组件对象。

实现

  • 建议直接看原书代码。

进化过程

  • 1.先将不同的功能模块分为不同的组件,实体类本身只是调用组件中的方法(作为容器),参数为自身。
  • 2.对组件类进行接口化,最后变成实体类中只要使用继承自接口的类即可。对于接口的不同实现就可以实现不同的功能。

设计决策

对象如何获得组件

对象创建组件
  • 自己创建所以一定能拿到需要的组件
  • 组件模式的优势在于自由的将不同的组件赋予一个对象,从而让对象获得不同的能力,或者说变成了某个特定的游戏对象。但是如果用硬编码的方式获得组件,那么这个对象就定型了。
外部提供组件
  • 对象更加灵活。我们可以提供不同的组件,这样就能改变对象的行为。 通过共用组件,对象变成了组件容器,我们可以为不同目的一遍又一遍重用它。
  • 对象可以与具体的组件类型解耦。 如果我们允许外部代码提供组件,好处是也可以传递派生的组件类型。 这样,对象只知道组件接口而不知道组件的具体类型。这是一个很好的封装结构。
  • PS:细细体会unity的组件实现。

组件之间如何通信

通过修改容器对象的状态:
  • 这个可以参考unity的实现。在unity中每个GameObject都必须有transform组件,以为位置、角度和缩放信息算是所有对象都必须有的,而且在物理组件、渲染组件中都需要用到。
  • 但是这个方案的问题就在于,如果一个GameObject使用了多个组件,而这些组件在修改数据时可能需要一定的顺序才行,比如计算移动的组件需要限制性,在执行物理相关和渲染相关的,因为可能一个对象在一帧中已经离开了摄像机范围而不需要渲染了。
互相引用
  • 这个没什么好多解释的,掌握了对象的引用自然可以获得其数据和方法。
  • 但是这个是一种倒退,因为耦合了。
消息机制
  • 恩恩,尤其是使用订阅发布模式的消息系统。

参考

  • 原文
  • 一个不错的框架,我是先学习了这个框架在看这个文章的,醍醐灌顶之感。