Articles of 实体系统

了解实体组件模型

可能重复: 实体状态在基于组件的系统中的角色? 所以,我听说过一些关于游戏编程的模型,涉及到创建实体,然后附加不同的组件来改变它们的行为。 所以,一个敌方实体可能会附加AI的组件,碰撞物理等等。这似乎是一个很好的解决创建引擎问题的方法,但是我并不确切地知道一个实体或组件是。 所以我的问题是:实体对象封装到底是什么? 我将如何去附加组件?

初始化具有构造函数参数的实体

我正在开发基于回合的基于拼图的益智游戏,并创建新的实体,我使用以下代码: Field.CreateEntity(10, 5, Factory.Player()); 这会在[10; 5]。 我正在使用类似工厂的类来通过组合来创建实体。 这就是CreateEntity方法的样子: public void CreateEntity(int mX, int mY, Entity mEntity) { mEntity.Field = this; TileManager.AddEntity(mEntity, true); GetTile(mX, mY).AddEntity(mEntity); mEntity.Initialize(); InvokeOnEntityCreated(mEntity); } 由于实体的许多组件(以及逻辑)需要知道它们所在的图块,或者它们所属的字段是什么,所以我需要mEntity.Initialize(); 知道实体何时知道自己的领域和瓦片。 Initialize(); 方法包含对事件处理程序的调用,以便我可以在工厂类中这样做: result.OnInitialize += () => result.AddTags(TDLibConstants.GroundWalkableTag, TDLibConstants.TrapdoorTag); result.OnInitialize += () => result.AddComponents(new RenderComponent(), new ElementComponent(), new DirectionComponent()); 这个工作到目前为止,但它不是优雅的,它是非常开放的错误。 我也使用相同的想法与组件:他们有一个无参数的构造函数,当你调用AddComponent(mComponent); 方法,实体的工作是将组件的实体设置为自己。 另一种方法是在工厂类中使用Field,int,int参数来执行如下操作: new Entity(Field, 10, 5); […]

实体组件系统中的属性所有权

您通常如何处理这些系统中的数据所有权? 现在我只有一个映射types(std :: string或hashed int) – > void *,其中外部源可以通过简单的AddAttribute方法添加属性。 现在我遇到了删除某些数据的地方和方法的问题,因为有些数据是通过外部源添加的(例如,引用另一个实体),其中一些是包含它的实体的合法数据(例如健康属性)。 最明显的解决scheme将是简单地使用共享指针,但不知何故,我担心,当我有很多实体时,他们的开销会变得明显(请参阅https://stackoverflow.com/questions/3628081/shared-ptr-horrible速度 )。 另一个我可以想到的解决scheme是首先使用两个不同的方法:“AddAttributeExternal”和“AddAttributeInternal”(或类似的命名是无关的),其中属性只会删除通过第二个添加的数据。 但是我想避免这种情况,因为它引入了重复的代码,当你引入大量的数据变化时,可能会出错。 有更好的/更优化的解决scheme,还是我需要改变我对实体数据的思维方式?

我怎样才能有效地更新只有在给定的框架中重要的实体?

我正在制作一个RTS,它可能在一张地图上有很多单位(想想帝国时代 )。 我正在寻找更新我的单位的方法。 我想避免在每个实体的每一帧都调用一个虚拟的Update()方法。 另一方面,那些看不见的单位仍然应该更新,并“正常”行事。 我假设这是一个相当标准的问题; 怎样处理这种情况呢?

这种实体/组件组织如何提高caching效率?

我一直在读实体组件系统作为OpenGL引擎的devise模式。 我试图实现的风格有实体只是整数,组件是长连续的数组,例如世界位置组件的glm::vec3 。 实体整数然后作为索引进入这些数组。 所有这一切都被这篇文章描述得最好。 据我所知,ECS的主要好处包括: 简化和消除不必要的依赖和意大利面代码 性能提升:连续的组件arrays转化为更less的caching未命中以及复杂inheritance的整体去除 虽然我同意第一点,但我不明白第二点如何是真的。 在常规的平局上,你几乎总是需要大部分组件。 您需要位置,缩放,旋转以将MVPmatrix加载到着色器中。 你需要网格和纹理来渲染自己。 你甚至需要浅色的细节或是否投射阴影。 一切! 这意味着您将不可避免地遇到某种forms的caching未命中,因为您无法将您的组件arrays放入caching中。 除此之外,由于实体整数是组件数组中的索引, 所以每当添加一个实体时, 所有组件数组的大小都需要增大,而与其types无关。 这意味着添加30个没有网格的实体将不可避免地生成30个永远不会被使用的空网格分配。 你将如何实现这样一个系统,以真正减less不必要的内存浪费,caching未命中?

如何让我的组件只包含原始数据?

我在阅读ECS中的组件仅仅是数据,没有逻辑。 我试图按照这个,我得到了这个工作: class Sprite : public Component { public: Sprite(const std::string &textureid = ""); std::string getTextureId() const; void setTextureId(const std::string& textureid); void setColor(const Color& color); Color getColor() const; private: std::string m_textureid; Color m_color; }; 现在在我的SpriteRenderingSystem中,我必须为每个具有一个Sprite组件的实体创建每个框架(我现在正在使用它),设置该对象的参数,渲染并销毁它。 我知道这不是优化,我不喜欢它。 我认为我可以使用我的组件来保存一个指向SFML :: Sprite对象的指针,然后我只需要在每一帧都渲染它,而不必像下面那样创建/设置/渲染/销毁它: class Sprite : public Component { public: Sprite(const std::string &textureid = ""); std::string getTextureId() const; void […]

如何打击精灵信息的指数增长?

在我的2D平台游戏中,我有一些在世界各地移动的精灵。 当两个小精灵相互碰撞时,我计算出碰撞有多深,然后调用一个虚拟方法来让两个精灵处理碰撞(例如,一个火球会杀死另一个精灵)。 每个精灵都被检查是否与其他“精灵”的精灵碰撞。 “Nearness”是通过我的懒四叉树确定的,它实际上只是一个大小均匀的单元格列表,对象被sorting。 然而,虚拟方法调用(或消息)的数量随着精灵同时碰撞的次数呈指数增长,导致<1fps,屏幕上只有大约120个精灵。 如果三个精灵彼此重叠,则需要发送六个消息。 四个精灵需要12个消息,二十个精灵需要380个消息。 即使将游戏世界划分为单元格,检查冲突的代价也是非常高昂的 – 如果30个精灵在同一个单元格中,则需要900次碰撞检查。 现在,我不希望有120个屏幕上的精灵成为常态 – 它可能接近20,但我真的关心可播放和幻灯片之间的范围有多小。 我强烈怀疑,如果我真的希望每个精灵都相互传递信息,那么没有比N*(N-1)/2消息更好的方法。 有什么我可以做的,以降低成本? 编辑:根据要求,这是相关的代码 : foreach (var collidableSprite in Sprites.GetItemsNearItem(sprite)) { if (Object.ReferenceEquals(collidableSprite, sprite)) { continue; } BoundingRectangle hitboxA = sprite.Hitbox; BoundingRectangle hitboxB = collidableSprite.Hitbox; Vector2 intersectA = hitboxA.GetIntersectionDepth(hitboxB); Vector2 intersectB = hitboxB.GetIntersectionDepth(hitboxA); if (!intersectA.IsNaN() && !intersectB.IsNaN()) { sprite.HandleSpriteCollision(collidableSprite, intersectA); collidableSprite.HandleSpriteCollision(sprite, intersectB); } […]

我应该如何devise窗口,input和行为系统之间的游戏对象依赖关系?

这是我第一次尝试创建一个游戏引擎。 我遇到了一个理论问题,希望在实施之前解决。 现在我有一个WindowSystem ,它打开窗口,设置GL_CONTEXT等,我希望它负责所有的东西窗口。 然后我有另一个系统管理input称为InputSystem 。 然后我有一个游戏对象行为的行为系统。 问题:考虑一个代表菜单的游戏对象,它可以select更改分辨率/其他graphics设置。 我怎样才能以最小的耦合链接这三个系统,以便Behavior脚本可以closures窗口? 通常情况下,系统通过组件进行交互,但是窗口没有组件。 从我读过的系统不应该彼此了解。 我不知道如何去做这样的事情。

访问实体configuration数据,不用单例

每个实体都有一些随时间变化的统计信息,有些统计信息对于一个给定types的实体是静态的。 例如,当前的hp vs max hp:可以说人类的最大值为100hp,那么每个人都有一个int hp成员,但是对于所有的人来说const int max_hp=100是没有意义的,因为它总是一样的东西。 这可以通过使用static成员variables来解决,但这里有一个问题:我想在应用程序启动时从configuration文件中加载所有的统计信息,例如max_hp ,这就排除了static使用。 我知道如何协调这两件事情的唯一方法是使用单例对象,它通过类似于singleton::instance().model("human").stat("max_hp")向实体提供其统计信息。 但是,我所见过的每一个单身人士都提到了警告他们不要使用它们。 而且我也不想使用它,因为那样我的实体更新方法就失去了参照透明性。 所以简而言之: 我想避免重复的数据。 我想从文件加载数据。 我想避免全球状态。 更新方法必须是纯函数。 我可以用什么策略来满足这些要求? 我需要更新方法是纯粹的,因为我的引擎是围绕并行更新每个实体的概念而构建的,要做到这一点的方法是让entity.update成为一个纯函数,它接受一个不变的对世界的引用并返回一个新的实体[0]。 所以每个实体都通过制作自己的副本来开始自己的更新,然后在更新过程中进行变更,直到最终返回到世界,成为新一代实体的体现。 现在如果只有dynamic数据被复制,那将会是很多复制的! 但是,要复制所有(重复)静态数据每一帧都是疯狂的,我正在寻找的方法,让我只能复制dynamic统计数据,同时仍然可以访问模型数据。 [0] https://www.youtube.com/watch?v=Uooh0Y9fC_M

如何在实体系统中创建通用字符实体?

在下面的代码是我在实体系统中创建一个字符的方式。 但我认为这是脱钩的,我很难与这个class级脱钩。 第一种方法 public enum CharacterType { PLAYER_CHARACTER, // PC or a character controlled by a player NON_PLAYER_CHARACTER // NPC or a character controlled by a computer it self (artificial intelligence), but notice that it is a friendly character } public class Character { // Player-Character can be controlled by the player it self // […]