Bevy Entity

145 阅读2分钟

work-for-sql-query-databases.jpg

从上一篇Bevy Component我们基本认识了ECS中的Component,这篇文章,我们将介绍Entity

EntityComponent是紧密相连的,从比较高的视角看,Entity可以拥有零个或者多个Component实例。

每个Entity只能拥有一个Component类型的一个组件,也就是同类组件只能有一个。可以在整个实体的生命周期中动态添加或删除这些类型。

Entity实际上是代表其相关组件索引的标识符。

Entity即索引

Entity类型是一种轻巧的标识符,仅用于生成他的WorldBevy中的概念,可以暂时理解为应用)。

// https://github.com/bevyengine/bevy/blob/main/crates/bevy_ecs/src/entity/mod.rs
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub struct Entity {
  generation: u32,
  index: u32,
}

Entity本身只有indexgeneration两个属性,该类的设计可以保证Entity在维持内存连续性的基础上完成快速的数据插入删除,这正是Bevy高效率的原因之一。

EntityWorld的视角

每个World都会有一个Entity的列表,其中包含3组实体ID

  • freelist:已经吧被释放的ID
  • reserved:曾经在freelist中,但是现在被保留着。
  • pengding:暂时不存在的新的ID计数。

Entity中的generationindex确保同时存在的两个实体将永远不会共享相同的索引。

每当具有给定索引的实体被销毁时,其对应的“代次”(Generation)会递增。这一机制用于记录该索引被重复使用的次数。

这些唯一的标识符使Bevy能够以惰性方式分配它们。先保留ID,然后分配。

当然我们在使用Bevy开发游戏的时候,不需要关心这些,生成一个Entity,只需要:

fn spawn_health(
  mut commands: Commands
) {
  commands.spawn(Health(0));
}

关于索引的分配流程,如下图所示:

graph TD
    A[Entity创建] --> B[分配新索引]
    B -->|首次分配| C[索引N, 世代0]
    C --> D[销毁实体]
    D --> E[加入空闲列表]
    E --> F[再次分配]
    F --> G[索引N, 世代+1]

总结

到此,关于BevyECS的基本介绍就完成了,后续,我们将会研究Bevy的其他方面。