Plug and documentation: https://github.com/sschmid/Entitas-CSharp/wiki/Home
Information:
What is Entitas
Entitas high operating efficiency of a lightweight C # Entity-Component-System ( ECS) framework, customized specifically for unity. Internal cache and provide quick access to components. It has been carefully designed to work best in garbage collection environment.
## Advantages and disadvantages:
Comments from big brother
advantage:
- Follow the rules of this framework to write code, clear code structure.
- ECS this mode, the coupling is very low, all the combinations of objects are game components only, scalable, can be arranged through the rational combination of component a new game object.
- Very convenient to manage all state entities, entitas provides functionality similar state machine, when a property changes of interest, can easily respond to the System, the state no matter what, can easily make correspondence processing.
- unity itself on a similar development model ECS, unity2018 is the introduction of a new framework for ECS, entitas is in line with this development model
- entitas since open source, has been updating and maintenance, and by the unity of official recognition, has mentioned unite Conference. So, this framework is still very tricky.
Disadvantages:
- Domestic less information, high difficult to get started. Domestic use this framework to develop particularly small, encountered problems to climb their own pit.
- Not suitable for small projects. Small projects but trouble with entitas
- entitas update too fast, did not keep up with the official wiki documentation updates, for example, I was watching the official Demo-MatchOne, there is an Attribute Event, and yet do not have this on the wiki
- 代码热更方面是个问题, entitas基本对unity开发定了一套完整的规则,特别是有Code Generate,如果项目发布后想要更新加入新的代码会很麻烦,官方对此也没有说明,目前好像也没有人分享在entitas中加入lua热更的功能
编程思想
面向对象思想强调对象,通过对象自身属性等完成具体实现。ECS则强调过程,通过并无实际意义的实体来收集作为数据的容器来完成具体实现。
- E:Entity无实际意义,仅作为收集组合C的容器。
- C:Component包含数据的组件,无方法实现。
S:处理数据的系统,自身无任何数据,通过方法来实现。
Entitas基本概念
+------------------+
| Context |
|------------------|
| e e | +-----------+
| e e---|----> | Entity |
| e e | |-----------|
| e e e | | Component |
| e e | | | +-----------+
| e e | | Component-|----> | Component |
| e e e | | | |-----------|
| e e e | | Component | | Data |
+------------------+ +-----------+ +-----------+
|
|
| +-------------+ Groups:
| | e | Subsets of entities in the context
| | e e | for blazing fast querying
+---> | +------------+
| e | | |
| e | e | e |
+--------|----+ e |
| e |
| e e |
+------------+
Entity
entity是一个存储数据的容器,用以表现程序中存在的对象。你可以添加,替换和移除数据通过IComponent。Entitas也有相应的事件event来通知你这些变化。
Entitas通过代码生成器可以自然的产生很多易读的代码如下文中的方法便是代码生成器自动产生的API调用。
entity.AddPosition(3, 7);
entity.AddHealth(100);
entity.isMovable = true;
entity.ReplacePosition(10, 100);
entity.ReplaceHealth(entity.health.value - 1);
entity.isMovable = false;
entity.RemovePosition();
var hasPos = entity.hasPosition;
var movable = entity.isMovable;
Context
Context是一个让你可以创建和销毁实体entities的工厂。通过它可以过滤感兴趣的实体。
// Contexts.game is kindly generated for you by the code generator
var gameContext = Contexts.game;
var entity = gameContext.CreateEntity();
entity.isMovable = true;
// Returns all entities having MovableComponent and PositionComponent.
// Matchers are also generated for you.
var entities = gameContext.GetEntities(Matcher<GameEntity>.AllOf(GameMatcher.Movable, GameMatcher.Position));
foreach (var e in entities) {
// do something
}
Group
通过组Group,可以对上下文中的实体进行超快速过滤。 当实体更改时,它们会不断更新,并且可以立即返回实体组。 想象一下,您有成千上万个实体,而您只需要那些具有PositionComponent的实体-只需询问该组Group的上下文,它的结果就已经被筛选完成。
gameContext.GetGroup(GameMatcher.Position).GetEntities();
Group和获取的entities都被缓存下来,所以该方法运行速度非常高。尽可能的优先使用Group。gameContext.GetEntities(GameMatcher.Moveble)同样可以内部地使用groups。
Groups有OnEntityAdded,OnEntityRemoved,OnEntityUpdated来对group变化作出响应。
gameContext.GetGroup(GameMatcher.Position).OnEntityAdded += (group, entity, index, component) => {
// Do something
};
如果你想汇总和处理这些变化,可以使用Collector
Collector
Collector提供了便捷的方法来对group的变化作出反应。比如你想汇总和处理所有添加或替换PositionComponent的实体entities。
var group = gameContext.GetGroup(GameMatcher.Position);
var collector = group.CreateCollector(GroupEvent.Added);
接下来
foreach (var e in collector.collectedEntities) {
// do something with all the entities
// that have been collected to this point of time
}
collector.ClearCollectedEntities();
停用collector可以方便的结束监视
collector.Deactivate();
Matcher
Matcher匹配器由代码生成器生成,可以组合。匹配器通常用于从感兴趣的上下文中获取实体组。需要在匹配器前加上你感兴趣的上下文名称(例如GameMatcher, InputMatcher等)。
System
entitas中有四种Systems:
- IInitializeSystem: 只执行一次 (system.Initialize())
- IExecuteSystem: 每帧执行 (system.Execute())
- ICleanupSystem: 在其他系统完成后每一帧执行(system.Cleanup())
- ReactiveSystem: 当观察的group改变时执行(system.Execute(Entity[]))
public class MoveSystem : IExecuteSystem {
public void Execute() {
// Do sth
}
}
public class CreateLevelSystem : IInitializeSystem {
public void Initialize() {
// Do sth
}
}
public class RenderPositionSystem: ReactiveSystem<GameEntity> {
public RenderPositionSystem(Contexts contexts) : base(contexts.Game) {
}
protected override Collector<GameEntity> GetTrigger(IContext<GameEntity> context) {
return context.CreateCollector(GameMatcher.Position);
}
protected override bool Filter(GameEntity entity) {
// check for required components (here it is position and view)
return entity.hasPosition && entity.hasView;
}
protected override void Execute(List<GameEntity> entities) {
foreach (var e in entities) {
// do stuff to the matched entities
e.view.gameObject.transform.position = e.position.position;
}
}
}
Finally, it should be noted that the need to create a System's System Management, as a game development process, can not be just a System, in order to facilitate the management, there was the concept [Feature] System of. This class should inherit Feature, Add all System into the constructor. Feature like a System of SystemManager management.
var systems = new Systems(contexts)
.Add(new CreateLevelSystem(contexts))
.Add(new UpdateBoardSystem(contexts))
.Add(new MoveSystem(contexts))
.Add(new RenderPositionSystem(contexts));
// Call once on start
systems.Initialize();
// Call every frame
systems.Execute();
/ To be continued