复合模式/实体系统和传统OOP

Dav*_*nco 18 java language-agnostic design-patterns composite

我正在开发一个用Java编写的小游戏(但这个问题与语言无关).因为我想探索各种设计模式,所以我对复合模式 /实体系统(我最初在这里这里读到)作为典型的深层次继承的替代方案.

现在,在写了几千行代码后,我有点困惑.我认为理解模式,我喜欢使用它.我认为它非常酷,而且星巴克也是如此,但它觉得它提供的好处有点短暂而且(最让我烦恼的是)在很大程度上取决于你的粒度.

这是上面第二篇文章的图片: 在此输入图像描述

我喜欢对象(游戏实体或任何你想要称之为的东西)的方式有一组最小的组件,推断的想法是你可以编写类似于下面的代码:

BaseEntity Alien = new BaseEntity();
BaseEntity Player = new BaseEntity();

Alien.addComponent(new Position(), new Movement(), new Render(), new Script(), new Target());
Player.addComponent(new Position(), new Movement(), new Render(), new Script(), new Physics());
Run Code Online (Sandbox Code Playgroud)

..这将是非常好的...但在现实中,代码最终看起来像

BaseEntity Alien = new BaseEntity();
BaseEntity Player = new BaseEntity();

Alien.addComponent(new Position(), new AlienAIMovement(), new RenderAlien(), new ScriptAlien(), new Target());
Player.addComponent(new Position(), new KeyboardInputMovement(), new RenderPlayer(), new ScriptPlayer(), new PhysicsPlayer());
Run Code Online (Sandbox Code Playgroud)

似乎我最终得到了一些由较少组件组成的非常专业的组件.通常,我必须制作一些具有其他组件依赖性的组件.毕竟,如果你没有位置,你怎么渲染?不仅如此,你最终渲染玩家与外星人和手榴弹的方式可能根本不同.除非你制作一个非常大的组件(在这种情况下......为什么你还在使用复合模式?),你不能拥有一个指示所有三个组件的组件.

给出另一个真实的例子.我的游戏中有角色可以装备各种装备.当装备一件装备时,会改变一些统计数据以及视觉上显示的内容.这是我的代码现在的样子:

billy.addControllers(new Movement(), new Position(), new CharacterAnimationRender(), new KeyboardCharacterInput());

billy.get(CharacterAnimationRender.class).setBody(BODY.NORMAL_BODY);
billy.get(CharacterAnimationRender.class).setFace(FACE.BLUSH_FACE);
billy.get(CharacterAnimationRender.class).setHair(HAIR.RED_HAIR);
billy.get(CharacterAnimationRender.class).setDress(DRESS.DRAGON_PLATE_ARMOR);
Run Code Online (Sandbox Code Playgroud)

以上CharacterAnimationRender.class仅影响VISUALLY显示的内容.所以我显然需要制作另一个处理齿轮属性的组件.但是,为什么我会这样做:

billy.addControllers(new CharacterStatistics());

billy.get(CharacterAnimationRender.class).setBody(BODY.NORMAL_BODY);
billy.get(CharacterStatistics.class).setBodyStats(BODY_STATS.NORMAL_BODY);
Run Code Online (Sandbox Code Playgroud)

当我可以制作一个CharacterGearStuff控制器/组件来处理统计数据的分布和视觉变化?

最重要的是,我不确定这应该如何帮助提高工作效率,因为除非您想手动处理所有内容,否则您仍然需要创建依赖于2个以上组件的"元组件"(并修改/交叉修改所有组件)子组件 - 将我们带回OOP).或者也许我在想它完全错了.我呢?

Ada*_*dam 6

听起来你有点误解了组件模式.

组件只是数据,没有代码.如果你的组件中有代码,它不再是一个组件 - 它更复杂.

因此,例如,您应该能够轻松地分享您的CharacterAnimationRender和CharacterStatistics,例如:

CharacterStats { int BODY }
CharacterGameStats { ...not sure what data you have that affects gameplay, but NOT the rendering... }
CharacterVisualDetails { int FACE, int HAIR }
Run Code Online (Sandbox Code Playgroud)

......但是没有必要让他们意识到彼此的存在.当你谈论组件之间的"依赖关系"时,我暂停你已经迷路了.一个int的结构如何"依赖"另一个int结构?他们不能.它们只是大块的数据.

...

回到开头的问题,你最终会:

Alien.addComponent(new Position(), new AlienAIMovement(), new RenderAlien(), new ScriptAlien(), new Target());
Player.addComponent(new Position(), new KeyboardInputMovement(), new RenderPlayer(), new ScriptPlayer(), new PhysicsPlayer());
Run Code Online (Sandbox Code Playgroud)

...那很完美.假设您已正确编写这些组件,您已将数据拆分为易于读取/调试/编辑/编码的小块.

然而,这是在猜测,因为你没有指定这些组件中的内容......例如AlienAIMovement - 那是什么?通常情况下,我希望你有一个"AIMovement()",然后编辑它以使其成为Alien的版本,例如更改该组件中的一些内部标志以使用AI系统中的"Alien"功能来表示它.