first commit

This commit is contained in:
宫欣海
2025-02-20 11:27:28 +08:00
commit 68090ca38d
91 changed files with 9915 additions and 0 deletions

112
src/ecmodule/Component.ts Normal file
View File

@@ -0,0 +1,112 @@
import { ComponentManager } from "./ComponentManager";
import { Entity } from "./Entity";
import { ObjectBase } from "./ObjectBase";
export abstract class Component extends ObjectBase {
/** 组件名 */
public name: string;
/** 组件类型 */
public type: number;
/** 是否需要更新 */
public needUpdate: boolean;
/** 所属实体 */
public entity: Entity;
/** 所属组件管理器 */
public componentManager: ComponentManager;
/** 是否需要销毁 */
public _needDestroy: boolean;
/** 更新ID */
public _updateId: number = -1;
/** 是否更新中 */
public get _updating(): boolean {
return this._updateId != -1;
}
/** 生命周期函数 添加到实体 */
public _add(): void {
this.onAdd();
}
/** 生命周期函数 销毁 */
public _destroy(): void {
this.onDestroy();
}
/** 生命周期函数 添加到实体后 在这个函数中可以获取其他组件 */
public _enter(): void {
// 自动开启更新
if (this.needUpdate) {
this.componentManager.startUpdateComponent(this);
}
this.onEnter();
}
/** 生命周期函数 从实体中移除 */
public _remove(): void {
this.stopUpdate();
this.onRemove();
this.componentManager._destroyComponent(this);
}
/** 更新 */
public _update(dt: number): void {
this.onUpdate(dt);
}
/** 开启更新 */
public startUpdate(): void {
if (!this.needUpdate) {
this.needUpdate = true;
this.componentManager?.startUpdateComponent(this);
}
}
/** 停止更新 */
public stopUpdate(): void {
if (this.needUpdate) {
this.needUpdate = false;
this.componentManager?.stopUpdateComponent(this);
}
}
/**
* 获取组件
* @param {number} componentType 组件类型
* @returns {T}
*/
public getComponent<T extends Component>(componentType: number): T {
return this.entity.getComponent<T>(componentType);
}
/**
* 删除自己
*/
public destroySelf(): void {
this.entity.removeComponent(this.type);
}
/**
* 被添加到实体 对应onDestroy
*/
protected onAdd(): void { }
/**
* 组件被销毁 对应onAdd
*/
protected onDestroy(): void { }
protected onUpdate(dt: number): void { }
/** 可在此方法获取实体其他组件 */
protected abstract onEnter(): void;
/** 从实体中删除 */
protected abstract onRemove(): void;
}

View File

@@ -0,0 +1,254 @@
import { Component } from "./Component";
import { ComponentPool } from "./ComponentPool";
/**
* 组件更新信息
*
* @export
* @class ComponentUpdate
*/
export class ComponentUpdate {
/** 组件更新类型 */
public componentType: number;
/** 组件更新列表 */
private readonly _components: Component[] = [];
/** create constructor */
public constructor(componentType: number) {
this.componentType = componentType;
}
/**
* 添加要更新的组件
* @param component 组件
*/
public addComponent(component: Component): void {
this._components.push(component);
component._updateId = this._components.length - 1;
}
/**
* 删除要更新的组件
* @param {Component} component 组件
*/
public removeComponent(component: Component): void {
const components = this._components;
const finalUpdateID = components.length - 1;
const updateID = component._updateId;
component._updateId = -1;
/** 最后一个和当前要删除的不是同一个,交换位置 */
if (finalUpdateID != updateID) {
const finalComponent = components[finalUpdateID];
// #EC_DEBUG_BEGIN
if (finalComponent._updateId != finalUpdateID) {
throw new Error(`组件(${finalComponent.toString()})更新ID(${finalUpdateID})与存储更新ID(${finalComponent._updateId})不一致`);
}
// #EC_DEBUG_END
finalComponent._updateId = updateID;
components[updateID] = finalComponent;
}
components.pop();
}
/** 更新 */
public _update(dt: number): void {
const components = this._components;
const componentCount = components.length;
if (componentCount > 0) {
for (let i = 0; i < componentCount; ++i) {
const component = components[i];
if (component.needUpdate && component._updating) {
component._update(dt);
}
}
}
}
}
export class ComponentManager {
/**
* 组件池
* @type {ComponentPool}
*/
protected componentPool: ComponentPool;
/** 更新组件池 */
protected readonly updatingComponents: ComponentUpdate[] = [];
protected readonly componentUpdateOrderList: number[] = [];
/** 新添加的或者新停止更新的组件池 */
private readonly _toUpdateComponents: Component[] = [];
private readonly _toStopComponents: Component[] = [];
/** 当前更新的组件类型 */
private _currentUpdateComponentType: number = -1;
/**
*Creates an instance of ComponentManager.
* @param {ComponentPool} componentPool 组件池
* @param {number[]} componentUpdateOrderList 组件更新顺序
*/
constructor(componentPool: ComponentPool, componentUpdateOrderList: number[]) {
this.componentPool = componentPool;
this._toUpdateComponents.length = 0;
this._toStopComponents.length = 0;
for (const componentType of componentUpdateOrderList) {
this._addComponentUpdateOrder(componentType);
}
}
public destroy(): void {
this.componentPool.clear();
this.updatingComponents.length = 0;
this.componentUpdateOrderList.length = 0;
this._toUpdateComponents.length = 0;
this._toStopComponents.length = 0;
}
/**
* 创建组件
* @template T
* @param {string} componentName 组件名
* @returns {T} 创建的组件
*/
public createComponent<T extends Component>(componentName: string): T {
const component = this.componentPool.get(componentName) as T;
// component._enable = true;
// component.needDestroy = false;
component.componentManager = this;
return component;
}
/**
* 开始更新组件
* @param {Component} component 组件
*/
public startUpdateComponent(component: Component): void {
if (component._updating) {
return;
}
if (this._currentUpdateComponentType != component.type) {
this._addComponentToUpdateList(component);
return;
}
this._toUpdateComponents.push(component);
}
/**
* 停止更新组件
* @param {Component} component 组件
*/
public stopUpdateComponent(component: Component): void {
if (!component._updating) {
return;
}
if (this._currentUpdateComponentType != component.type) {
this._removeComponentToUpdateList(component);
return;
}
this._toStopComponents.push(component);
}
/**
* 销毁组件(内部使用)
* @param {Component} component
*/
public _destroyComponent(component: Component): void {
if (!component._updating) {
component._destroy();
this.componentPool.recycle(component);
} else {
component._needDestroy = true;
}
}
/** 更新所有组件(内部使用) */
public _update(dt: number): void {
this._updateAllComponents(dt);
this._currentUpdateComponentType = -1;
this._clearStopComponents();
this._addUpdateComponents();
}
/**
* 添加组件更新顺序,先添加的先更新
* @param {number} componentType 组件类型
*/
private _addComponentUpdateOrder(componentType: number): ComponentManager {
this.componentUpdateOrderList.push(componentType);
const updatingComponents = this.updatingComponents;
for (let i = updatingComponents.length; i <= componentType; ++i) {
updatingComponents.push(null);
}
if (updatingComponents[componentType]) {
throw new Error(`组件类型(${componentType}:${this.componentPool.className(componentType)})已经添加到更新列表`);
}
updatingComponents[componentType] = new ComponentUpdate(componentType);
return this;
}
/** 添加组件到组件更新列表 */
private _addComponentToUpdateList(component: Component): void {
if (component.type >= this.updatingComponents.length || !this.updatingComponents[component.type]) {
throw new Error(`组件(${component.constructor.name}没有添加到组件更新列表请使用addComponentUpdateOrder添加更新`);
}
this.updatingComponents[component.type].addComponent(component);
}
/** 组件更新列表中删除组件 */
private _removeComponentToUpdateList(component: Component): void {
this.updatingComponents[component.type].removeComponent(component);
}
/** 更新所有组件 */
private _updateAllComponents(dt: number): void {
// 按优先级更新所有组件
const updateList = this.componentUpdateOrderList;
const updatingComponents = this.updatingComponents;
let componentType: number;
for (let i = 0, l = updateList.length; i < l; ++i) {
componentType = updateList[i];
this._currentUpdateComponentType = componentType;
updatingComponents[componentType]._update(dt);
}
}
private _clearStopComponents(): void {
const toStopComponents = this._toStopComponents;
const l = toStopComponents.length;
if (l > 0) {
for (let i = 0; i < l; ++i) {
const component = toStopComponents[i];
if (!component.needUpdate && component._updating) {
this._removeComponentToUpdateList(component);
if (component._needDestroy) {
this._destroyComponent(component);
}
}
}
toStopComponents.length = 0;
}
}
private _addUpdateComponents(): void {
const toUpdateComponents = this._toUpdateComponents;
const l = toUpdateComponents.length;
if (l > 0) {
for (let i = 0; i < l; ++i) {
const component = toUpdateComponents[i];
if (component.needUpdate && !component._updating) {
this._addComponentToUpdateList(component);
}
}
toUpdateComponents.length = 0;
}
}
}

View File

@@ -0,0 +1,84 @@
import { Component } from "./Component";
import { ObjectBase } from "./ObjectBase";
import { ObjectFactory } from "./ObjectFactory";
export class ComponentPool {
/** 组件对象类型到组件类型转换 */
private readonly _objectTypeToComponentType: number[] = new Array<number>(128);
private _pools: Map<number, ObjectFactory> = new Map();
private _nameToObjectType: Map<string, number> = new Map();
/**
* 注册组件
* @param {number} componentObjectType 组件对象类型
* @param {number} componentType 组件类型
* @param {string} name 组件名称
* @param {new () => Component} ctor 构造函数
*/
public register(componentObjectType: number, componentType: number, name: string, ctor: new () => ObjectBase): void {
if (this._pools.has(componentObjectType)) {
throw new Error(`组件(${name})已注册, 不允许重复注册`);
}
this._pools.set(componentObjectType, new ObjectFactory(componentObjectType, 128, name, ctor));
this._nameToObjectType.set(name, componentObjectType);
const objectTypeToComponentType = this._objectTypeToComponentType;
for (let i = objectTypeToComponentType.length; i <= componentObjectType; ++i) {
objectTypeToComponentType.push(i);
}
objectTypeToComponentType[componentObjectType] = componentType;
}
public getObjectTypeByName(componentName: string): number {
return this._nameToObjectType.get(componentName);
}
/**
* 创建组件
* @param {number} componentName 组件名
* @returns {T} 创建的组件
*/
public get<T extends Component>(componentName: string): T {
let objectType = this.getObjectTypeByName(componentName);
const factory = this._pools.get(objectType);
if (!factory) {
throw new Error(`组件(${componentName})未注册,使用组件装饰器 ecclass 注册组件`);
}
const component = factory.allocate() as T;
component.name = factory.name;
component.type = this._objectTypeToComponentType[objectType];
return component;
}
/**
* 通过组件对象类型获取组件类名
* @param {number} componentObjectType 组件类型
* @returns {string}
*/
public className(componentObjectType: number): string {
const factory = this._pools.get(componentObjectType);
if (!factory) {
throw new Error(
`组件(${componentObjectType}没有注册使用ComponentPool.register(componentObjectType, componentType, componentClass)注册组件`
);
}
return factory.name;
}
/**
* 回收组件
* @param {BaseComponent} component 要回收的组件
* @memberof ComponentPool
*/
public recycle(component: Component): void {
const objectFactory = this._pools.get(component.objectType);
objectFactory.recycle(component);
}
/** 清理缓存 */
public clear(): void {
for (const factory of this._pools.values()) {
factory._clear();
}
}
}

View File

@@ -0,0 +1,109 @@
import { color, size, v2, v3 } from "cc";
import { _ecdecorator, ComponentPool, warn } from "../kunpocc";
import { Component } from "./Component";
/**
* @Author: Gongxh
* @Date: 2025-01-24
* @Description:
*/
export class ECDataHelper {
/** 组件池 */
public static _componentPool: ComponentPool = new ComponentPool();
/** 注册所有组件 */
public static registerComponents(): void {
let index = 0;
let maps = _ecdecorator.getComponentMaps();
maps.forEach((info: _ecdecorator.ECComponentInfo, ctor: any) => {
this._componentPool.register(index++, info.componentType, info.name, ctor);
});
}
public static getComponentPool(): ComponentPool {
return this._componentPool;
}
/** 解析组件数据 */
public static parse(component: Component, data: Record<string, any>): void {
const maps = _ecdecorator.getComponentMaps();
const ctor = component.constructor;
if (!maps.has(ctor)) {
return;
}
const info = maps.get(ctor);
for (const property in data) {
let propInfo = info.props[property];
if (!propInfo) {
warn(`组件 ${component.name} 属性 ${property} 未注册`);
continue;
}
let value = data[property];
(component as any)[property] = this.getPropValue(propInfo, value);
}
}
private static getPropValue(propInfo: _ecdecorator.ECPropInfo, value: any): any {
switch (propInfo.type) {
case "int":
if (typeof value === "number") {
return value;
}
return propInfo.defaultValue || 0;
case "float":
if (typeof value === "number") {
return value;
}
return propInfo.defaultValue || 0;
case "boolean":
if (typeof value === "boolean") {
return value;
}
return propInfo.defaultValue || false;
case "size":
if (typeof value === "object" && typeof value.width === "number" && typeof value.height === "number") {
return size(value.width, value.height);
}
return propInfo.defaultValue || size(0, 0);
case "vec2":
if (typeof value === "object" && typeof value.x === "number" && typeof value.y === "number") {
return v2(value.x, value.y);
}
return propInfo.defaultValue || v2(0, 0);
case "vec3":
if (typeof value === "object" && typeof value.x === "number" && typeof value.y === "number" && typeof value.z === "number") {
return v3(value.x, value.y, value.z);
}
return propInfo.defaultValue || v3(0, 0, 0);
case "color":
if (typeof value === "object" && typeof value[0] === "number" && typeof value[1] === "number" && typeof value[2] === "number") {
return color(value[0], value[1], value[2], typeof value[3] === "number" ? value[3] : 255);
}
return propInfo.defaultValue || color(255, 255, 255, 255);
case "asset":
case "spriteframe":
case "prefab":
case "jsonAsset":
case "particle":
case "animation":
case "audio":
case "skeleton":
case "entity":
return typeof value === "string" ? value : (propInfo.defaultValue || "");
case "enum":
return value;
case "array":
if (Array.isArray(value)) {
return value;
}
return propInfo.defaultValue || [];
case "object":
if (typeof value === "object") {
return value;
}
return propInfo.defaultValue || {};
default:
break;
}
return undefined;
}
}

140
src/ecmodule/ECDecorator.ts Normal file
View File

@@ -0,0 +1,140 @@
/**
* @Author: Gongxh
* @Date: 2025-01-14
* @Description: 实体组件装饰器
*/
import { Color, Size, Vec2, Vec3 } from "cc";
import { ObjectHelper } from "../tool/helper/ObjectHelper";
export namespace _ecdecorator {
const ECPropMeta = "__ecpropmeta__"
type ECPropType = "int" | "float" | "string" | "boolean" | "size" | "vec2" | "vec3" | "color" | "asset" | "spriteframe" | "jsonAsset" | "particle" | "animation" | "audio" | "prefab" | "skeleton" | "enum" | "array" | "object" | "entity";
interface ECPropInfoBase {
/** 属性默认值 */
defaultValue?: any,
/** 编辑器中的显示名称 */
displayName?: string,
/** 编辑器中的提示 */
tips?: string
}
interface ECPropInfoNumber extends ECPropInfoBase {
/** 属性类型 */
type: "int" | "float";
/** 默认值:0 */
defaultValue?: number;
}
interface ECPropInfoBoolean extends ECPropInfoBase {
/** 属性类型 */
type: "boolean";
/** 默认值:false */
defaultValue?: boolean;
}
interface ECPropInfoSize extends ECPropInfoBase {
/** 属性类型 */
type: "size";
/** 默认值:Size(0,0) */
defaultValue?: Size;
}
interface ECPropInfoVec extends ECPropInfoBase {
/** 属性类型 */
type: "vec2" | "vec3";
/** 默认值: Vec2(0,0) | Vec3(0,0,0) */
defaultValue?: Vec2 | Vec3;
}
interface ECPropInfoString extends ECPropInfoBase {
/** 属性类型 */
type: "string" | "asset" | "spriteframe" | "jsonAsset" | "particle" | "animation" | "audio" | "prefab" | "skeleton" | "entity";
/** 默认值: "" */
defaultValue?: string;
}
interface ECPropInfoColor extends ECPropInfoBase {
/** 属性类型 */
type: "color";
/** 默认值:Color(255, 255, 255, 255) */
defaultValue?: Color;
}
interface ECPropInfoArray extends ECPropInfoBase {
/** 属性类型 */
type: "array";
/** 类型格式 当类型是复合类型enum、array、object时必须 */
format: ECPropType | ECPropInfo;
}
interface ECPropInfoObject extends ECPropInfoBase {
/** 属性类型 */
type: "object";
/** 类型格式 当类型是复合类型enum、array、object时必须 */
format: Record<string, ECPropType> | Record<string, ECPropInfo>;
}
interface ECPropInfoEnum extends ECPropInfoBase {
type: "enum";
/** 枚举值 */
format: object;
/** 默认值 */
defaultValue?: string | number;
}
export type ECPropInfo = ECPropInfoNumber | ECPropInfoBoolean | ECPropInfoSize | ECPropInfoVec | ECPropInfoString | ECPropInfoColor | ECPropInfoArray | ECPropInfoObject | ECPropInfoEnum;
/**
* 组件注册数据结构
*/
export interface ECComponentInfo {
/** 组件名 */
name: string;
/** 组件类型 */
componentType: number;
/** 组件描述 */
describe: string;
/** 属性 */
props: Record<string, ECPropInfo>;
}
/** 用来存储组件注册信息 */
const eclassMap: Map<any, ECComponentInfo> = new Map();
/** 获取组件注册信息 */
export function getComponentMaps(): Map<any, ECComponentInfo> {
return eclassMap;
}
/**
* 实体组件装饰器
* @param {string} res.describe 组件组描述
*/
export function ecclass(name: string, componentType: number, res?: { describe?: string }): Function {
/** target 类的构造函数 */
return function (ctor: any): void {
// console.log(`组件装饰器 组件【${name}】属性:`, JSON.stringify(ctor[ECPropMeta]));
eclassMap.set(ctor, {
name: name,
componentType: componentType,
props: ctor[ECPropMeta],
describe: res?.describe || name
});
};
}
/** 组件属性装饰器 */
export function ecprop(options: ECPropInfo): any {
return function (target: any, propName: any): void {
ObjectHelper.getObjectProp(target.constructor, ECPropMeta)[propName] = options;
};
}
}
let _global = globalThis || window || global;
(_global as any)["getKunpoRegisterECMaps"] = function () {
return _ecdecorator.getComponentMaps() as any;
};

162
src/ecmodule/ECManager.ts Normal file
View File

@@ -0,0 +1,162 @@
/**
* @Author: Gongxh
* @Date: 2025-01-14
* @Description: 实体组件管理对外接口
*/
import { Node } from "cc";
import { ECDataHelper } from "./ECDataHelper";
import { Entity } from "./Entity";
import { EntityManager } from "./EntityManager";
interface IEntityConfig {
[componentName: string]: Record<string, any>
}
interface IWorldConfig {
/** 实体管理器 */
world: EntityManager;
/** 世界节点 */
worldNode: Node;
}
export class ECManager {
/** 实体管理器 */
private static _worlds: Map<string, IWorldConfig> = new Map();
/** 实体配置信息 */
private static _entityList: { [name: string]: Record<string, any> } = {};
/** 注册所有组件 如果GameEntry因分包导致组件的代码注册晚于 CocosEntry的 onInit函数, 则需要在合适的时机手动调用此方法 */
public static registerComponents(): void {
ECDataHelper.registerComponents();
}
/**
* 创建EC世界 创建EC世界前必须先注册组件
* @param {string} worldName 名称
* @param {Node} node 世界节点
* @param {number[]} componentUpdateOrderList 组件更新顺序列表 (只传需要更新的组件列表)
* @param {number} [maxCapacityInPool=128] 实体池最大容量,多余的实体不会缓存
* @param {number} [preloadEntityCount=32] 预加载Entity数量
*/
public static createECWorld(worldName: string, node: Node, componentUpdateOrderList: number[], maxCapacityInPool = 128, preloadEntityCount = 32): EntityManager {
if (this._worlds.has(worldName)) {
throw new Error(`ECWorld ${worldName} already exists`);
}
const entityManager = new EntityManager(worldName, ECDataHelper.getComponentPool(), componentUpdateOrderList, maxCapacityInPool, preloadEntityCount);
this._worlds.set(worldName, { world: entityManager, worldNode: node });
return entityManager;
}
/** 获取EC世界 */
public static getECWorld(worldName: string): EntityManager {
if (!this._worlds.has(worldName)) {
throw new Error(`ECWorld ${worldName} not found`);
}
const entityManager = this._worlds.get(worldName).world;
if (!entityManager) {
throw new Error(`ECWorld ${worldName} is null`);
}
return entityManager;
}
/** 获取EC世界节点 */
public static getECWorldNode(worldName: string): Node {
if (!this._worlds.has(worldName)) {
throw new Error(`ECWorld ${worldName} not found`);
}
const node = this._worlds.get(worldName).worldNode;
if (!node) {
throw new Error(`ECWorld ${worldName} is null`);
}
return node;
}
/** 销毁EC世界 */
public static destroyECWorld(worldName: string): void {
let entityManager = this.getECWorld(worldName);
if (entityManager) {
entityManager.destroy();
this._worlds.delete(worldName);
}
}
/**
* 注册配置表中的实体信息
* @param config 实体配置信息,格式为 {实体名: {组件名: 组件数据}}
*/
public static registerEntityConfig(config: { [entityName: string]: IEntityConfig }): void {
// 遍历并注册每个实体的配置
for (const entityName in config) {
this._entityList[entityName] = config[entityName];
}
}
/**
* 添加实体信息 (如果已经存在, 则数据组合)
* 如果存在编辑器编辑不了的数据 用来给编辑器导出的实体信息 添加扩展数据
* @param name 实体名
* @param info 实体信息
*/
public static addEntityInfo(name: string, info: IEntityConfig): void {
if (this._entityList[name]) {
this._entityList[name] = Object.assign(this._entityList[name], info);
} else {
this._entityList[name] = info;
}
}
/** 获取实体配置信息 */
public static getEntityInfo(name: string): Record<string, any> {
if (!this._entityList[name]) {
throw new Error(`Entity ${name} info not found, please register it first`);
}
return this._entityList[name];
}
/**
* 创建实体
* @param worldName 实体管理器名称
* @param name 实体名字
* @returns {kunpo.Entity} 实体
*/
public static createEntity(worldName: string, name: string): Entity {
let info = this.getEntityInfo(name);
let world = this.getECWorld(worldName);
let entity = world.createEntity(name);
info && this._addComponentToEntity(world, entity, info);
world.addEntity(entity);
return entity;
}
private static _addComponentToEntity(world: EntityManager, entity: Entity, componentsData: Record<string, any>): void {
for (const componentName in componentsData) {
let component = world.createComponent(componentName);
ECDataHelper.parse(component, componentsData[componentName]);
entity.addComponent(component);
}
}
/**
* 销毁实体
* @param worldName 世界名称
* @param entity 实体
*/
public static destroyEntity(worldName: string, entity: Entity): void {
if (!entity || !entity.id) {
return;
}
this.destroyEntityById(worldName, entity.id);
}
/**
* 销毁实体
* @param worldName 世界名称
* @param entityId 实体ID
*/
public static destroyEntityById(worldName: string, entityId: number): void {
let world = this.getECWorld(worldName);
world.destroyEntityById(entityId);
}
}

79
src/ecmodule/ECType.ts Normal file
View File

@@ -0,0 +1,79 @@
/**
* @type {&} AND按位与处理两个长度相同的二进制数两个相应的二进位都为 1该位的结果值才为 1否则为 0
* @type {|} OR按位或处理两个长度相同的二进制数两个相应的二进位中只要有一个为 1该位的结果值为 1
* @type {~} 取反,取反是一元运算符,对一个二进制数的每一位执行逻辑反操作。使数字 1 成为 00 成为 1
* @type {^} 异或,按位异或运算,对等长二进制模式按位或二进制数的每一位执行逻辑异按位或操作。操作的结果是如果某位不同则该位为 1否则该位为 0
* @type {<<} 左移,把 << 左边的运算数的各二进位全部左移若干位,由 << 右边的数指定移动的位数高位丢弃低位补0; 将一个值左移一个位置相当于将其乘以2移位两个位置相当于乘以4依此类推。
* @type {>>} 右移,把 >> 左边的运算数的各二进位全部右移若干位,>> 右边的数指定移动的位数
* @type {>>>} 无符号右移与有符号右移位类似除了左边一律使用0 补位
*/
import { Stack } from "../tool/DataStruct/Stack";
export const EntityIndexBits = 16;
export const EntityIndexMask = (1 << EntityIndexBits) - 1;
export const MaxEntityCount = 1 << EntityIndexBits;
export type EntityId = number;
/**
* 2进制转10进制 (不支持小数和负数)
* @param {number} bitNumber 二进制数
* @return {number} 十进制数
*/
export function bit2Decimal(bitNumber: number): number {
let bitString = String(bitNumber);
let len = bitString.length;
let index = len - 1;
let result: number = 0;
do {
result += Number(bitString[index]) * Math.pow(2, len - index - 1);
index--;
} while (index >= 0);
return result;
}
/**
* 10进制转2进制 (不支持小数和负数)
* @param {number} num 十进制数
* @return {number} 二进制数
*/
export function decimal2Bit(num: number): number {
let stack = new Stack<number>();
let dividend: number = Math.floor(num);
let remainder: number;
do {
remainder = dividend % 2;
stack.push(remainder);
dividend = Math.floor(dividend / 2);
} while (dividend > 0);
let result = "";
while (!stack.isEmpty()) {
result += stack.pop().toString();
}
return Number(result);
}
/**
* 通过实体id获取实体index
* @param id 实体id
*/
export function getEntityIndex(id: EntityId): number {
return id & EntityIndexMask;
}
/**
* 通过实体id获取实体版本
* @param id
*/
export function getEntityVersion(id: EntityId): number {
return id >>> EntityIndexBits;
}
/**
* 实体描述
* @param id 实体id
*/
export function entityIdString(id: EntityId): string {
return `${getEntityIndex(id)}:${getEntityVersion(id)}`;
}
// console.log("-------->", EntityIndexBits); 16
// console.log("-------->", EntityIndexMask); 65535
// console.log("-------->", MaxEntityCount); 65536

277
src/ecmodule/Entity.ts Normal file
View File

@@ -0,0 +1,277 @@
import { Component } from "./Component";
import { EntityId } from "./ECType";
import { EntityManager } from "./EntityManager";
export class Entity {
/**
* 实体名称
* @type {String}
*/
public name: string;
/**
* 实体ID
* @type {EntityId}
*/
public id: EntityId;
/**
* 实体标识
* @type {Set<number>}
* @memberof Entity
*/
public tags: Set<number>;
/**
* 实体状态
* @type {Map<number, number>}
* @memberof Entity
*/
public states: Map<number, number>;
/**
* 是否被激活 (添加到实体管理器时激活)
* @type {boolean}
*/
public active: boolean = false;
/**
* 所属实体管理器 (实体创建后直接赋值)
* @private
* @type {EntityManager}
*/
public entityManager: EntityManager;
/**
* 所有组件
* @type {Map<number, Component>}
* @type {number} 组件类型
* @type {Component} 组件
*/
public readonly components: Map<number, Component> = new Map();
/**
* 实体被添加到EntityManager
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _add(): void {
this.active = true;
for (const component of this.components.values()) {
component._enter();
}
}
/**
* 实体销毁,不要手动调用
* @memberof Entity
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _destroy(): void {
this.removeAllComponents();
this.tags && this.tags.clear();
this.states && this.states.clear();
this.active = false;
this.entityManager = null;
}
/**
* 添加标签
* @param {number[]} ...tags 标签除了表示Entity还可以通过EntityManager获取指定标签的Entity
*/
public addTag(...tag: number[]): void {
let tags = this.tags;
if (!tags) {
tags = this.tags = new Set<number>();
}
for (let i = 0; i < tag.length; i++) {
tags.add(tag[i]);
this.active && this.entityManager && this.entityManager._addEntityTag(this.id, tag[i]);
}
}
/**
* 删除标签
* @param {number} tag 删除的标签
*/
public removeTag(tag: number): void {
if (this.tags) {
this.tags.delete(tag);
this.active && this.entityManager && this.entityManager._removeEntityTagById(this.id, tag);
}
}
/**
* 是否包含标签
* @param {number} tag 标签
* @returns {boolean} 是否包含
*/
public hasTag(...tag: number[]): boolean {
let tags = this.tags;
if (!tags) {
return false;
}
for (let i = 0; i < tag.length; i++) {
if (tags.has(tag[i])) {
return true;
}
}
return false;
}
/**
* 获取组件
* @param {number} componentType 组件类型
* @returns {T}
*/
public getComponent<T extends Component>(componentType: number): T {
return this.components.get(componentType) as T;
}
/**
* 添加组件
* @param {Component} component 组件
*/
public addComponent(component: Component): void {
if (this.hasComponent(component.type)) {
throw new Error(`组件{${component.constructor.name}类型:${component.type})已经存在,不允许添加同一类型组件`);
}
this.components.set(component.type, component);
component.entity = this;
component._add();
if (this.active) {
component._enter();
}
}
/**
* 删除组件
* @param {number} componentType 组件类型
*/
public removeComponent(componentType: number): void {
const component = this.components.get(componentType);
if (component) {
this.components.delete(componentType);
component._remove();
}
}
/**
* 删除所有组件
*/
public removeAllComponents(): void {
for (const component of this.components.values()) {
component._remove();
}
this.components.clear();
}
/**
* 是否包含组件
* @param {number} componentType 组件类型
* @returns {boolean} 是否包含组件
*/
public hasComponent(componentType: number): boolean {
return this.components.has(componentType);
}
/**
* 销毁自己
*/
public destroy(): void {
this.entityManager.destroyEntityById(this.id);
}
/**
* 添加监听
* @param eventName 监听的消息名
* @param callback 回调
* @param entityId 实体ID
* @param once 是否单次监听
*/
public addEvent(eventName: string, callback: (...args: any[]) => void, once: boolean = false): void {
this.entityManager && this.entityManager._addEvent(eventName, callback, this, once);
}
/**
* 发送消息
* @param eventName 消息名
* @param entityId 实体ID
* @param args 发送参数
*/
public sendListener(eventName: string, ...args: any[]): void {
this.entityManager && this.entityManager._sendEvent(eventName, this, ...args);
}
public removeListener(eventName: string, callback?: (...args: any[]) => void): void {
this.entityManager && this.entityManager._removeEvent(eventName, this, callback);
}
/**
* 添加状态
* 状态采用计数方式对状态处理时需要保证addState和removeState成对存在
* @param {number} state 状态类型
* @memberof Entity
*/
public addState(state: number): void {
let states = this.states;
if (!states) {
states = this.states = new Map<number, number>();
}
states.set(state, (states.get(state) || 0) + 1);
}
/**
* 删除状态
*
* @param {number} state 状态类型
* @returns {boolean} 如果计数为0或状态不存在则返回true
* @memberof Entity
*/
public removeState(state: number): boolean {
const states = this.states;
if (!states) {
return false;
}
let stateCount = states.get(state);
if (stateCount) {
// 处理状态计数为0则删除状态
--stateCount;
if (stateCount == 0) {
states.delete(state);
return true;
}
states.set(state, stateCount);
return false;
}
return true;
}
/**
* 是否包含指定状态
* @param {number} state 状态
* @returns {boolean}
* @memberof Entity
*/
public hasState(state: number): boolean {
return this.states && this.states.has(state);
}
/**
* 清除状态
* @param {number} state 状态
* @memberof Entity
*/
public clearState(state: number): void {
this.states && this.states.delete(state);
}
/**
* 清除所有状态
* @memberof Entity
*/
public clearAllStates(): void {
this.states && this.states.clear();
}
}

View File

@@ -0,0 +1,420 @@
import { EventManager } from "../event/EventManager";
import { warn } from "../tool/log";
import { Component } from "./Component";
import { ComponentManager } from "./ComponentManager";
import { ComponentPool } from "./ComponentPool";
import { EntityId, entityIdString, EntityIndexBits, getEntityIndex, getEntityVersion, MaxEntityCount } from "./ECType";
import { Entity } from "./Entity";
export class EntityManager {
/**
* 名称
* @type {string}
*/
public name: string;
/**
* 单例实体
* @type {Entity}
*/
public readonly insEntity: Entity = new Entity();
/**
* 单例实体激活状态
* @type {boolean}
*/
public insActive: boolean = false;
/**
* 组件管理
* @type {ComponentManager}
*/
public componentManager: ComponentManager;
/**
* 普通实体事件容器
* @type {EventManager}
*/
private _eventManager: EventManager;
/**
* 单例实体消息监听容器
* @type {EventManager}
*/
private _insEventManager: EventManager;
/** 实体池 */
private readonly _entityPool: Entity[] = [];
/** tag标记池 */
private readonly _tagToEntity: Map<number, Set<EntityId>> = new Map<number, Set<EntityId>>();
/** 实体回收池 */
private _recyclePool: Entity[] = [];
/** 实体回收池最大容量 */
private _maxCapacityInPool: number;
/** 实体回收版本 */
private _entityVersion: number[] = [];
/** 回收实体ID */
private _recycleEntityIds: EntityId[] = [];
/** 世界是否删除 */
private _isDestroyed: boolean;
/** 是否正在更新 */
private _updating: boolean;
/**
* 实体池最大容量,回收的多余的实体不会缓存
* @param {string} name 名称
* @param {ComponentPool} componentPool 组件池
* @param {ComponentPool} componentUpdateOrderList 组件更新顺序
* @param {number} [maxCapacityInPool=128] 实体回收池最大容量
* @param {number} [preloadEntityCount=32] 预加载Entity数量
*/
// eslint-disable-next-line prettier/prettier
constructor(name: string, componentPool: ComponentPool, componentUpdateOrderList: number[], maxCapacityInPool: number = 128, preloadEntityCount: number = 32) {
this.name = name;
if (preloadEntityCount >= MaxEntityCount) {
throw new Error(`预加载超出实体最大数量:${preloadEntityCount} >= max(${MaxEntityCount})`);
}
// 占位
this._entityPool.push(null);
this._entityVersion.push(1);
this._maxCapacityInPool = maxCapacityInPool;
// 预创建
for (let i = 0; i < preloadEntityCount; ++i) {
this._recyclePool.push(new Entity());
}
// 组件管理器
this.componentManager = new ComponentManager(componentPool, componentUpdateOrderList);
this.insEntity.entityManager = this;
}
/**
* 添加实体标签(内部使用)
* @param {EntityId} entityId 实体Id
* @param {number} tag 标签
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _addEntityTag(entityId: EntityId, tag: number): void {
this._validateEntityById(entityId);
let entitiesByTag = this._tagToEntity.get(tag);
if (!entitiesByTag) {
entitiesByTag = new Set<EntityId>();
this._tagToEntity.set(tag, entitiesByTag);
}
entitiesByTag.add(entityId);
}
/**
* 删除实体Tag内部使用
* @param {Entity} entity 实体
* @param {number} tag 标签
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _removeEntityTag(entity: Entity, tag: number): void {
this._removeEntityTagById(entity.id, tag);
}
/**
* 通过实体ID删除实体Tag内部使用
* @param {EntityId} entityId 实体Id
* @param {number} tag 标签
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
public _removeEntityTagById(entityId: EntityId, tag: number): void {
this._validateEntityById(entityId);
const entitiesByTag = this._tagToEntity.get(tag);
if (entitiesByTag) {
entitiesByTag.delete(entityId);
}
}
/**
* 创建实体
* @returns {Entity} 实体
*/
public createEntity(name: string): Entity {
const entity = this._recyclePool.pop() || new Entity();
entity.id = 0;
entity.name = name;
entity.entityManager = this;
return entity;
}
/**
* 添加实体
* @param {Entity} entity 要添加的实体
*/
public addEntity(entity: Entity): void {
if (this.exists(entity.id)) {
throw new Error(`实体(${entityIdString(entity.id)}已经添加到EntityManager`);
}
// 分配实体Id
if (this._recycleEntityIds.length > 0) {
const newIndex = this._recycleEntityIds.pop();
this._entityPool[newIndex] = entity;
entity.id = (this._entityVersion[newIndex] << EntityIndexBits) | newIndex;
} else {
this._entityPool.push(entity);
this._entityVersion.push(1);
entity.id = MaxEntityCount | (this._entityPool.length - 1);
}
this._addEntityToTag(entity);
entity._add();
}
/**
* 销毁实体
* @param {Entity} entity 要删除的实体
*/
public destroyEntity(entity: Entity): void {
this.destroyEntityById(entity.id);
}
/**
* 销毁指定ID实体
* @param {EntityId} entityId 实体Id
*/
public destroyEntityById(entityId: EntityId): void {
const entity = this.getEntity(entityId);
if (!entity) {
warn(`实体(${entityIdString(entityId)})已经被销毁`);
return;
}
this._recycleEntity(entity);
this._eventManager && this._eventManager.removeList(entity);
}
/**
* 销毁所有实体
* @param {boolean} ignoreSingletonEntity 是否忽略单例实体
*/
public destroyAllEntities(ignoreSingletonEntity: boolean): void {
const entities = this._entityPool;
for (let i = 1, len = entities.length; i < len; ++i) {
if (entities[i]) {
this._destroyEntity(entities[i]);
}
}
this._recycleEntityIds.length = 0;
this._entityPool.length = 0;
this._entityVersion.length = 0;
this._tagToEntity.clear();
// 占位
this._entityPool.push(null);
this._entityVersion.push(1);
this._eventManager && this._eventManager.destroyAll();
// 销毁单例实体组件
if (!ignoreSingletonEntity) {
this.insEntity._destroy();
this.insActive = false;
this._insEventManager && this._insEventManager.destroyAll();
}
}
/**
* 通过实体ID获取实体
* @param {EntityId} entityId 实体Id
* @returns {(Entity | null)} 实体
*/
public getEntity(entityId: EntityId): Entity | null {
const index = getEntityIndex(entityId);
if (index <= 0 || index >= this._entityPool.length) {
return null;
}
if (this._entityVersion[index] == getEntityVersion(entityId)) {
return this._entityPool[index];
}
return null;
}
/**
* 获取指定标签的实体
* @param {number} tag 标签
* @returns {Entity[]} 返回的实体池
*/
public getEntitiesByTag(tag: number): Entity[] {
let buffer: Entity[] = [];
const entitiesByTag = this._tagToEntity.get(tag);
if (entitiesByTag) {
for (const entityId of entitiesByTag) {
const entity = this.getEntity(entityId);
entity && buffer.push(entity);
}
}
return buffer;
}
/**
* 根据实体ID判断实体是否存在
* @param {EntityId} entityId 实体Id
* @returns {boolean}
*/
public exists(entityId: EntityId): boolean {
const index = getEntityIndex(entityId);
if (index <= 0 || index >= this._entityPool.length) {
return false;
}
const entity = this._entityPool[index];
return entity && this._entityVersion[index] == getEntityVersion(entityId);
}
/**
* 创建组件
* @template T 组件类型
* @param {string} componentName 组件名
* @returns {T} 创建的组件
*/
public createComponent<T extends Component>(componentName: string): T {
return this.componentManager.createComponent<T>(componentName);
}
/**
* 添加单例组件
* @param component
*/
public addSingleton(component: Component): void {
this.insEntity.addComponent(component);
}
/**
* 获取单例组件
*/
public getSingleton<T extends Component>(componentType: number): T {
return this.insEntity.getComponent<T>(componentType);
}
/**
* 删除单例组件
*/
public removeSingleton(componentType: number): void {
this.insEntity.removeComponent(componentType);
}
/**
* 是否存在对应的单例组件
*/
public hasSingleton(componentType: number): boolean {
return this.insEntity.hasComponent(componentType);
}
/**
* 激活单例组件
*/
public activeSingleton(): void {
const insEntity = this.insEntity;
if (this.insActive) {
throw new Error("单例实体已经被激活");
}
this.insActive = true;
insEntity.id = -1;
insEntity._add();
}
/**
* 销毁EntityManager
*/
public destroy(): void {
if (this._isDestroyed) {
return;
}
if (this._updating) {
throw new Error("请勿在更新时销毁EntityManager");
}
this.destroyAllEntities(false);
this.componentManager.destroy();
this._isDestroyed = true;
}
/**
* 添加消息监听 (内部使用)
* @param eventName 消息名
* @param callback 事件回调
* @param entityId 实体ID
* @param once 是否单次事件
*/
public _addEvent(eventName: string, callback: (...args: any[]) => void, entity: Entity, once: boolean = false): void {
if (entity == this.insEntity) {
this._insEventManager = this._insEventManager ? this._insEventManager : new EventManager();
this._insEventManager._addEvent(eventName, callback, once, entity);
return;
}
this._eventManager = this._eventManager ? this._eventManager : new EventManager();
this._eventManager._addEvent(eventName, callback, once, entity);
}
/**
* 发送消息 (内部使用)
* @param eventName 消息名
* @param entityId 实体ID
* @param args 发送参数
*/
public _sendEvent(eventName: string, entity: Entity, ...args: any[]): void {
if (entity == this.insEntity) {
this._insEventManager && this._insEventManager.send(eventName, entity, ...args);
return;
}
this._eventManager && this._eventManager.send(eventName, entity, ...args);
}
public _removeEvent(eventName: string, entity: Entity, callback?: (...args: any[]) => void): void {
if (entity == this.insEntity) {
this._insEventManager && this._insEventManager.remove(eventName, callback, entity);
return;
}
this._eventManager && this._eventManager.remove(eventName, callback, entity);
}
/** 更新 */
public update(dt: number): void {
this._updating = true;
this.componentManager._update(dt);
this._updating = false;
}
/**
* 回收Entity
* @param {Entity} entity 要回收的Entity
*/
private _recycleEntity(entity: Entity): void {
// 回收实体Id
const entityIndex = getEntityIndex(entity.id);
this._recycleEntityIds.push(entityIndex);
this._entityPool[entityIndex] = null;
++this._entityVersion[entityIndex];
this._destroyEntity(entity);
}
/**
* 销毁实体
* @param {Entity} entity
*/
// eslint-disable-next-line @typescript-eslint/member-ordering
private _destroyEntity(entity: Entity): void {
entity._destroy();
if (this._recyclePool.length < this._maxCapacityInPool) {
this._recyclePool.push(entity);
}
}
/**
* 实体根据tag添加到tag列表中
* @param entity
*/
private _addEntityToTag(entity: Entity): void {
const tags = entity.tags;
if (!tags || tags.size == 0) {
return;
}
const entityId = entity.id;
for (const tag of tags.values()) {
this._addEntityTag(entityId, tag);
}
}
private _validateEntityById(entityId: EntityId): void {
if (!this.exists(entityId)) {
throw new Error(`实体(${entityId})不存在`);
}
}
}

View File

@@ -0,0 +1,17 @@
export class ObjectBase {
/** 是否被回收 */
public recycled: boolean;
/** 对象类型 */
public objectType: number;
/** 回收 */
public _recycle(): void {
this.recycled = true;
}
/** 重新利用 */
public _reuse(): void {
this.recycled = false;
}
}

View File

@@ -0,0 +1,64 @@
import { ObjectBase } from "./ObjectBase";
export class ObjectFactory {
/** 对象类 */
private _ctor: new () => ObjectBase;
/** 对象名称 */
private _name: string;
/** 对象类型 */
private _objectType: number;
/** 最大容量 */
private _maxCapacity: number;
/** 对象池 */
private _stack: ObjectBase[] = [];
constructor(objectType: number, capacity: number, name: string, objectClass: new () => ObjectBase) {
this._objectType = objectType;
this._maxCapacity = capacity;
this._name = name;
this._ctor = objectClass;
}
/**
* 获取对象名称
* @returns {string} 对象名称
*/
public get name(): string {
return this._name;
}
/**
* 获取对象
* @returns {T} 返回的组件
*/
public allocate<T extends ObjectBase>(): T {
if (this._stack.length == 0) {
const ret = new this._ctor() as T;
ret.objectType = this._objectType;
return ret;
}
const ret = this._stack.pop() as T;
ret._reuse();
return ret;
}
/**
* 回收对象
* @returns {boolean}
*/
public recycle(ret: ObjectBase): boolean {
if (ret.recycled) {
throw new Error(`对象(${ret.constructor.name})已经被回收了`);
}
if (this._maxCapacity > 0 && this._stack.length < this._maxCapacity) {
ret._recycle();
this._stack.push(ret);
return true;
}
return false;
}
public _clear(): void {
this._stack.length = 0;
}
}