避免splice开销问题,改为SwapPop + typeId → denseIndex

This commit is contained in:
YHH
2025-09-03 10:56:33 +08:00
parent dbddbbdfb8
commit 7792710694

View File

@@ -74,92 +74,66 @@ export class Entity {
/**
* 实体名称
*
* 用于标识和调试的友好名称。
*/
public name: string;
/**
* 实体唯一标识符
*
* 在场景中唯一的数字标识符。
*/
public readonly id: number;
/**
* 组件集合
*
* 存储实体拥有的所有组件。
*/
public readonly components: Component[] = [];
/**
* 所属场景引用
*
* 指向实体所在的场景实例。
*/
public scene: IScene | null = null;
/**
* 更新间隔
*
* 控制实体更新的频率,值越大更新越不频繁。
*/
public updateInterval: number = 1;
/**
* 销毁状态标志
*
* 标记实体是否已被销毁。
*/
public _isDestroyed: boolean = false;
/**
* 父实体引用
*
* 指向父级实体,用于构建实体层次结构。
*/
private _parent: Entity | null = null;
/**
* 子实体集合
*
* 存储所有子级实体的数组。
*/
private _children: Entity[] = [];
/**
* 激活状态
*
* 控制实体是否处于激活状态。
*/
private _active: boolean = true;
/**
* 实体标签
*
* 用于分类和查询的数字标签。
*/
private _tag: number = 0;
/**
* 启用状态
*
* 控制实体是否启用更新和处理。
*/
private _enabled: boolean = true;
/**
* 更新顺序
*
* 控制实体在系统中的更新优先级。
*/
private _updateOrder: number = 0;
/**
* 组件位掩码
*
* 用于快速查询实体拥有的组件类型。
*/
private _componentMask: BitMask64Data = BitMask64Utils.clone(BitMask64Utils.ZERO);
@@ -168,6 +142,11 @@ export class Entity {
*/
private _componentsByTypeId: (Component | undefined)[] = [];
/**
* typeId到components数组中密集索引的映射表
*/
private _componentDenseIndexByTypeId: number[] = [];
/**
* 构造函数
*
@@ -181,7 +160,6 @@ export class Entity {
/**
* 获取销毁状态
*
* @returns 如果实体已被销毁则返回true
*/
public get isDestroyed(): boolean {
@@ -190,7 +168,6 @@ export class Entity {
/**
* 获取父实体
*
* @returns 父实体如果没有父实体则返回null
*/
public get parent(): Entity | null {
@@ -338,21 +315,20 @@ export class Entity {
private addComponentInternal<T extends Component>(component: T): T {
const componentType = component.constructor as ComponentType<T>;
// 注册组件类型(如果尚未注册)
if (!ComponentRegistry.isRegistered(componentType)) {
ComponentRegistry.register(componentType);
}
const typeId = ComponentRegistry.getBitIndex(componentType);
// 设置组件的实体引用
component.entity = this;
// 直址存储
this._componentsByTypeId[typeId] = component;
const denseIndex = this.components.length;
this._componentDenseIndexByTypeId[typeId] = denseIndex;
this.components.push(component);
// 更新位掩码
const componentMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(this._componentMask, componentMask);
@@ -369,23 +345,18 @@ export class Entity {
public addComponent<T extends Component>(component: T): T {
const componentType = component.constructor as ComponentType<T>;
// 检查是否已有此类型的组件
if (this.hasComponent(componentType)) {
throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`);
}
// 使用内部方法添加组件
this.addComponentInternal(component);
// 如果场景存在且有组件存储管理器,添加到存储器
if (this.scene && this.scene.componentStorageManager) {
this.scene.componentStorageManager.addComponent(this.id, component);
}
// 调用组件的生命周期方法
component.onAddedToEntity();
// 发射组件添加事件
if (Entity.eventBus) {
Entity.eventBus.emitComponentAdded({
timestamp: Date.now(),
@@ -399,9 +370,7 @@ export class Entity {
}
// 通知QuerySystem实体组件已改变需要重新索引
if (this.scene && this.scene.querySystem) {
// 移除旧的索引,重新添加以更新索引
this.scene.querySystem.removeEntity(this);
this.scene.querySystem.addEntity(this);
}
@@ -416,7 +385,6 @@ export class Entity {
* @returns 组件实例或null
*/
public getComponent<T extends Component>(type: ComponentType<T>): T | null {
// 首先检查位掩码快速排除O(1)
if (!ComponentRegistry.isRegistered(type)) {
return null;
}
@@ -426,7 +394,6 @@ export class Entity {
return null;
}
// 直址访问
const typeId = ComponentRegistry.getBitIndex(type);
const component = this._componentsByTypeId[typeId];
@@ -434,25 +401,24 @@ export class Entity {
return component as T;
}
// 如果场景有组件存储管理器,从存储器获取
if (this.scene && this.scene.componentStorageManager) {
const storageComponent = this.scene.componentStorageManager.getComponent(this.id, type);
if (storageComponent) {
// 同步到稀疏数组
this._componentsByTypeId[typeId] = storageComponent;
if (!this.components.includes(storageComponent)) {
const denseIndex = this.components.length;
this._componentDenseIndexByTypeId[typeId] = denseIndex;
this.components.push(storageComponent);
}
return storageComponent;
}
}
// 最后回退到线性搜索
for (let i = 0; i < this.components.length; i++) {
const component = this.components[i];
if (component instanceof type) {
// 同步到稀疏数组
this._componentsByTypeId[typeId] = component;
this._componentDenseIndexByTypeId[typeId] = i;
return component as T;
}
}
@@ -504,33 +470,42 @@ export class Entity {
public removeComponent(component: Component): void {
const componentType = component.constructor as ComponentType;
// 从稀疏数组中移除
if (ComponentRegistry.isRegistered(componentType)) {
const typeId = ComponentRegistry.getBitIndex(componentType);
this._componentsByTypeId[typeId] = undefined;
// 更新位掩码
const bitIndex = ComponentRegistry.getBitIndex(componentType);
BitMask64Utils.clearBit(this._componentMask, bitIndex);
}
// 从迭代数组中移除
const index = this.components.indexOf(component);
if (index !== -1) {
this.components.splice(index, 1);
if (!ComponentRegistry.isRegistered(componentType)) {
return;
}
// 从组件存储管理器中移除
const typeId = ComponentRegistry.getBitIndex(componentType);
this._componentsByTypeId[typeId] = undefined;
BitMask64Utils.clearBit(this._componentMask, typeId);
const denseIndex = this._componentDenseIndexByTypeId[typeId];
if (denseIndex !== undefined && denseIndex < this.components.length) {
const lastIndex = this.components.length - 1;
if (denseIndex !== lastIndex) {
const lastComponent = this.components[lastIndex];
this.components[denseIndex] = lastComponent;
const lastComponentType = lastComponent.constructor as ComponentType;
const lastTypeId = ComponentRegistry.getBitIndex(lastComponentType);
this._componentDenseIndexByTypeId[lastTypeId] = denseIndex;
}
this.components.pop();
}
this._componentDenseIndexByTypeId[typeId] = -1;
if (this.scene && this.scene.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
// 调用组件的生命周期方法
if (component.onRemovedFromEntity) {
component.onRemovedFromEntity();
}
// 发射组件移除事件
if (Entity.eventBus) {
Entity.eventBus.emitComponentRemoved({
timestamp: Date.now(),
@@ -543,13 +518,9 @@ export class Entity {
});
}
// 清除组件的实体引用
component.entity = null as any;
// 通知QuerySystem实体组件已改变需要重新索引
if (this.scene && this.scene.querySystem) {
// 移除旧的索引,重新添加以更新索引
this.scene.querySystem.removeEntity(this);
this.scene.querySystem.addEntity(this);
}
@@ -574,32 +545,25 @@ export class Entity {
* 移除所有组件
*/
public removeAllComponents(): void {
// 复制组件列表,避免在迭代时修改
const componentsToRemove = [...this.components];
// 清空稀疏数组和位掩码
this._componentsByTypeId.length = 0;
this._componentDenseIndexByTypeId.length = 0;
BitMask64Utils.clear(this._componentMask);
// 移除组件
for (const component of componentsToRemove) {
const componentType = component.constructor as ComponentType;
// 从组件存储管理器中移除
if (this.scene && this.scene.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
// 调用组件的生命周期方法
component.onRemovedFromEntity();
// 清除组件的实体引用
component.entity = null as any;
}
// 清空组件列表
this.components.length = 0;
}
/**
@@ -615,7 +579,6 @@ export class Entity {
try {
addedComponents.push(this.addComponent(component));
} catch (error) {
// 如果某个组件添加失败,继续添加其他组件
Entity._logger.warn(`添加组件失败 ${getComponentInstanceTypeName(component)}:`, error);
}
}
@@ -674,16 +637,13 @@ export class Entity {
return child; // 已经是子实体
}
// 如果子实体已有父实体,先从原父实体移除
if (child._parent) {
child._parent.removeChild(child);
}
// 设置父子关系
child._parent = this;
this._children.push(child);
// 如果子实体还没有场景,设置为父实体的场景
if (!child.scene && this.scene) {
child.scene = this.scene;
this.scene.addEntity(child);
@@ -704,7 +664,6 @@ export class Entity {
return false;
}
// 移除父子关系
this._children.splice(index, 1);
child._parent = null;
@@ -715,7 +674,6 @@ export class Entity {
* 移除所有子实体
*/
public removeAllChildren(): void {
// 复制子实体列表,避免在迭代时修改
const childrenToRemove = [...this._children];
for (const child of childrenToRemove) {
@@ -731,14 +689,12 @@ export class Entity {
* @returns 找到的子实体或null
*/
public findChild(name: string, recursive: boolean = false): Entity | null {
// 在直接子实体中查找
for (const child of this._children) {
if (child.name === name) {
return child;
}
}
// 递归查找
if (recursive) {
for (const child of this._children) {
const found = child.findChild(name, true);
@@ -761,14 +717,12 @@ export class Entity {
public findChildrenByTag(tag: number, recursive: boolean = false): Entity[] {
const result: Entity[] = [];
// 在直接子实体中查找
for (const child of this._children) {
if (child.tag === tag) {
result.push(child);
}
}
// 递归查找
if (recursive) {
for (const child of this._children) {
result.push(...child.findChildrenByTag(tag, true));
@@ -852,14 +806,12 @@ export class Entity {
* 活跃状态改变时的回调
*/
private onActiveChanged(): void {
// 通知所有组件活跃状态改变
for (const component of this.components) {
if ('onActiveChanged' in component && typeof component.onActiveChanged === 'function') {
(component as any).onActiveChanged();
}
}
// 通知场景实体状态改变
if (this.scene && this.scene.eventSystem) {
this.scene.eventSystem.emitSync('entity:activeChanged', {
entity: this,
@@ -879,14 +831,12 @@ export class Entity {
return;
}
// 更新所有组件
for (const component of this.components) {
if (component.enabled) {
component.update();
}
}
// 更新所有子实体
for (const child of this._children) {
child.update();
}
@@ -904,28 +854,22 @@ export class Entity {
this._isDestroyed = true;
// 销毁所有子实体
const childrenToDestroy = [...this._children];
for (const child of childrenToDestroy) {
child.destroy();
}
// 从父实体中移除
if (this._parent) {
this._parent.removeChild(this);
}
// 移除所有组件
this.removeAllComponents();
// 从场景中移除
if (this.scene) {
// 从查询系统中移除
if (this.scene.querySystem) {
this.scene.querySystem.removeEntity(this);
}
// 从实体列表中移除
if (this.scene.entities) {
this.scene.entities.remove(this);
}
@@ -971,6 +915,7 @@ export class Entity {
childIds: number[];
depth: number;
indexMappingSize: number;
denseIndexMappingSize: number;
} {
return {
name: this.name,
@@ -986,7 +931,8 @@ export class Entity {
childCount: this._children.length,
childIds: this._children.map(c => c.id),
depth: this.getDepth(),
indexMappingSize: this._componentsByTypeId.filter(c => c !== undefined).length
indexMappingSize: this._componentsByTypeId.filter(c => c !== undefined).length,
denseIndexMappingSize: this._componentDenseIndexByTypeId.filter(idx => idx !== -1 && idx !== undefined).length
};
}
}