游戏邦在:
杂志专栏:
gamerboom.com订阅到鲜果订阅到抓虾google reader订阅到有道订阅到QQ邮箱订阅到帮看

阐述实体组件模式所存在的问题

发布时间:2014-04-21 18:47:38 Tags:,,

作者:Sean Farrell

在过去10年里,实体组件模式取得了巨大的发展。但是如果你着眼于它的设计,会发现涌现出来的问题远远多于它所解决的问题。

一般说来,实体组件模式可以概括为:一个由组件组成的实体,每个组件都发挥着一个独特的作用。实体并不包含任何自身的逻辑,但却受到了所谓的组件的驱动。

entity(from gamedev)

entity(from gamedev)

但是实体组件模式尝试着去解决什么问题呢?

实体组件模式的每个图解都是从一个经典的受对象驱动的谜题而开始:基于直角的较深的继承阶层架构。例如你拥有一个地精类别。你形成了2个地精类别的领域,飞翔的地精能够飞翔,而魔法地精能够使用魔法。但这里所存在的问题在于我们很难去创造飞翔魔法地精。

Goblin(from gamedev)

Goblin(from gamedev)

甚至是利用C++和它的多重继承功能,你也不知道该怎么做,你仍需要解决可怕的钻石和虚拟的继承。但大多数语言并不支持一种简明的方式去执行它。

在解决组件的问题时,GroundMovement, FlyingMovment, MeleeAttack以及MagicAttack组件被创造了出来,基于此我们可以组成不同类型的地精。

flyingmagicgoblin(from gamedev)

flyingmagicgoblin(from gamedev)

做得好,现在我们将从一个反面模式(较深的继承阶层架构)过度到一个不同的反面模式中(较广的继承阶层架构)。核心问题在于继承阶层架构尝试着整合直角理念,但这却不是个好主意。为什么不使用两个对象阶层,一个用于攻击模式,一个用于移动模式呢?

attack(from gamedev.net)

attack(from gamedev.net)

就像你在对象趋向角度所看到的,实体组件模式在这方面表现得很糟糕。但这并不是实体组件模式尝试着解决的唯一问题。

在很多情况下你将看到受数据驱动的引擎的理念。该理念在于你可以通过从代码移动对象组合到某些数据形式中而缩短开发时间。这让游戏设计师能够通过编写一些XML或使用一个独特的编辑器去”创造“新对象。尽管潜在的动机是有效的,它却不需要使用一个实体组件模式,就像一些反面例子便呈现出这点。

将结构批评置于一旁,实体组件模式的执行是绝不可能有效的。在大多数情况下,组件并不是移动或攻击的有效理念,它们更适合渲染和碰撞检测。但除非你拥有额外的管理结构,你需要着眼于每个实体比检查它是否拥有与渲染过程相关的组件。

world(from gamedev)

world(from gamedev)

解决问题(无需从根本上改变设计)的最简单的方法便是引进系统。在这种情况下,真正的执行是在系统内部,组件只是指示预想的行为。结果在于系统拥有所有相关的数据,并且是基于非常简洁的格式,且能够有效地发挥作用。

world 2(from gamedev.net)

world 2(from gamedev.net)

但如果你凑近点看的话会发现我们拥有所有的这些无用的组件。如果你删除了组件并指示使用组件上的属性,并且系统只是指望指定的属性的话会怎样?现在你拥有的是鸭子类型(游戏邦注:duck typing,它是动态类型的一种风格。)

world 3(from gamedev.net)

world 3(from gamedev.net)

鸭子类型是经常用于较弱的语言中的理念,例如JavaScript或Python。在此的主要理念在于实际类型较不相干,但特定的属性和功能将在特定的环境中出现在特定的对象上。例如如果它是文件流,内存流或网络套接字的话便是不相干的—-如果它具有编写功能的话便能够用于连续对象。

鸭子类型的问题在于并不能简单地适应原生语言。你可以使用一些不同类型编造一些解决方法,但这绝不是一种有效的解决方法。

有可能你已经拥有一个脚本系统,在这种情况下解决方法便较为直接,你可以在脚本中执行核心的游戏逻辑,潜在的系统将着眼于这种定义并在原生代码中执行任何提升。交替较重和脚软的层面的理念并不是什么心内容,并且将被当成是灵活性和执行所需要的。

你可能会认为在脚本中执行游戏逻辑是无效的。在这种情况下,你正在创造一款模拟游戏,这是没错的。在这些情况下,提取你的逻辑并将其压缩到核心理念是有意义的。然后你将针对于模拟层直接执行表现层和控制层。

graphic(from gamedev)

graphic(from gamedev)

关于这一设计的突出之处在于你可以分解表现层和模拟层,从而可以将其中一个置于一台计算机上,另一个置于其它计算机上。

network(from gamedev.net)

network(from gamedev.net)

等等,我们是否只是在说MVC?让我们改变对象。

当着眼于可扩展性时你将拥有一些有趣的需求。关于实体组件系统的一个非常巧妙的执行是将其设置为MMO。这里所存在的理念在于实体和组件并未存在与代码中,但却是数据库中的内容。系统被分布于多台计算机上,并且每一个都是基于它们自己的节奏,按照规定浏览并编写到数据库中。

alsystem(from gamedev.net)

alsystem(from gamedev.net)

这样的设计解决了一个分布式系统的需求,并提醒了我NASA和NATO使用High Level Architecture去连接多个实时模拟。这一设计方法也拥有其自身的标准。

是个明智的方法,那我们应该怎么做呢?

如果你在阅读这些问题,你要么是在创造游戏引擎,要么就是在创造游戏。要知道每一款游戏都有不同的需求,游戏引擎需要尝试着满足许多不同的需求。你要牢记自己所开发的内容以及需求的范围。如果你现在的设计很糟糕,你并不需要采取极端的做法去拯救你的设计,因为有可能你将不再需要它。你应该尝试着采取最明智的方法去解决自己所面对的问题。发挥创造性并着眼于别人的做法是有效的。(本文为游戏邦/gamerboom.com编译,拒绝任何不保留版权的转载,如需转载请联系:游戏邦

A Critique of the Entity Component Model

By Sean “rioki” Farrell

The entity component model is all the rave for the last decade. But if you look at the design it opens more issues than it solves.

Broadly speaking the entity component model can be summarized as the following: An entity is composed of components who each serve a unique purpose. The entity does not contain any logic of its own but is empowered by said components.

But what does the entity component model try to solve?

Each and every illustration of the entity component model starts with a classic object oriented conundrum: a deep inheritance hierarchy with orthogonal proposes. For example you have a Goblin class. You form two specialisations of the Goblin class, the FylingGoblin who can fly and the MagicGoblin who uses magic spells. The problem is that it is hard to create the FylingMagicGoblin.

Even with C++ and its multiple inheritance, you are not in the clear as you still have the dreaded diamond and virtual inheritance to solve. But most languages simply do not support a concise way to implement it.

When solving the issue with components, the components GroundMovement, FlyingMovment, MeleeAttack and MagicAttack are created and the different types of goblins are composed from these.

Good job, now we went from one anti-pattern (deep inheritance hierarchy) to a different anti-pattern (wide inheritance hierarchy). The central issue is that the inheritance hierarchy tries to incorporate orthogonal concepts and that is never a good idea. Why not have two object hierarchies, one for attack modes and one for movement modes?

As you can see from an object oriented standpoint the entity component model fares quite poorly. But that is not the only problem the entity component model tries to solve.

In many cases you see the concept of a data driven engine. The idea is that you can cut down on development time by moving the object composition out of the code and into some form of data. This allows game designers to “build” new objects by writing some XML or using a fancy editor. Although the underlying motivation is valid, it does not need to use an entity component model, as a few counter examples show quite well.

Putting the structural criticism aside, a naive implementation of the entity component model can in no way be efficient. In most cases the components are not such high concepts as moving or attacking, they are more along the lines of rendering and collision detection. But unless you have additional management structures, you need to look at each and every entity and check if it has components that are relevant for the rendering process.

The simplest way to resolve the issue, without altering the design too radically, is the introduction of systems. In this case the actual implementation is within the systems and the components are just indicating the desired behaviour. The result is that a system has all the relevant data in a very concise and compact format and as a result can operate quite efficiently.

But if you look closely you can see that we have all these useless components. What if you removed the components and just used properties on the components and the systems just look for appropriately named properties? Now you have duck typing.

Duck typing is a concept that is used a lot in weakly typed languages, like for example JavaScript or Python. The main idea here is that the actual type is irrelevant, but specific properties and function are expected on a given object within a specific context. For example it is irrelevant if it is a file stream, a memory stream or a network socket – if it has the write function it can be used to serialize objects to.

The problem with duck typing is that is does not lend itself easily to native languages. You can cook up some solution using some varying type but in no way is this an elegant solution.

Chances are you already have a scripting system, in this case the solution is quite straight forward, you implement the core game logic in scripts and underlying systems look at this definition and implement any heavy lifting in native code. The idea of alternating hard and soft layers is nothing new and should be considered where flexibility and performance is needed.

You may think that implementing the game logic in scripts is an inefficient way to do it. In cases where you are building a simulation-oriented game this may be quite true. In these cases is makes sense to extract your logic and reduce it to its core concepts, a simulaiton if you will. Then implement the presentation layer and control layers externally directly against the simulation layer.

The nice thing about this design is that you can split the presentation layer and simulation so far that you can put one of them on one computer and the other on a different one.

Wait, did you just describe MVC? Um… No… Stop changing the subject.

When looking into scalability you get interesting requirements. One very clever implementation of the entity component system was make it scale in an MMO setting. The idea here is that entities and components do not exist in code, but are entries in a database. The systems are distributed over multiple computers and each work at their own pace and read and write to the dabase as required.

This design addresses the need of a distributed system and reminds me of the High Level Architecture][10] used by NASA and NATO to hook up multiple real-time simulations together. Yes this design approach even has its own standard, the IEEE 1516.

Ok, oh wise one, what should we do?

If you read about these issues you are either building a game engine or a game. Each and every game has different requirements and game engines try to satisfy a subset of these different requirements. Remember what you are developing and the scope of your requirements. If your current design sucks, you do not need to go overboard with your design, because chances are you aren’t gonna need it. Try to make the smallest step that will solve the problem you are facing. It pays out to be creative and look at what others have done.(source:gamedev)


上一篇:

下一篇: