Unity ECS 框架

Wesley13
• 阅读 1138

20180312

ECS编程思想

这种编程思想很早前就已经提出,ECS分别是Entity,Component,System的缩写.

  • Entity是实例,作为承载组件的载体,也是框架中维护对象的实体.
  • Component只包含数据,具备这个组件便具有这个功能.
  • System作为逻辑维护,维护对应的组件执行相关操作.

ECS和传统的OOP相比更看重的是组件,附加组件即具备功能.

C#是面向对象语言,从语言层面上就支持面向对象的编程思想:集成封装和多态.

  • 面向对象:我是什么,我有属性,我有方法,我要继承然后重写成自己独有的.

  • 面向组件:我有什么,我有组件便具备这个功能,我由很多组件组成了实体.

按照ECS的思路,功能拆分成组件,然后把这些细小的组件组合便组成了具备所需功能的对象.实际上Unity也是这种实现思路,但是它的组件式属性和逻辑的合集.

最近看了ECS编程思想,看了Entitas逻辑,写了小Demo,感觉:

编程思路/框架没有最好只有更合适,可能A框架适合RPG游戏,B框架更适合FPS游戏.

  • Entity的时序

    开发中经常会遇到控制时序的逻辑,比如某个Entity必须在另一个Entity逻辑完成后再执行,当然可以通过添加组件标识来控制时序执行,但是如果存在大量这种逻辑势必会增加很多对应的组件作为标识.

  • System时序

    同样可以添加Component作为控制标识作为过滤条件,A系统要在B系统结束之后,C系统启动之前,D系统挂起时...开发到后期怎么办.(待机,前摇,蓄能,施法,表现,结束,)太多太多状态一帧/分帧维护起来估计也会乱吧.

  • System更合适维护一组Entity

    • 比如FPS游戏,MOBA游戏用ECS思想拆分合适,每个玩家的角色功能对等(都是人物,都在移动,战斗)不同的角色的技能枪支拆分单独实现.

    • 如果是大型RPG游戏,每个门派角色,大厅npc,商城商人,敌人角色的状态动作各不相同,这种ECS当然能实现,每个功能,拆分成细小组件,创建对应System类维护,但是这样归根到底一个System经过遍历筛选其实只维护了一个Entity上面的组件.因为角色功能独有,以后这个组件也不会被其他Entity组合使用.

  • 功能解耦

    功能之间解耦,对应的组件和系统只关心本身的功能,不会对其他功能造成影响.

  • 重构

    不方便重构

  • 数据维护

    数据分散到对应的组件,比如服务器下发一份最新数据,需要一一维护对应组件的属性,数据收集也是如此.

  • 客户端服务器共享代码

    客户端拆分表现组件后,只包含纯逻辑功能.

  • 数据层表现层分离

    在不同的组件和系统中维护,不必像oop再拆分表现逻辑.

  • 方便扩展

    如果设计合理,可以通过现有组件组合新的Entity. 1- 性能

    数据在内存中线性存在,Entity复用.

ECS框架:Entitas

基于ECS的框架有很多,Entitas便是其中一个.

官方的ECS也会在2018.1beta版本中推出.

根据wiki很容易就能够搭建起项目,运行起工程,但是有些也需要开发者注意,比如Component作为标识还是作为数据存储;Component生成代码后改变类型或者删除字段后的生成报错,Group/Feature/Unit使用等等.

关于代码生成,它提供两个版本:

  • 免费版
  • 收费版

免费版根据反射生成代码,需要无编译错误下运行;收费版不需要,即使有代码报错也可以生成代码.

自己扩展的代码可以分为两部分:

  • Components
  • 其他代码(System,Service...等其他逻辑)

这样做的好处是重新生成代码时,方便的把这两个目录移除项目(或者StreamingAssets),生成基础代码,然后移回Component代码,然后生成组件代码,然后移回其他代码.

Entitas实践

最简单的输出hello world

源码: https://github.com/hiramtan/test/tree/Entitas_Example_HelloWorld

创建一个Component:

public class HelloWorldComponent : IComponent
{
    public string s;
}

生成代码后创建两个system,一个用来创建entity并附加组件,另一个用来输出日志:

public class CreatSystem : IInitializeSystem
{
    private Contexts _contexts;
    public CreatSystem(Contexts contexts)
    {
        _contexts = contexts;
    }
    public void Initialize()
    {
        var e = _contexts.game.CreateEntity();
        e.AddHelloWorld("hello world");
    }
}


public class HelloWorldSystem : ReactiveSystem<GameEntity>
{
    private Contexts _contexts;

    public HelloWorldSystem(Contexts contexts) : base(contexts.game){
    }

    protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
    {
        return context.CreateCollector(GameMatcher.HelloWorld);
    }
    protected override bool Filter(GameEntity entity)
    {
        return entity.hasHelloWorld;
    }
    protected override void Execute(List<GameEntity> entities)
    {
        foreach (var e in entities)
        {
            Debug.Log(e.helloWorld.s);
        }
    }
}

上面的代码已经实现了输出功能,但是为了方便管理上面的这两个System,我们添加一个RootSystems专门管理游戏中的各种System:

public class RootSystems : Feature
{
    public RootSystems(Contexts contexts)
    {
        Add(new CreatSystem(contexts));
        Add(new HelloWorldSystem(contexts));
    }
}

所有的功能都实现了,在unity工程中添加一个入口方法挂载到场景中,Main.cs:

public class Main : MonoBehaviour
{
    private RootSystems s;
    // Use this for initialization
    void Start()
    {
        s = new RootSystems(Contexts.sharedInstance);
        s.Initialize();
    }
    // Update is called once per frame
    void Update()
    {
        s.Execute();
    }
}

运行,正常输出,因为输出实现的是reactivesystem,当值发生变化时便会输出.

Unity ECS

今天untiy在beta版本中公布了自己的ECS系统,Entity,ComponentData,ComponentSystem,随着unity官方的引入,势必会被推广起来.

点击链接加入QQ群【83596104】:https://jq.qq.com/?_wv=1027&k=5l6rZEr


参考资料

  1. https://github.com/sschmid/Entitas-CSharp
  2. https://blog.codingnow.com/2017/06/overwatch_ecs.html
  3. http://www.ecsframework.com/
  4. https://youtu.be/OJmVBo5HGOY
  5. http://t-machine.org/index.php/category/entity-systems/
  6. http://www.benmutou.com/archives/2421
  7. https://www.cnblogs.com/yangrouchuan/p/7436533.html
  8. http://blog.csdn.net/u012632851/article/details/75370836
  9. http://blog.csdn.net/langresser_king/article/details/46324977
  10. http://blog.csdn.net/wuxiaoming1733/article/details/79037812
  11. http://blog.lmorchard.com/2013/11/27/entity-component-system/
  12. http://piemaster.net/2011/07/entity-component-primer/
  13. http://www.richardlord.net/blog/ecs/what-is-an-entity-framework.html
  14. http://blog.csdn.net/qq992817263/article/details/78155443
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
ET框架学习
参加实习一个月了公司新项目准备使用ET框架进行开发在走通et的流程之前我们必须了解一个概念:ECS组件式编程这个概念有区别于我们我们常见的unity开发思路(虽然unity本身也是采用了给go添加component),在unity开发中,常见的思路是entitymanager,就是说把业务抽象成实体管理器的模式,实体就是抽象出来的
Stella981 Stella981
3年前
Spring Boot日志集成
!(https://oscimg.oschina.net/oscnet/1bde8e8d00e848be8b84e9d1d44c9e5c.jpg)SpringBoot日志框架SpringBoot支持JavaUtilLogging,Log4j2,Lockback作为日志框架,如果你使用star
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这