ECS代码优化

This commit is contained in:
dgflash
2022-09-05 16:41:24 +08:00
parent a1b24ff75e
commit 17550343c7
5 changed files with 65 additions and 63 deletions

View File

@@ -1,8 +1,7 @@
import { ECSComp } from "./ECSComp";
import { ECSEntity } from "./ECSEntity";
import { ECSGroup } from "./ECSGroup";
import { ECSMatcher } from "./ECSMatcher";
import { ECSModel } from "./ECSModel";
import { CompCtor, CompType, ECSModel, EntityCtor } from "./ECSModel";
import { ECSComblockSystem, ECSRootSystem, ECSSystem } from "./ECSSystem";
/** Entity-Component-System实体-组件-系统)框架 */
@@ -29,14 +28,7 @@ export module ecs {
/** 处理游戏逻辑系统对象 - 继承此对象实现自定义业务逻辑 */
export const ComblockSystem = ECSComblockSystem;
/** 组件类型 */
export type CompType<T> = CompCtor<T> | number;
//#region 接口
/** 实体构造器接口 */
export interface EntityCtor<T> {
new(): T;
}
/** 组件接口 */
export interface IComp {
@@ -46,15 +38,6 @@ export module ecs {
reset(): void;
}
/** 组件构造器接口 */
export interface CompCtor<T> {
new(): T;
/** 组件编号 */
tid: number;
/** 组件名 */
compName: string;
}
/** 实体匹配器接口 */
export interface IMatcher {
mid: number;
@@ -189,23 +172,6 @@ export module ecs {
return entity as T;
}
/**
* 创建group每个group只关心对应组件的添加和删除
* @param matcher 实体筛选器
*/
export function createGroup<E extends ECSEntity = ECSEntity>(matcher: ecs.IMatcher): ECSGroup<E> {
let group = ECSModel.groups.get(matcher.mid);
if (!group) {
group = new ECSGroup(matcher);
ECSModel.groups.set(matcher.mid, group);
let careComponentTypeIds = matcher.indices;
for (let i = 0; i < careComponentTypeIds.length; i++) {
ECSModel.compAddOrRemove.get(careComponentTypeIds[i])!.push(group.onComponentAddOrRemove.bind(group));
}
}
return group as unknown as ECSGroup<E>;
}
/**
* 动态查询实体
* @param matcher 匹配器
@@ -215,7 +181,7 @@ export module ecs {
export function query<E extends Entity = Entity>(matcher: IMatcher): E[] {
let group = ECSModel.groups.get(matcher.mid);
if (!group) {
group = createGroup(matcher);
group = ECSModel.createGroup(matcher);
ECSModel.eid2Entity.forEach(group.onComponentAddOrRemove, group);
}
return group.matchEntities as E[];

View File

@@ -1,6 +1,6 @@
import { ecs } from "./ECS";
import { ECSMask } from "./ECSMask";
import { ECSModel } from "./ECSModel";
import { CompCtor, CompType, ECSModel } from "./ECSModel";
//#region 辅助方法
@@ -24,13 +24,13 @@ function broadcastCompAddOrRemove(entity: ECSEntity, componentTypeId: number) {
* 创建组件对象
* @param ctor
*/
function createComp<T extends ecs.IComp>(ctor: ecs.CompCtor<T>): T {
function createComp<T extends ecs.IComp>(ctor: CompCtor<T>): T {
var cct = ECSModel.compCtors[ctor.tid];
if (!cct) {
throw Error(`没有找到该组件的构造函数,检查${ctor.compName}是否为不可构造的组件`);
}
let comps = ECSModel.compPools.get(ctor.tid)!;
let component = comps.pop() || new (cct as ecs.CompCtor<T>);
let component = comps.pop() || new (cct as CompCtor<T>);
return component as T;
}
@@ -57,6 +57,7 @@ function destroyEntity(entity: ECSEntity) {
//#endregion
/** ECS实体对象 */
export class ECSEntity {
/** 实体唯一标识,不要手动修改 */
eid: number = -1;
@@ -65,7 +66,7 @@ export class ECSEntity {
/** 组件过滤数据 */
private mask = new ECSMask();
/** 当前实体身上附加的组件构造函数 */
private compTid2Ctor: Map<number, ecs.CompType<ecs.IComp>> = new Map();
private compTid2Ctor: Map<number, CompType<ecs.IComp>> = new Map();
/** 配合 entity.remove(Comp, false) 记录组件实例上的缓存数据,在添加时恢复原数据 */
private compTid2Obj: Map<number, ecs.IComp> = new Map();
@@ -117,9 +118,9 @@ export class ECSEntity {
*/
add<T extends ecs.IComp>(obj: T): ECSEntity;
add(ctor: number, isReAdd?: boolean): ECSEntity;
add<T extends ecs.IComp>(ctor: ecs.CompCtor<T>, isReAdd?: boolean): T;
add<T extends ecs.IComp>(ctor: ecs.CompType<T>, isReAdd?: boolean): T;
add<T extends ecs.IComp>(ctor: ecs.CompType<T> | T, isReAdd: boolean = false): T | ECSEntity {
add<T extends ecs.IComp>(ctor: CompCtor<T>, isReAdd?: boolean): T;
add<T extends ecs.IComp>(ctor: CompType<T>, isReAdd?: boolean): T;
add<T extends ecs.IComp>(ctor: CompType<T> | T, isReAdd: boolean = false): T | ECSEntity {
if (typeof ctor === 'function') {
let compTid = ctor.tid;
if (ctor.tid === -1) {
@@ -158,7 +159,7 @@ export class ECSEntity {
return comp;
}
else {
let tmpCtor = (ctor.constructor as ecs.CompCtor<T>);
let tmpCtor = (ctor.constructor as CompCtor<T>);
let compTid = tmpCtor.tid;
// console.assert(compTid !== -1 || !compTid, '组件未注册!');
// console.assert(this.compTid2Ctor.has(compTid), '已存在该组件!');
@@ -188,7 +189,7 @@ export class ECSEntity {
* @param ctors 组件类
* @returns
*/
addComponents<T extends ecs.IComp>(...ctors: ecs.CompType<T>[]) {
addComponents<T extends ecs.IComp>(...ctors: CompType<T>[]) {
for (let ctor of ctors) {
this.add(ctor);
}
@@ -200,8 +201,8 @@ export class ECSEntity {
* @param ctor 组件类
*/
get(ctor: number): number;
get<T extends ecs.IComp>(ctor: ecs.CompCtor<T>): T;
get<T extends ecs.IComp>(ctor: ecs.CompCtor<T> | number): T {
get<T extends ecs.IComp>(ctor: CompCtor<T>): T;
get<T extends ecs.IComp>(ctor: CompCtor<T> | number): T {
// @ts-ignore
return this[ctor.compName];
}
@@ -210,7 +211,7 @@ export class ECSEntity {
* 组件是否在实体存在内
* @param ctor 组件类
*/
has(ctor: ecs.CompType<ecs.IComp>): boolean {
has(ctor: CompType<ecs.IComp>): boolean {
if (typeof ctor == "number") {
return this.mask.has(ctor);
}
@@ -226,7 +227,7 @@ export class ECSEntity {
* 设置该参数为false这样该组件对象会缓存在实体身上下次重新添加组件时会将该组件对象添加回来不会重新从组件缓存
* 池中拿一个组件来用。
*/
remove(ctor: ecs.CompType<ecs.IComp>, isRecycle: boolean = true) {
remove(ctor: CompType<ecs.IComp>, isRecycle: boolean = true) {
let hasComp = false;
//@ts-ignore
let componentTypeId = ctor.tid;
@@ -258,7 +259,7 @@ export class ECSEntity {
}
}
private _remove(comp: ecs.CompType<ecs.IComp>) {
private _remove(comp: CompType<ecs.IComp>) {
this.remove(comp, false);
}

View File

@@ -1,7 +1,7 @@
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSMask } from "./ECSMask";
import { ECSModel } from "./ECSModel";
import { CompCtor, CompType, ECSModel } from "./ECSModel";
let macherId: number = 1;
@@ -51,7 +51,7 @@ export class ECSMatcher implements ecs.IMatcher {
* 组件间是或的关系,表示关注拥有任意一个这些组件的实体。
* @param args 组件索引
*/
anyOf(...args: ecs.CompType<ecs.IComp>[]): ECSMatcher {
anyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
this.rules.push(new AnyOf(...args));
this.bindMatchMethod();
return this;
@@ -61,7 +61,7 @@ export class ECSMatcher implements ecs.IMatcher {
* 组件间是与的关系,表示关注拥有所有这些组件的实体。
* @param args 组件索引
*/
allOf(...args: ecs.CompType<ecs.IComp>[]): ECSMatcher {
allOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
this.rules.push(new AllOf(...args));
this.bindMatchMethod();
return this;
@@ -74,9 +74,9 @@ export class ECSMatcher implements ecs.IMatcher {
* 不是特殊情况不建议使用onlyOf。因为onlyOf会监听所有组件的添加和删除事件。
* @param args 组件索引
*/
onlyOf(...args: ecs.CompType<ecs.IComp>[]): ECSMatcher {
onlyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
this.rules.push(new AllOf(...args));
let otherTids: ecs.CompType<ecs.IComp>[] = [];
let otherTids: CompType<ecs.IComp>[] = [];
for (let ctor of ECSModel.compCtors) {
if (args.indexOf(ctor) < 0) {
otherTids.push(ctor);
@@ -91,7 +91,7 @@ export class ECSMatcher implements ecs.IMatcher {
* 不包含指定的任意一个组件
* @param args
*/
excludeOf(...args: ecs.CompType<ecs.IComp>[]) {
excludeOf(...args: CompType<ecs.IComp>[]) {
this.rules.push(new ExcludeOf(...args));
this.bindMatchMethod();
return this;
@@ -139,7 +139,7 @@ abstract class BaseOf {
protected mask = new ECSMask();
constructor(...args: ecs.CompType<ecs.IComp>[]) {
constructor(...args: CompType<ecs.IComp>[]) {
let componentTypeId = -1;
let len = args.length;
for (let i = 0; i < len; i++) {
@@ -147,7 +147,7 @@ abstract class BaseOf {
componentTypeId = args[i] as number;
}
else {
componentTypeId = (args[i] as ecs.CompCtor<ecs.IComp>).tid;
componentTypeId = (args[i] as CompCtor<ecs.IComp>).tid;
}
if (componentTypeId == -1) {
throw Error('存在没有注册的组件!');

View File

@@ -2,7 +2,7 @@
* @Author: dgflash
* @Date: 2022-05-12 14:18:44
* @LastEditors: dgflash
* @LastEditTime: 2022-09-05 14:16:15
* @LastEditTime: 2022-09-05 16:37:10
*/
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
@@ -10,12 +10,29 @@ import { ECSGroup } from "./ECSGroup";
type CompAddOrRemove = (entity: ecs.Entity) => void;
/** 组件类型 */
export type CompType<T> = CompCtor<T> | number;
/** 实体构造器接口 */
export interface EntityCtor<T> {
new(): T;
}
/** 组件构造器接口 */
export interface CompCtor<T> {
new(): T;
/** 组件编号 */
tid: number;
/** 组件名 */
compName: string;
}
/** ECS框架内部数据 */
export class ECSModel {
/** 实体自增id */
static eid = 1;
/** 实体造函数 */
static entityCtors: Map<ecs.EntityCtor<any>, string> = new Map();
static entityCtors: Map<EntityCtor<any>, string> = new Map();
/** 实体对象缓存池 */
static entityPool: Map<string, ECSEntity[]> = new Map();
/** 通过实体id查找实体对象 */
@@ -26,7 +43,7 @@ export class ECSModel {
/** 组件缓存池 */
static compPools: Map<number, ecs.IComp[]> = new Map();
/** 组件构造函数 */
static compCtors: (ecs.CompCtor<any> | number)[] = [];
static compCtors: (CompCtor<any> | number)[] = [];
/**
* 每个组件的添加和删除的动作都要派送到“关心”它们的group上。goup对当前拥有或者之前删除前拥有该组件的实体进行组件规则判断。判断该实体是否满足group
* 所期望的组件组合。
@@ -42,4 +59,21 @@ export class ECSModel {
* key是组件的筛选规则一个筛选规则对应一个group
*/
static groups: Map<number, ECSGroup> = new Map();
/**
* 创建group每个group只关心对应组件的添加和删除
* @param matcher 实体筛选器
*/
static createGroup<E extends ECSEntity = ECSEntity>(matcher: ecs.IMatcher): ECSGroup<E> {
let group = ECSModel.groups.get(matcher.mid);
if (!group) {
group = new ECSGroup(matcher);
ECSModel.groups.set(matcher.mid, group);
let careComponentTypeIds = matcher.indices;
for (let i = 0; i < careComponentTypeIds.length; i++) {
ECSModel.compAddOrRemove.get(careComponentTypeIds[i])!.push(group.onComponentAddOrRemove.bind(group));
}
}
return group as unknown as ECSGroup<E>;
}
}

View File

@@ -1,6 +1,7 @@
import { ecs } from "./ECS";
import { ECSEntity } from "./ECSEntity";
import { ECSGroup } from "./ECSGroup";
import { ECSModel } from "./ECSModel";
/** 继承此类实现具体业务逻辑的系统 */
export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
@@ -35,12 +36,12 @@ export abstract class ECSComblockSystem<E extends ECSEntity = ECSEntity> {
this.removedEntities = new Map<number, E>();
this.execute = this.execute1;
this.group = ecs.createGroup(this.filter());
this.group = ECSModel.createGroup(this.filter());
this.group.watchEntityEnterAndRemove(this.enteredEntities, this.removedEntities);
}
else {
this.execute = this.execute0;
this.group = ecs.createGroup(this.filter());
this.group = ECSModel.createGroup(this.filter());
}
if (hasFirstUpdate) {