unity-ECS架构Entitas记录
关于 ECS框架 Entitas 的相关记录
前篇
官网
用Entitas开发游戏的体验是怎么样的 - https://www.zhihu.com/question/64701202
Unity使用ECS架构entitas实现ui响应及回放系统 - http://blog.csdn.net/qq992817263/article/details/78155443
Unity3D Entitas Wooga的ECS Entity Component System - http://blog.csdn.net/u012632851/article/details/75370836
流程图
自己用 visio 画的比较粗糙的框架流程, 方便了解整体框架的流程, 下载地址: ecs-entitas.vsd
Attributes
官网详解:https://github.com/sschmid/Entitas-CSharp/wiki/Attributes
Unique
在 context 中只存在一份实例,生成代码会在 Context 中生成几个属性
Context.{ComponentName}Entity
Context.{ComponentName}.{ComponentProperty}
(non-flag components)Context.Set{ComponentName}({ComponentProperty})
(non-flag components)Context.Replace{ComponentName}({ComponentProperty})
(non-flag components)Context.Remove{ComponentName}()
(non-flag components)Context.has{ComponentName}()
(non-flag components)
Define your component:
1 | using Entitas; |
You now have the following properties and methods available:
1 | var context = Contexts.core; |
初始化一个 unique 实例, 会生成一个对应的 context 的一个字段 isXxx,true 为生成, false 销毁
1 | readonly InputContext _context; |
PrimaryEntityIndex
EntityIndex
通过具体的 name get 到 对应环境下有用该组件的 所有entity 的值
1 | [ ] |
CustomComponentName
生成 PositionComponent, VelocityComponent
1 | [ ] |
DontGenerate
禁止生成代码
1 | using Entitas; |
添加组件 Component
假设所有的组件都定义在 GameComponents.cs 文件中
在 GameComponents.cs 中增加一个组件 SayComponent ,并增加属性
1
2
3
4
5
6//指定entity的标签为 Game, 也就是可以通过 GameEntity 访问到, 生成代码在 GameSayComponent.cs
[ ]
public class SayComponent : IComponent { //命名必须为 XxxComponent
public string msg;
public int age;
}然后生成代码 ctrl + shift + g , 可以看下生成后的代码 GameSayComponent.cs 都有些神马东东
1 | // 可以看到是通过 partial 关键字去扩展 GameEntity类,是其拥有对应组件的一些方法 |
- 生成一个 entity 后,添加组件 SayComponent
1 | GameEntity mover = _gameContext.CreateEntity(); |
通过entity访问组件 SayComponent 的属性
1
2
3foreach (GameEntity e in entities) {
Debug.LogFormat("--- SaySystem.Execute, say:{0}, age:{1}", e.say.msg, e.say.age);
}
获取指定组 Group
get 到 拥有 SpriteComponent组件 的所有entity 的组
1
2
3
4
5
6
7
8public class MiddleMouseKeyChangeSpriteSystem : IExecuteSystem
{
readonly IGroup<GameEntity> _sprites;
// 获取所有拥有Sprite的组
public MiddleMouseKeyChangeSpriteSystem(Contexts contexts)
{
_sprites = contexts.game.GetGroup(GameMatcher.Sprite);
}
添加系统 System
官网解释:https://github.com/sschmid/Entitas-CSharp/wiki/Systems
There are 4 different types of Systems:
- IInitializeSystem: Executes once (
system.Initialize()
)- IExecuteSystem: Executes every frame (
system.Execute()
)- ICleanupSystem: Executes every frame after the other systems are finished (
system.Cleanup()
)- ReactiveSystem: Executes when the observed group changed (
system.Execute(Entity[])
)
无论是那种系统,都需要添加进 Entitas 框架内,才能生效
1
2
3
4
5
6
7
8 public class AllSystems : Feature
{
public AllSystems(Contexts ctxs) : base("All Systems")
{
Add(new EmitInputSystem(ctxs));
Add(new CreateMoverSystem(ctxs));
}
}
反应系统 ReactiveSystem
ReactiveSystem:反应系统,只有在所监听的组件 _collector 有变化的时候,才会执行 Execute 方法,形参 entities 是发生变化的列表
需要重写一些方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class AddViewSystem : ReactiveSystem<GameEntity> {
// 创建Sprite的过滤器,指定 监听某种类型的 entity 的变化
protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context) {
return context.CreateCollector(GameMatcher.Sprite);
// return context.CreateCollector(InputMatcher.AllOf(InputMatcher.RightMouse, InputMatcher.MouseDown)); // 监听多种Entity
}
// 第二次过滤,没有View,没有关联上GameObject的情况
protected override bool Filter(GameEntity entity) {
return entity.hasSprite && !entity.hasView;
}
// 创建一个View的GameObject,并进行关联
protected override void Execute(List<GameEntity> entities) {
foreach (GameEntity e in entities) {
Debug.Log("--- AddViewSystem.Execute");
GameObject go = new GameObject("Game View");
go.transform.SetParent(_viewContainer, false);
e.AddView(go); // Entity关联GameObject
go.Link(e, _context); // GameObject关联Entity
}
}- Execute : 官网的解释是
Execute()
is where the bulk of your game logic resides ,也就是处理变化逻辑的地方
- Execute : 官网的解释是
混合反应系统 MultiReactiveSystem
解释:To react to changes of entities from multiple contexts you will need to use multi-reactive system
教程:https://github.com/sschmid/Entitas-CSharp/wiki/MultiReactiveSystem-Tutorial
普通update系统
实现接口 IExecuteSystem , 接受系统的 update
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class MiddleMouseKeyChangeSpriteSystem : IExecuteSystem
{
readonly IGroup<GameEntity> _sprites;
// 获取所有拥有Sprite的组
public MiddleMouseKeyChangeSpriteSystem(Contexts contexts) {
_sprites = contexts.game.GetGroup(GameMatcher.Sprite);
}
// 需要实现的接口
public void Execute() {
...
}
}