基于ECS的开发的游戏框架(包含众多游戏扩展类,不仅限ECS框架)

基于ECS的游戏框架

项目地址: esengine/ecs-framework: 一套ecs框架,可用于egret/laya/cocos及其他使用ts/js语言的引擎 (github.com)

框架介绍

ecs-framework 的目标是成为功能强大的框架。我们不仅仅提供了ECS框架,还有更为强劲的游戏基础框架。它为您构建游戏提供了坚实的基础。它包括的许多功能包括:

  • 完整的场景/实体/组件系统
  • SpatialHash用于超快速的广相物理学查找。您永远不会看到它,因为它在幕后起作用,但是您仍然会喜欢它,因为它可以通过射线广播或重叠检查迅速找到您附近的所有事物。
  • AABB,圆和多边形碰撞/触发检测
    • ShapeCollisionsBox
    • ShapeCollisionsCircle
    • ShapeCollisionsLine
    • ShapeCollisionsPoint
    • ShapeCollisionsPolygon
  • 高效的协程,可在多个帧或动画定时中分解大型任务(Core.startCoroutine)
  • 通过Astar和广度优先搜索提供寻路支持,以查找图块地图或您自己的自定义格式 ( 参见 https://github.com/esengine/ecs-astar )
  • tween系统。任何number / Vector / 矩形/字段或属性都可以tween。 (参见 https://github.com/esengine/ecs-tween)
  • 针对核心事件的优化的事件发射器(发射器类),您也可以将其添加到自己的任何类中
  • 延迟和重复任务的调度程序(核心调度方法)
  • 丰富的数学支持库
    • MathHelper
    • Bezier
    • Matrix2D
    • Vector2
    • Rectangle
    • Flags

框架讨论

之前在社区里看到有关于ECS框架的讨论了。相信大家对ECS也有了一个概念。因为受到语言的影响,并没有多线程也没有内存布局的控制,所以框架也没有采用传统的ECS架构。typescript与其他语言不同,因此我对ecs的设计尽可能的支持typescript特性

ECS比起其他设计模式更灵活,可以更好的集中、组织、排序和过滤游戏中的对象。ecs让您拥有轻量级实体和组件,这些组件可以由系统批量处理。
例如,您在制作一个射手,您可能会有几十到几百个子弹,这些作为轻量级实体由系统批量处理。

渲染结合

为了使框架与cocos更加贴合使用,提供了一个项目示例,地址如下:

esengine/cocos-framework: 基于cocos与ecs-framework开发的框架 (github.com)

里面包含了几个渲染相关的例子(没有提供关于ECS的具体使用方式,后续还会更新更多的例子)

  • 基础场景

  • LineCast 射线检测

  • ArcadeRigidBody

19赞

太强啦,前排顶一下

好东西,多谢分享

看了Example,按我看过比较纯净ecs框架的经验,不明太白component为啥会有这么多方法和Update,而看不到明显的System定义。。?

export class component_camera extends es.Component implements es.IUpdatable, es.ICamera {
    // ...
    public update() {
        this.camera.node.setPosition(new Vec3(this.position.x, this.position.y, 1000));
        // let camera = this.camera.getComponent(Camera);
        // if (camera) camera.orthoHeight = 320 + 320 * this.zoom;
    }
}

准确定义,似乎不是真正意义上的ECS框架(Entity-Component-System),更像是Cocos现在的组件模式(Node-Component)。

Example没有提供关于ECS的具体使用,如果需要查看ECS使用请参阅原项目README介绍

ECS框架的基本使用

创建实体

创建实体一般由场景控制。您需要在场景内进行创建或添加实体(createEntity / addEntity)

注意:创建实体需要在场景onStart方法进行创建,而不是直接在initialize方法内创建。initialize 只是在构造函数完成后进行调用,此时该场景并未被激活。

class MainScene extends es.Scene {
    onStart() {
        // 创建一个名为player的实体
        const player = this.createEntity("player");
    }
}

添加组件

每个实体都会有多个组件,如果我们需要实体能够拥有一个新的能力,则需要给它添加相对应的组件,组件必须继承 es.Component 来标志为组件。

注意:组件一般没有具体逻辑,一般只存放一些属性,逻辑应该由系统进行调用

class MovementComponent extends es.Component { 
    // 定义该实体的移动速度
    public moveSpeed: number = 100;
}

将组件添加至Player实体上(addComponent)

class MainScene extends es.Scene {
    onStart() {
        // 创建一个名为player的实体,createEntity方法会将创建的实体返回给你
        const player = this.createEntity("player");
        // 为实体添加一个移动组件,addComponent会将新建的移动组件返回给你
        const moveComponent = player.addComponent(new MovementComponent())
    }
}

添加系统

系统里会使用Matcher类帮助过滤它所感兴趣的实体并对其进行更新。我们一般定义系统会与对应的组件相匹配,刚我们创建了一个移动组件,则相对应的就会有一个移动系统来处理该类型的组件。

这里我们使用es.EntityProcessingSystem,因为我们要对带有移动组件的实体进行更新。

系统也分多种类型,分为管理实体的系统(es.EntityProcessingSystem)/管理系统的系统(es.ProcessingSystem)

class MoveSystem extends es.EntityProcessingSystem {
    // 必须实现
    processEntity(entity: Entity) {
        // 这里会传入带有MoveComponent的实体
        // 为什么会传入只带有MoveComponent的实体? 
        // 因为在构造函数中有一个Matcher匹配器,在你初始化MoveSystem的时候需要你传入匹配的对象. 见下方如何定义匹配带MoveComponent的匹配器

        // 该方法每帧都会执行,请确保您的操作尽可能的小或者在使用大数据时采用缓存的方法进行获取操作
        const moveComponent = entity.getComponent(MovementComponent);
        if (!moveComponent.enabled)
            return;

        // 根据moveComponent的数据执行移动的逻辑
    }
}

定义Matcher匹配器匹配所有带MoveComponent的实体

// 这里你可以传入多个组件类型
// one 满足
const matcher = Matcher.empty().all(MovementComponent);

激活系统

使用addEntityProcessor方法进行添加系统

class MainScene extends es.Scene {
    onStart() {
        const matcher = Matcher.empty().all(MovementComponent);
        // 将所有带MoveComponent的实体送到该系统处理
        this.addEntityProcessor(new MoveSystem(matcher));

        // 创建一个名为player的实体,createEntity方法会将创建的实体返回给你
        const player = this.createEntity("player");
        // 为实体添加一个移动组件,addComponent会将新建的移动组件返回给你
        const moveComponent = player.addComponent(new MovementComponent());
    }
}

抱歉,看得不仔细。 :flushed:

框架并没有采用传统ECS。在传统ECS上进行了扩展改造,框架的目的是为了提供游戏的基础方法,框架适用于所有使用TS/JS的游戏引擎

mark一下

我的只是个小玩具。

框架都是辅助工具,真正还是要看使用的人。根据你的实际情况来使用就行了,目前这个框架我自己也在多个游戏类型当中使用到,还是比较方便的。

mark,后面也许用得着

跟白鹭那个EgretPro的ecs很像,不过扩展了很多东西

腻害~腻害~大佬们都有绝活~:ox::beer:~

v1.2.2 更新
https://github.com/esengine/ecs-framework/releases

  1. component的update允许更新
  2. 优化框架性能,Time支持传入自定义dt
  3. 优化vector2构造函数
  4. 新增渲染接口
  5. 修复arcadeRigidBody不触发onEntityTransform事件
  6. 修复mover碰撞失效问题
  7. 修复mover返回collisionResult无数据问题
  8. 新增phycics.debugDraw默认绘制(需要实现渲染接口后才可使用)
  9. 新增圆盒重叠检查
  10. 完善Color类
  11. 新增角色控制器(包含单向平台,跳跃及斜坡)
  12. math库完善

大佬,角色控制器这部分怎么用的

白鹭pro很久没更新了

有做到内存布局控制的ECS框架
但受限于JS本身, 框架使用的是SoA (Structure of Arrays), 而非AoS (Array of Structures)
并发也暂时不支持, 但仍是有趣的设计 :grinning:

bitECS
https://github.com/NateTheGreatt/bitECS

wolf-ecs
https://github.com/EnderShadow8/wolf-ecs

2赞

mark 回去再看

mark!!!

mark!!!