我目前正在学习"实体组件系统"。在阅读了许多教程和论坛主题之后,我仍然想知道渲染逻辑必须去哪里。我不是在谈论实际的OpenGL/DirectX渲染代码,例如,采用精灵并渲染它。我的意思是决定渲染哪个精灵的逻辑。
可见实体需要三个方面:
- 评估 AI(更改位置、状态等(
- 评估呈现状态。例如,当实体行走、攀爬、被击中时要使用的精灵循环......
- 实际渲染精灵
大多数教程建议使用AISystem(1.(作为逻辑和渲染系统(3.(来显示RenderComponent中定义的精灵(循环(。他们没有说的是渲染组件在哪里更新。我的理解是,仅仅将(2.(放入(1.(,从而将字符逻辑与渲染逻辑混合在一起,将是糟糕的设计。
直接的解决方案是为每个敌人添加一个特定的渲染逻辑系统。例如,对于Gumba,我可以添加一个GumbaLogicSystem,一个GumbaRenderLogicSystem,对于实际渲染,一个所有基于精灵的实体使用的通用SpriteRenderSystem。但是,这意味着为每个实体类型创建两个组件*和两个系统,这似乎不是一个好的解决方案。
有没有一个好的解决方案,在保持系统数量较少的同时分离字符逻辑和渲染逻辑?
谢谢
(* = 在简单方法中,系统根据实体的组件处理实体。为了让 GumbaRenderLogicSystem 在实体上工作,它需要一个 GumbaRenderingLogicComponent 才能被该系统识别。字符逻辑也是如此。
编辑1:我知道ECS是一种抽象模式。我的问题旨在了解如何保持系统数量较少的最佳实践。我的例子是出于游戏编程,但不限于这个领域。让我用一个更抽象的例子来解释:
想象一下,我有一些可见的实体。在基于层次结构的架构中,我会有这样的东西:
- SomeModel(继承自AbstractModel(
- SomeController (继承自 AbstractController(
- SomeRenderer(继承自PixelRenderer,而PixelRenderer又继承自AbstractRenderer(。
在 ECS 中,我需要一大堆新类:
- SomeModelSpecificDataComponent(即特定于此语义实体的数据(
- SomeModelSystem(执行逻辑(
- SomeModelSpecificRenderComponent(即渲染特定于此语义实体的数据(
- SomeModelSpecificRendererLogicSystem(决定如何渲染的系统(
- 像素渲染器系统
有什么方法可以减少需要引入的新系统的数量吗?一种解决方案可能是添加"代理"或"行为对象":一个通用的渲染组件附加了一个"渲染代理"类的实例,该类具有在渲染系统中调用的单个方法"更新"。因此,从技术上讲,组件不包含逻辑本身。不过,我担心这可能是过度设计的。
经过一段时间的思考和多次讨论,我意识到我的思维方式可能是错误的。我所描述的实际上适用于普通 ECS 方法。
防止系统和组件爆炸的唯一方法是对游戏元素进行适当的抽象,以便可以描述渲染的各种需求,而不是进行编程。
我的意思是,例如,精灵引擎必须允许足够的抽象,您只能通过存储在渲染系统评估的渲染组件中的描述来表达各种动画和状态。您还需要做的是将解决方案正确拆分为可重用的部分。
通过这种方式,ECS 比其他模式更能迫使您真正考虑一个好的架构。