export module ecs { export interface IComp { canRecycle : boolean ; ent : Entity ; reset ( ) : void ; } export interface CompCtor < T > { new ( ) : T ; tid : number ; compName : string ; } /**
     * 组件里面只放数据可能在实际写代码的时候比较麻烦。如果是单纯对组件内的数据操作可以在组件里面写方法。
     */ export abstract class Comp implements IComp { /**
         * 组件的类型id，-1表示未给该组件分配id
         */ static tid : number = - 1 ; static compName : string ; /**
         * 拥有该组件的实体
         */ ent ! : Entity ; /**
         * 是否可回收组件对象，默认情况下都是可回收的。
         * 如果该组件对象是由ecs系统外部创建的，则不可回收，需要用户自己手动进行回收。
         */ canRecycle : boolean = true ; /**
         * 组件被回收时会调用这个接口。可以在这里重置数据，或者解除引用。
         *
         * **不要偷懒，除非你能确定并保证组件在复用时，里面的数据是先赋值然后再使用。**
         */ abstract reset ( ) ; } type CompAddOrRemove = ( entity : Entity ) => void ; export type CompType < T > = CompCtor < T > | number ; /**
     * 组件缓存池
     */ let compPools = new Map ( ) ; /**
     * 组件类型id
     */ let compTid = 0 ; /**
     * 组件构造函数
     */ let compCtors = [ ] ; /**
     * 每个组件的添加和删除的动作都要派送到“关心”它们的group上。goup对当前拥有或者之前（删除前）拥有该组件的实体进行组件规则判断。判断该实体是否满足group
     * 所期望的组件组合。
     */ let compAddOrRemove = new Map ( ) ; let tags = new Map ( ) ; param compName param canNew export function register < T > ( compName , canNew = true ) { return function ( ctor ) { if ( ctor . tid === - 1 ) { ctor . tid = compTid ++ ; ctor . compName = compName ; if ( canNew ) { compCtors . push ( ctor ) ; compPools . set ( ctor . tid , [ ] ) ; } else { compCtors . push ( null ) ; } compAddOrRemove . set ( ctor . tid , [ ] ) ; } else { throw new Error ( `重复注册组件： ${ compName }.` ) ; } } ; } registerTag returns export function registerTag ( ) { return function ( _class ) { let tid = compTid ; for ( let k in _class ) { tid = compTid ++ ; _class [ k ] = tid ; compCtors . push ( tid ) ; compPools . set ( tid , [ ] ) ; compAddOrRemove . set ( tid , [ ] ) ; tags . set ( tid , k ) ; } } ; } /**
     * 实体对象缓存池
     */ let entityPool = [ ] ; /**
     * 通过实体id查找实体对象
     */ let eid2Entity = new Map ( ) ; /**
     * 缓存的group
     *
     * key是组件的筛选规则，一个筛选规则对应一个group
     */ let groups = new Map ( ) ; /**
     * 实体自增id
     */ let eid = 1 ; /**
     * 创建实体
     */ export function createEntity < E extends Entity = Entity > ( ) { let entity = entityPool . pop ( ) ; if ( ! entity ) { entity = new Entity ( ) ; entity . eid = eid ++ ; } eid2Entity . set ( entity . eid , entity ) ; return entity as E ; } param ctor function createComp < T extends IComp > ( ctor ) { if ( ! compCtors [ ctor . tid ] ) { throw Error ( `没有找到该组件的构造函数，检查${ ctor . compName }是否为不可构造的组件` ) ; } let component = compPools . get ( ctor . tid ) ! . pop ( ) || new ( compCtors [ ctor . tid ] as CompCtor < T > ) ; return component as T ; } param ctor export function createEntityWithComp < T extends IComp > ( obj ) ; export function createEntityWithComp ( ctor ) ; export function createEntityWithComp < T extends IComp > ( ctor ) ; export function createEntityWithComp < T extends IComp > ( ctor ) { let entity = createEntity ( ) ; return entity . add ( ctor ) ; } param ctors export function createEntityWithComps < E extends Entity = Entity > ( ... ctors ) { let entity = createEntity ( ) ; entity . addComponents ( ... ctors ) ; return entity as E ; } param entity function destroyEntity ( entity ) { if ( eid2Entity . has ( entity . eid ) ) { entityPool . push ( entity ) ; eid2Entity . delete ( entity . eid ) ; } else { console . warn ( '试图销毁不存在的实体！' ) ; } } param matcher export function createGroup < E extends Entity = Entity > ( matcher ) { let group = groups . get ( matcher . mid ) ; if ( ! group ) { group = new Group ( matcher ) ; groups . set ( matcher . mid , group ) ; let careComponentTypeIds = matcher . indices ; for ( let i = 0 ; i < careComponentTypeIds . length ; i ++ ) { compAddOrRemove . get ( careComponentTypeIds [ i ] ) ! . push ( group . onComponentAddOrRemove . bind ( group ) ) ; } } return group as unknown as Group < E > ; } param matcher returns export function query < E extends Entity = Entity > ( matcher ) { let group = groups . get ( matcher . mid ) ; if ( ! group ) { group = createGroup ( matcher ) ; eid2Entity . forEach ( group . onComponentAddOrRemove , group ) ; } return group . matchEntities as E [ ] ; } /**
     * 清理所有的实体
     */ export function clear ( ) { eid2Entity . forEach ( ( entity ) => { entity . destroy ( ) ; } ) ; groups . forEach ( ( group ) => { group . clear ( ) ; } ) ; compAddOrRemove . forEach ( callbackLst => { callbackLst . length = 0 ; } ) ; eid2Entity . clear ( ) ; groups . clear ( ) ; } param entity param componentTypeId function broadcastCompAddOrRemove ( entity , componentTypeId ) { let events = compAddOrRemove . get ( componentTypeId ) ; for ( let i = events ! . length - 1 ; i >= 0 ; i -- ) { events ! [ i ] ( entity ) ; } if ( tid2comp . has ( componentTypeId ) ) { tid2comp . delete ( componentTypeId ) ; } } param eid export function getEntityByEid < E extends Entity = Entity > ( eid ) { return eid2Entity . get ( eid ) as E ; } /**
     * 当前活动中的实体数量
     */ export function activeEntityCount ( ) { return eid2Entity . size ; } param args export function allOf ( ... args ) { return new Matcher ( ) . allOf ( ... args ) ; } param args export function anyOf ( ... args ) { return new Matcher ( ) . anyOf ( ... args ) ; } param args export function onlyOf ( ... args ) { return new Matcher ( ) . onlyOf ( ... args ) ; } param args export function excludeOf ( ... args ) { return new Matcher ( ) . excludeOf ( ... args ) ; } let tid2comp = new Map ( ) ; param ctor export function getSingleton < T extends IComp > ( ctor ) { if ( ! tid2comp . has ( ctor . tid ) ) { let comp = createEntityWithComp ( ctor ) as T ; tid2comp . set ( ctor . tid , comp ) ; } return tid2comp . get ( ctor . tid ) as T ; } param obj export function addSingleton ( obj ) { let tid = ( obj . constructor as CompCtor < IComp > ) . tid ; if ( ! tid2comp . has ( tid ) ) { tid2comp . set ( tid , obj ) ; } } class Mask { private mask : Uint32Array ; private size : number = 0 ; constructor ( ) { let length = Math . ceil ( compTid / 31 ) ; this . mask = new Uint32Array ( length ) ; this . size = length ; } set ( num ) { this . mask [ ( ( num / 31 ) >>> 0 ) ] |= ( 1 << ( num % 31 ) ) ; } delete ( num ) { this . mask [ ( ( num / 31 ) >>> 0 ) ] &= ~ ( 1 << ( num % 31 ) ) ; } has ( num ) { return ! ! ( this . mask [ ( ( num / 31 ) >>> 0 ) ] & ( 1 << ( num % 31 ) ) ) ; } or ( other ) { for ( let i = 0 ; i < this . size ; i ++ ) { if ( this . mask [ i ] & other . mask [ i ] ) { return true ; } } return false ; } and ( other ) { for ( let i = 0 ; i < this . size ; i ++ ) { if ( ( this . mask [ i ] & other . mask [ i ] ) != this . mask [ i ] ) { return false ; } } return true ; } clear ( ) { for ( let i = 0 ; i < this . size ; i ++ ) { this . mask [ i ] = 0 ; } } } export class Entity { /**
         * 实体唯一标识，不要手动修改。
         */ public eid : number = - 1 ; private mask = new Mask ( ) ; /**
         * 当前实体身上附加的组件构造函数
         */ private compTid2Ctor : Map < number , CompType < IComp > > = new Map ( ) ; private compTid2Obj : Map < number , IComp > = new Map ( ) ; constructor ( ) { } param componentTypeId param isReAdd add < T extends IComp > ( obj ) ; add ( ctor , isReAdd ? ) ; add < T extends IComp > ( ctor , isReAdd ? ) ; add < T extends IComp > ( ctor , isReAdd = false ) { if ( typeof ctor === 'function' ) { let compTid = ctor . tid ; if ( ctor . tid === - 1 ) { throw Error ( '组件未注册！' ) ; } if ( this . compTid2Ctor . has ( compTid ) ) { if ( isReAdd ) { this . remove ( ctor ) ; } else { console . log ( `已经存在组件：${ ctor . compName }` ) ; return this [ ctor . compName ] as T ; } } this . mask . set ( compTid ) ; let comp ; if ( this . compTid2Obj . has ( compTid ) ) { comp = this . compTid2Obj . get ( compTid ) as T ; this . compTid2Obj . delete ( compTid ) ; } else { comp = createComp ( ctor ) as T ; } this [ ctor . compName ] = comp ; this . compTid2Ctor . set ( compTid , ctor ) ; comp . ent = this ; broadcastCompAddOrRemove ( this , compTid ) ; return comp ; } else if ( typeof ctor === 'number' ) { if ( tags . has ( ctor ) ) { this . mask . set ( ctor ) ; this . compTid2Ctor . set ( ctor , ctor ) ; let tagName = tags . get ( ctor ) ! ; this [ tagName ] = ctor ; broadcastCompAddOrRemove ( this , ctor ) ; } else { throw Error ( '不存在的tag！' ) ; } return this ; } else { let tmpCtor = ( ctor . constructor as CompCtor < T > ) ; let compTid = tmpCtor . tid ; if ( compTid === - 1 || compTid == null ) { throw Error ( '组件未注册！' ) ; } if ( this . compTid2Ctor . has ( compTid ) ) { throw Error ( '已经存在该组件！' ) ; } this . mask . set ( compTid ) ; this [ tmpCtor . compName ] = ctor ; this . compTid2Ctor . set ( compTid , tmpCtor ) ; ctor . ent = this ; ctor . canRecycle = false ; broadcastCompAddOrRemove ( this , compTid ) ; return this ; } } addComponents < T extends IComp > ( ... ctors ) { for ( let ctor of ctors ) { this . add ( ctor ) ; } return this ; } get ( ctor ) ; get < T extends IComp > ( ctor ) ; get < T extends IComp > ( ctor ) { let compName ; if ( typeof ( ctor ) === 'number' ) { compName = tags . get ( ctor ) ! ; } else { compName = ctor . compName ; } return this [ compName ] ; } has ( ctor ) { if ( typeof ctor == "number" ) { return this . mask . has ( ctor ) ; } else { return this . compTid2Ctor . has ( ctor . tid ) ; } } param ctor param isRecycle remove ( ctor , isRecycle = true ) { let componentTypeId = - 1 ; let compName = '' ; let hasComp = false ; if ( typeof ctor === "number" ) { componentTypeId = ctor ; if ( this . mask . has ( ctor ) ) { hasComp = true ; compName = tags . get ( ctor ) ! ; } } else { componentTypeId = ctor . tid ; compName = ctor . compName ; if ( this . mask . has ( componentTypeId ) ) { hasComp = true ; let comp = this [ ctor . compName ] as IComp ; comp . ent = null ; if ( isRecycle ) { comp . reset ( ) ; if ( comp . canRecycle ) { compPools . get ( componentTypeId ) . push ( comp ) ; } } else { this . compTid2Obj . set ( componentTypeId , comp ) ; } } } if ( hasComp ) { this [ compName ] = null ; this . mask . delete ( componentTypeId ) ; this . compTid2Ctor . delete ( componentTypeId ) ; broadcastCompAddOrRemove ( this , componentTypeId ) ; } } private _remove ( comp ) { this . remove ( comp , false ) ; } /**
         * 销毁实体，实体会被回收到实体缓存池中。
         */ destroy ( ) { this . compTid2Ctor . forEach ( this . _remove , this ) ; destroyEntity ( this ) ; this . compTid2Obj . clear ( ) ; } } export class Group < E extends Entity = Entity > { /**
         * 实体筛选规则
         */ private matcher : IMatcher ; private _matchEntities : Map < number , E > = new Map ( ) ; private _entitiesCache : E [ ] | null = null ; /**
         * 符合规则的实体
         */ public get matchEntities ( ) { if ( this . _entitiesCache === null ) { this . _entitiesCache = Array . from ( this . _matchEntities . values ( ) ) ; } return this . _entitiesCache ; } /**
         * 当前group中实体的数量。
         *
         * 不要手动修改这个属性值。
         */ public count = 0 ; /**
         * 获取matchEntities中第一个实体
         */ get entity ( ) : E { return this . matchEntities [ 0 ] ; } private _enteredEntities : Map < number , E > | null = null ; private _removedEntities : Map < number , E > | null = null ; constructor ( matcher ) { this . matcher = matcher ; } public onComponentAddOrRemove ( entity ) { if ( this . matcher . isMatch ( entity ) ) { this . _matchEntities . set ( entity . eid , entity ) ; this . _entitiesCache = null ; this . count ++ ; if ( this . _enteredEntities ) { this . _enteredEntities . set ( entity . eid , entity ) ; this . _removedEntities ! . delete ( entity . eid ) ; } } else if ( this . _matchEntities . has ( entity . eid ) ) { this . _matchEntities . delete ( entity . eid ) ; this . _entitiesCache = null ; this . count -- ; if ( this . _enteredEntities ) { this . _enteredEntities . delete ( entity . eid ) ; this . _removedEntities ! . set ( entity . eid , entity ) ; } } } public watchEntityEnterAndRemove ( enteredEntities , removedEntities ) { this . _enteredEntities = enteredEntities ; this . _removedEntities = removedEntities ; } clear ( ) { this . _matchEntities . clear ( ) ; this . _entitiesCache = null ; this . count = 0 ; this . _enteredEntities ?. clear ( ) ; this . _removedEntities ?. clear ( ) ; } } abstract class BaseOf { protected mask = new Mask ( ) ; public indices : number [ ] = [ ] ; constructor ( ... args ) { let componentTypeId = - 1 ; let len = args . length ; for ( let i = 0 ; i < len ; i ++ ) { if ( typeof ( args [ i ] ) === "number" ) { componentTypeId = args [ i ] as number ; } else { componentTypeId = ( args [ i ] as CompCtor < IComp > ) . tid ; } if ( componentTypeId == - 1 ) { throw Error ( '存在没有注册的组件！' ) ; } this . mask . set ( componentTypeId ) ; if ( this . indices . indexOf ( componentTypeId ) < 0 ) { this . indices . push ( componentTypeId ) ; } } if ( len > 1 ) { this . indices . sort ( ( a , b ) => { return a - b ; } ) ; } } public toString ( ) { return this . indices . join ( '-' ) ; } public abstract getKey ( ) ; public abstract isMatch ( entity ) ; } /**
     * 用于描述包含任意一个这些组件的实体
     */ class AnyOf extends BaseOf { public isMatch ( entity ) { return this . mask . or ( entity . mask ) ; } getKey ( ) { return 'anyOf:' + this . toString ( ) ; } } /**
     * 用于描述包含了“这些”组件的实体，这个实体除了包含这些组件还可以包含其他组件
     */ class AllOf extends BaseOf { public isMatch ( entity ) { return this . mask . and ( entity . mask ) ; } getKey ( ) { return 'allOf:' + this . toString ( ) ; } } /**
     * 不包含指定的任意一个组件
     */ class ExcludeOf extends BaseOf { public getKey ( ) { return 'excludeOf:' + this . toString ( ) ; } public isMatch ( entity ) { return ! this . mask . or ( entity . mask ) ; } } export interface IMatcher { mid : number ; indices : number [ ] ; key : string ; isMatch ( entity ) : boolean ; } let macherId = 1 ; /**
     * 筛选规则间是“与”的关系
     * 比如：ecs.Macher.allOf(...).excludeOf(...)表达的是allOf && excludeOf，即实体有“这些组件” 并且 “没有这些组件”
     */ class Matcher implements IMatcher { protected rules : BaseOf [ ] = [ ] ; protected _indices : number [ ] | null = null ; public isMatch ! : ( entity : Entity ) => boolean ; public mid : number = - 1 ; private _key : string | null = null ; public get key ( ) : string { if ( ! this . _key ) { let s = '' ; for ( let i = 0 ; i < this . rules . length ; i ++ ) { s += this . rules [ i ] . getKey ( ) ; if ( i < this . rules . length - 1 ) { s += ' && ' ; } } this . _key = s ; } return this . _key ; } constructor ( ) { this . mid = macherId ++ ; } /**
         * 匹配器关注的组件索引。在创建Group时，Context根据组件id去给Group关联组件的添加和移除事件。
         */ public get indices ( ) { if ( this . _indices === null ) { this . _indices = [ ] ; this . rules . forEach ( ( rule ) => { Array . prototype . push . apply ( this . _indices , rule . indices ) ; } ) ; } return this . _indices ; } param args public anyOf ( ... args ) { this . rules . push ( new AnyOf ( ... args ) ) ; this . bindMatchMethod ( ) ; return this ; } param args public allOf ( ... args ) { this . rules . push ( new AllOf ( ... args ) ) ; this . bindMatchMethod ( ) ; return this ; } param args public onlyOf ( ... args ) { this . rules . push ( new AllOf ( ... args ) ) ; let otherTids = [ ] ; for ( let ctor of compCtors ) { if ( args . indexOf ( ctor ) < 0 ) { otherTids . push ( ctor ) ; } } this . rules . push ( new ExcludeOf ( ... otherTids ) ) ; this . bindMatchMethod ( ) ; return this ; } param args public excludeOf ( ... args ) { this . rules . push ( new ExcludeOf ( ... args ) ) ; this . bindMatchMethod ( ) ; return this ; } private bindMatchMethod ( ) { if ( this . rules . length === 1 ) { this . isMatch = this . isMatch1 ; } else if ( this . rules . length === 2 ) { this . isMatch = this . isMatch2 ; } else { this . isMatch = this . isMatchMore ; } } private isMatch1 ( entity ) { return this . rules [ 0 ] . isMatch ( entity ) ; } private isMatch2 ( entity ) { return this . rules [ 0 ] . isMatch ( entity ) && this . rules [ 1 ] . isMatch ( entity ) ; } private isMatchMore ( entity ) { for ( let rule of this . rules ) { if ( ! rule . isMatch ( entity ) ) { return false ; } } return true ; } public clone ( ) { let newMatcher = new Matcher ( ) ; newMatcher . mid = macherId ++ ; this . rules . forEach ( rule => newMatcher . rules . push ( rule ) ) ; return newMatcher ; } } /**
     * 如果需要监听实体首次进入System的情况，实现这个接口。
     *
     * entityEnter会在update方法之前执行，实体进入后，不会再次进入entityEnter方法中。
     * 当实体从当前System移除，下次再次符合条件进入System也会执行上述流程。
     */ export interface IEntityEnterSystem < E extends Entity = Entity > { entityEnter ( entities ) : void ; } /**
     * 如果需要监听实体从当前System移除，需要实现这个接口。
     */ export interface IEntityRemoveSystem < E extends Entity = Entity > { entityRemove ( entities ) : void ; } /**
     * 第一次执行update
     */ export interface ISystemFirstUpdate < E extends Entity = Entity > { firstUpdate ( entities ) : void ; } export abstract class ComblockSystem < E extends Entity = Entity > { protected group : Group < E > ; protected dt : number = 0 ; private enteredEntities : Map < number , E > | null = null ; private removedEntities : Map < number , E > | null = null ; private hasEntityEnter : boolean = false ; private hasEntityRemove : boolean = false ; private tmpExecute : ( ( dt : number ) => void ) | null = null ; private execute ! : ( dt : number ) => void ; constructor ( ) { let hasOwnProperty = Object . hasOwnProperty ; let prototype = Object . getPrototypeOf ( this ) ; let hasEntityEnter = hasOwnProperty . call ( prototype , 'entityEnter' ) ; let hasEntityRemove = hasOwnProperty . call ( prototype , 'entityRemove' ) ; let hasFirstUpdate = hasOwnProperty . call ( prototype , 'firstUpdate' ) ; this . hasEntityEnter = hasEntityEnter ; this . hasEntityRemove = hasEntityRemove ; if ( hasEntityEnter || hasEntityRemove ) { this . enteredEntities = new Map < number , E > ( ) ; this . removedEntities = new Map < number , E > ( ) ; this . execute = this . execute1 ; this . group = createGroup ( this . filter ( ) ) ; this . group . watchEntityEnterAndRemove ( this . enteredEntities , this . removedEntities ) ; } else { this . execute = this . execute0 ; this . group = createGroup ( this . filter ( ) ) ; } if ( hasFirstUpdate ) { this . tmpExecute = this . execute ; this . execute = this . updateOnce ; } } init ( ) { } onDestroy ( ) { } hasEntity ( ) { return this . group . count > 0 ; } private updateOnce ( dt ) { if ( this . group . count === 0 ) { return ; } this . dt = dt ; if ( this . enteredEntities ! . size > 0 ) { ( this as unknown as IEntityEnterSystem ) . entityEnter ( Array . from ( this . enteredEntities ! . values ( ) ) as E [ ] ) ; this . enteredEntities ! . clear ( ) ; } ( this as unknown as ISystemFirstUpdate ) . firstUpdate ( this . group . matchEntities ) ; this . execute = this . tmpExecute ! ; this . execute ( dt ) ; this . tmpExecute = null ; } param dt returns private execute0 ( dt ) { if ( this . group . count === 0 ) { return ; } this . dt = dt ; this . update ( this . group . matchEntities ) ; } param dt returns private execute1 ( dt ) { if ( this . removedEntities ! . size > 0 ) { if ( this . hasEntityRemove ) { ( this as unknown as IEntityRemoveSystem ) . entityRemove ( Array . from ( this . removedEntities ! . values ( ) ) as E [ ] ) ; } this . removedEntities ! . clear ( ) ; } if ( this . group . count === 0 ) { return ; } this . dt = dt ; if ( this . enteredEntities ! . size > 0 ) { if ( this . hasEntityEnter ) { ( this as unknown as IEntityEnterSystem ) . entityEnter ( Array . from ( this . enteredEntities ! . values ( ) ) as E [ ] ) ; } this . enteredEntities ! . clear ( ) ; } this . update ( this . group . matchEntities as E [ ] ) ; } /**
         * 实体过滤规则
         *
         * 根据提供的组件过滤实体。
         */ abstract filter ( ) ; abstract update ( entities ) ; } /**
     * System的root，对游戏中的System遍历从这里开始。
     *
     * 一个System组合中只能有一个RootSystem，可以有多个并行的RootSystem。
     */ export class RootSystem { private executeSystemFlows : ComblockSystem [ ] = [ ] ; private systemCnt : number = 0 ; add ( system ) { if ( system instanceof System ) { Array . prototype . push . apply ( this . executeSystemFlows , system . comblockSystems ) ; } else { this . executeSystemFlows . push ( system as ComblockSystem ) ; } this . systemCnt = this . executeSystemFlows . length ; return this ; } init ( ) { this . executeSystemFlows . forEach ( sys => sys . init ( ) ) ; } execute ( dt ) { for ( let i = 0 ; i < this . systemCnt ; i ++ ) { this . executeSystemFlows [ i ] . execute ( dt ) ; } } clear ( ) { this . executeSystemFlows . forEach ( sys => sys . onDestroy ( ) ) ; } } /**
     * 系统组合器，用于将多个相同功能模块的系统逻辑上放在一起。System也可以嵌套System。
     */ export class System { private _comblockSystems : ComblockSystem [ ] = [ ] ; get comblockSystems ( ) { return this . _comblockSystems ; } add ( system ) { if ( system instanceof System ) { Array . prototype . push . apply ( this . _comblockSystems , system . _comblockSystems ) ; system . _comblockSystems . length = 0 ; } else { this . _comblockSystems . push ( system as ComblockSystem ) ; } return this ; } } }