All Projects → shangdibaozi → ECS

shangdibaozi / ECS

Licence: MIT license
Entity-Component-System

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to ECS

Entitas Lite
Entitas-Lite is a No-CodeGenerator branch of Entitas, and also a fast & easy ECS framework for C#/Unity.
Stars: ✭ 106 (-13.11%)
Mutual labels:  ecs, entity-component-system
Flecs
A fast entity component system (ECS) for C & C++
Stars: ✭ 2,201 (+1704.1%)
Mutual labels:  ecs, entity-component-system
Edyn
Edyn is a real-time physics engine organized as an ECS.
Stars: ✭ 113 (-7.38%)
Mutual labels:  ecs, entity-component-system
Learning Unity Ecs 2
A bunch of small Unity projects where I explore and learn Unity's new ECS and Job System. Updated for the new API.
Stars: ✭ 65 (-46.72%)
Mutual labels:  ecs, entity-component-system
SpaceWar-ECS
A space war game made with ECS and JobSystem in Unity.
Stars: ✭ 26 (-78.69%)
Mutual labels:  ecs, entity-component-system
Rust Game Development Frameworks
List of curated frameworks by the **Game Development in Rust** community.
Stars: ✭ 81 (-33.61%)
Mutual labels:  ecs, entity-component-system
Pyro
A linear Entity Component System
Stars: ✭ 125 (+2.46%)
Mutual labels:  ecs, entity-component-system
Svelto.ecs
Svelto ECS C# Lightweight Data Oriented Entity Component System Framework
Stars: ✭ 605 (+395.9%)
Mutual labels:  ecs, entity-component-system
Awesome Entity Component System
😎 A curated list of Entity-Component-System (ECS) libraries and resources
Stars: ✭ 180 (+47.54%)
Mutual labels:  ecs, entity-component-system
Uecs
Ubpa Entity-Component-System (U ECS) in Unity3D-style
Stars: ✭ 174 (+42.62%)
Mutual labels:  ecs, entity-component-system
Endless Runner Entitas Ecs
Runner template for Unity
Stars: ✭ 41 (-66.39%)
Mutual labels:  ecs, entity-component-system
Entitas Cpp
Entitas++ is a fast Entity Component System (ECS) C++11 port of Entitas C#
Stars: ✭ 229 (+87.7%)
Mutual labels:  ecs, entity-component-system
Ecs
A simple and easy to use entity-component-system C++ library
Stars: ✭ 20 (-83.61%)
Mutual labels:  ecs, entity-component-system
Entitas Sync Framework
Networking framework for Entitas ECS. Targeted at turnbased games or other slow-paced genres.
Stars: ✭ 98 (-19.67%)
Mutual labels:  ecs, entity-component-system
Ecs.hpp
C++17 Entity Component System
Stars: ✭ 25 (-79.51%)
Mutual labels:  ecs, entity-component-system
Gdk For Unity Fps Starter Project
SpatialOS GDK for Unity FPS Starter Project
Stars: ✭ 119 (-2.46%)
Mutual labels:  ecs, entity-component-system
Entt
Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more
Stars: ✭ 6,017 (+4831.97%)
Mutual labels:  ecs, entity-component-system
Ecs
LeoECS is a fast Entity Component System (ECS) Framework powered by C# with optional integration to Unity
Stars: ✭ 578 (+373.77%)
Mutual labels:  ecs, entity-component-system
Ape Ecs
Entity-Component-System library for JavaScript.
Stars: ✭ 137 (+12.3%)
Mutual labels:  ecs, entity-component-system
Egocs
EgoCS: An Entity (GameObject) Component System framework for Unity3D
Stars: ✭ 211 (+72.95%)
Mutual labels:  ecs, entity-component-system

简介

这是一个Typescript语言版的Entity-Component-System框架。框架参考了Unity的Entitas框架。

案例

Crimsonland

InfinityWar

使用说明

组件

自定义组件必须继承ecs.Comp,并且需要使用ecs.register注册组件。

@ecs.register('Hello')
export class HelloComponent extends ecs.Comp {
    info: string;
    data: number;

    // 组件被回收前会调用这个方法。
    reset() {
        this.info = '';
        this.data = 0;
    }
}

tag类组件

@ecs.registerTag()
export class ECSTag {
    static Tag1: number;
    static Tag2: number;
    static tag3: number;
}

// 相关使用方法
ecs.createEntityWithComps(Comp1, ECSTag.Tag1)

ent.has(ECSTag.Tag1)

ent.add(ECSTag.Tag2)

ent.remove(ECSTag.Tag2)

ecs.register功能

  • 能通过entity.Hello获得组件对象;
  • 将组件的构造函数存入ecs上下文中,并且给该类组件分配一个组件id。

ecs.registerTag

  • tag类组件必须用registerTag来装饰

实体

为了能利用Typescript的类型提示机制,在使用实体的时候需要用户自己继承ecs.Entity。

export class HelloEntity extends ecs.Entity {
    Hello: HelloComponent; // 这里的Hello要和ecs.register中填入的参数一致
}
  • 添加组件:
entity.add(HelloComponent); // 添加组件时会优先从组件缓存池中获取无用的组件对象,如果没有才会新创建一个组件对象
  • 添加组件对象:注意,外部创建的组件对象ecs系统不负责回收,需要用户自己管理该组件对象的声明周期。
let compObj = new HelloComponent();
entity.add(compObj)
  • 删除组件:
entity.remove(HelloComponent); // 组件对象会从实体身上移除并放入组件缓存池中
  • 删除组件但不删除组件对象:实际开发中,组件身上有很多属性,如果删除了后面再添加,属性值还原是个麻烦的问题, remove方法可以删除组件,但是不真正从实体身上移除该组件对象,这样下次重新添加组件时还是会添加那个组件对象。
entity.remove(HelloComponent, false)
  • 获得组件对象
1、entity.Hello; // 见上方自定义实体操作

2、entity.get(HelloComponent);
  • 判断是否拥有组件:
1、entity.has(HelloComponent);

2!!entity.Hello;
  • 销毁实体:
entity.destroy() // 销毁实体时会先删除实体身上的所有组件,然后将实体放入实体缓存池中

实体筛选

目前提供了四种类型的筛选能力,但是这四种筛选能力可以组合从而提供更强大的筛选功能。

  • anyOf: 用来描述包含任意一个这些组件的实体;
  • allOf: 用来描述同时包含了这些组件的实体;
  • onlyOf: 用来描述只包含了这些组件的实体;不是特殊情况不建议使用onlyOf,因为onlyOf会监听所有组件的添加和删除事件;
  • excludeOf: 表示不包含所有这里面的组件(“与”关系);

使用方式:

  • 表示同时拥有多个组件
ecs.allOf(AComponent, BComponent, CComponent);
  • 表示拥有任意一个组件
ecs.anyOf(AComponent, BComponent);
  • 表示拥有某些组件,并且不包含某些组件
// 不包含CComponent或者DComponent
ecs.allOf(AComponent, BComponent).excludeOf(CComponent, DComponent);

// 不同时包含CComponent和DComponent
ecs.allOf(AComponent, BComponent).excludeOf(CComponent).excludeOf(DComponent);

直接查询并获得实体

ecs.query(ecs.allOf(Comp1, Comp2))

系统

  • ecs.System: 用来组合某一功能所包含的System;
  • ecs.RootSystem: System的root;
  • ecs.ComblockSystem: 抽象类,组合式的System。默认情况,如果该System有实体,则每帧都会执行update方法;
  • ecs.IEntityEnterSystem: 实现这个接口表示关注实体的首次进入;
  • ecs.IEntityRemoveSystem: 实现这个接口表示关注实体的移除;
  • ecs.ISystemFirstUpdate: 实现这个接口会在System第一次执行update前执行一次firstUpdate

怎么使用

1、声明组件

@ecs.register('Node')
export class NodeComponent extends ecs.Comp {
    val: cc.Node = null;

    reset() {
        this.val = null;
    }
}

@ecs.reigster('Move')
export class MoveComponent extends ecs.Comp {
    heading: cc.Vec2 = cc.v2();
    speed: number = 0;

    reset() {
        this.heading.x = 0;
        this.heading.y = 0;
        this.speed = 0;
    }
}

@ecs.register('Transform')
export class TransformComponent extends ecs.Comp {
    position: cc.Vec2 = cc.v2();
    angle: number;
    reset() {
    
    }
}

export class AvatarEntity extends ecs.Entity {
    Node: NodeComponent;
    Move: MoveComponent;
    Transform: TransformComponent;
}

2、创建系统

export class RoomSystem extends ecs.RootSystem {
    constructor() {
        super();
        this.add(new MoveSystem());
        this.add(new RenderSystem());
    }
}

export class MoveSystem extends ecs.ComblockSystem<AvatarEntity> implements ecs.IEntityEnterSystem {

    init() {
    
    }

    filter(): ecs.IMatcher {
        return ecs.allOf(MoveComponent, TransformComponent);
    }

     // 实体第一次进入MoveSystem会进入此方法
    entityEnter(entities: AvatarEntity[]) {
        for(e of entities) {
            e.Move.speed = 100;
        }
    }
    
    // 每帧都会更新
    update(entities: AvatarEntity[]) {
        for(let e of entities) {
            let moveComp = e.Move; // e.get(MoveComponent);
            lel position = e.Transform.position;
            
            position.x += moveComp.heading.x * moveComp.speed * this.dt;
            position.y += moveComp.heading.y * moveComp.speed * this.dt;
            
            e.Transform.angle = cc.misc.lerp(e.Transform.angle, Math.atan2(moveComp.speed.y, moveComp.speed.x) * cc.macro.DEG, dt);
        }
    }
}

export class RenderSystem extends.ecs.ComblockSystem<AvatarEntity> implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem {
    filter(): ecs.IMatcher {
        return ecs.allOf(NodeComponent, TransformComponent);
    }
    
    // 实体第一次进入MoveSystem会进入此方法
    entityEnter(entities: AvatarEntity[]) {
        for(e of entities) {
            e.Node.val.active = true;
        }
    }
    
    entityRemove(entities: AvatarEntity[]) {
        for(let e of entities) {
            // Global.avatarNodePool.put(e.Node.val);
        }
    }
    
    update(entities: AvatarEntity[]) {
        for(let e of entities) {
            e.Node.val.setPosition(e.Transform.position);
            e.Node.val.angle = e.Transform.angle;
        }
    }
}

3、驱动ecs框架

const { ccclass, property } = cc._decorator;
@ccclass
export class GameControllerBehaviour extends cc.Component {
    rootSystem: RootSystem = null;

    onLoad() {
        this.rootSystem = new RootSystem();
        this.rootSystem.init();
    }
    
    createAvatar(node: cc.Node) {
        let entity = ecs.createEntityWithComps<AvatarEntity>(NodeComponent, TransformComponent, MoveComponent);
        entity.Node.val = node;
        // entity.Move.speed = 100;
    }

    update(dt: number) {
        this.rootSystem.execute(dt);
    }
}

和Cocos Creator的组件混合使用

创建基类

import { Component, _decorator } from "cc";
import { ecs } from "../../../Libs/ECS";
const { ccclass, property } = _decorator;

@ccclass('CCComp')
export abstract class CCComp extends Component implements ecs.IComp {
    
    static tid: number = -1;
    static compName: string;

    canRecycle: boolean;
    ent: ecs.Entity;

    onLoad() {
        this.ent = ecs.createEntity();
        this.ent.add(this);    
    }

    abstract reset(): void;
}

创建ecs组件并且赋予序列化的功能,这样就能在Cocos Creator的“属性检查器”上修改参数

import { _decorator, toDegree, v3, Node, Vec3 } from "cc";
import { ecs } from "../../../Libs/ECS";
const { ccclass, property } = _decorator;

let outV3 = v3();
@ccclass('MovementComponent')
@ecs.register('Movement')
export class MovementComponent extends ecs.Comp {
    pos: Vec3 = v3();
    angle: number = 0;
    speed: number = 0;

    @property
    acceleration: number = 0;

    @property
    private _maxSpeed: number = 0;
    @property
    set maxSpeed(val: number) {
        this._maxSpeed = val;
    }
    get maxSpeed() {
        return this._maxSpeed;
    }

    @property
    heading: Vec3 = v3();
    
    @property
    targetHeading: Vec3 = v3();

    reset() {

    }

    update(dt: number) {
        if(!Vec3.equals(this.heading, this.targetHeading, 0.01)) {
            Vec3.subtract(outV3, this.targetHeading, this.heading);
            outV3.multiplyScalar(0.025);
            this.heading.add(outV3);
            this.heading.normalize();
            this.angle = toDegree(Math.atan2(this.heading.y, this.heading.x)) - 90;
        }
        
        this.speed = Math.min(this.speed + this.acceleration * dt, this._maxSpeed);

        this.pos.add3f(this.heading.x * this.speed * dt, this.heading.y * this.speed * dt, 0);
    }

    calcAngle() {
        this.angle = toDegree(Math.atan2(this.heading.y, this.heading.x)) - 90;
        return this.angle;
    }
}

创建面向Cocos Creator的组件

import { Component, _decorator } from "cc";
const { ccclass, property } = _decorator;
@ccclass('Player')
@ecs.register('Player', false)
export class Player extends CCComp {
    @property({
        type: MovementComponent
    })
    movement: MovementComponent;

    onLoad() {
        super.onLoad();

        // 添加MovementComponent组件对象
        this.ent.add(this.movement);
    }
}

调试

添加如下代码

windows['ecs'] = ecs;

在chrome浏览器的console中输入ecs可看到

其中红框内为ecs上下文数据。

相关ecs框架

https://github.com/dualface/ecs-typescript

https://github.com/nomos/lokas-ts

https://github.com/darkoverlordofdata/entitas-ts

https://github.com/NateTheGreatt/bitecs

https://github.com/ecsyjs/ecsy

https://github.com/dannyfritz/flock-ecs

https://github.com/ddmills/geotic

https://github.com/fireveined/perform-ecs

https://github.com/ayebear/picoes

https://github.com/bvalosek/tiny-ecs

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].