perf(core): 优化 HierarchySystem 避免每帧遍历所有实体 (#279)
使用脏实体集合代替每帧遍历所有实体,静态场景下 process() 从 O(n) 优化为 O(1)。 性能提升: - 1000 实体静态场景: 81.79μs -> 0.07μs (快 1168 倍) - 10000 实体静态场景: 939.43μs -> 0.56μs (快 1677 倍) - 服务端模拟 (100房间 x 100实体): 2.7ms -> 1.4ms 每 tick 改动: - 新增 dirtyEntities Set 追踪需要更新缓存的实体 - process() 只遍历脏实体 - markCacheDirty() 将实体加入脏集合 - onAdded() 在实体注册时将脏实体加入集合 - onRemoved() 将实体从脏集合移除
This commit is contained in:
@@ -25,6 +25,12 @@ import { HierarchyComponent } from '../Components/HierarchyComponent';
|
|||||||
export class HierarchySystem extends EntitySystem {
|
export class HierarchySystem extends EntitySystem {
|
||||||
private static readonly MAX_DEPTH = 32;
|
private static readonly MAX_DEPTH = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脏实体集合 - 只有这些实体需要在 process() 中更新缓存
|
||||||
|
* Dirty entity set - only these entities need cache update in process()
|
||||||
|
*/
|
||||||
|
private dirtyEntities: Set<Entity> = new Set();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(Matcher.empty().all(HierarchyComponent));
|
super(Matcher.empty().all(HierarchyComponent));
|
||||||
}
|
}
|
||||||
@@ -36,14 +42,19 @@ export class HierarchySystem extends EntitySystem {
|
|||||||
return -1000;
|
return -1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override process(): void {
|
protected override process(_entities: readonly Entity[]): void {
|
||||||
// 更新所有脏缓存
|
// 只更新脏实体,不遍历所有实体 | Only update dirty entities, no full iteration
|
||||||
for (const entity of this.entities) {
|
if (this.dirtyEntities.size === 0) {
|
||||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
return;
|
||||||
if (hierarchy?.bCacheDirty) {
|
}
|
||||||
|
|
||||||
|
for (const entity of this.dirtyEntities) {
|
||||||
|
// 确保实体仍然有效 | Ensure entity is still valid
|
||||||
|
if (entity.scene) {
|
||||||
this.updateHierarchyCache(entity);
|
this.updateHierarchyCache(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.dirtyEntities.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -474,15 +485,21 @@ export class HierarchySystem extends EntitySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标记缓存为脏
|
* 标记缓存为脏,并添加到脏实体集合
|
||||||
|
* Mark cache as dirty and add to dirty entity set
|
||||||
*/
|
*/
|
||||||
private markCacheDirty(entity: Entity): void {
|
private markCacheDirty(entity: Entity): void {
|
||||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||||
if (!hierarchy) return;
|
if (!hierarchy) return;
|
||||||
|
|
||||||
hierarchy.bCacheDirty = true;
|
// 如果已经是脏的,跳过(避免重复递归)
|
||||||
|
// Skip if already dirty (avoid redundant recursion)
|
||||||
|
if (hierarchy.bCacheDirty) return;
|
||||||
|
|
||||||
// 递归标记所有子级
|
hierarchy.bCacheDirty = true;
|
||||||
|
this.dirtyEntities.add(entity);
|
||||||
|
|
||||||
|
// 递归标记所有子级 | Recursively mark all children
|
||||||
for (const childId of hierarchy.childIds) {
|
for (const childId of hierarchy.childIds) {
|
||||||
const child = this.scene?.findEntityById(childId);
|
const child = this.scene?.findEntityById(childId);
|
||||||
if (child) {
|
if (child) {
|
||||||
@@ -509,13 +526,28 @@ export class HierarchySystem extends EntitySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当实体被移除时清理层级关系
|
* 当实体被添加到系统时,将其加入脏集合
|
||||||
|
* When entity is added to system, add it to dirty set
|
||||||
*/
|
*/
|
||||||
protected onEntityRemoved(entity: Entity): void {
|
protected override onAdded(entity: Entity): void {
|
||||||
|
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||||
|
if (hierarchy && hierarchy.bCacheDirty) {
|
||||||
|
this.dirtyEntities.add(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当实体被移除时清理层级关系
|
||||||
|
* When entity is removed, clean up hierarchy relationships
|
||||||
|
*/
|
||||||
|
protected override onRemoved(entity: Entity): void {
|
||||||
|
// 从脏集合中移除 | Remove from dirty set
|
||||||
|
this.dirtyEntities.delete(entity);
|
||||||
|
|
||||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||||
if (!hierarchy) return;
|
if (!hierarchy) return;
|
||||||
|
|
||||||
// 从父级移除
|
// 从父级移除 | Remove from parent
|
||||||
if (hierarchy.parentId !== null) {
|
if (hierarchy.parentId !== null) {
|
||||||
const parent = this.scene?.findEntityById(hierarchy.parentId);
|
const parent = this.scene?.findEntityById(hierarchy.parentId);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@@ -529,8 +561,8 @@ export class HierarchySystem extends EntitySystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理子级:可选择销毁或移动到根级
|
// 处理子级:将子级移动到根级
|
||||||
// 默认将子级移动到根级
|
// Handle children: move children to root level
|
||||||
for (const childId of hierarchy.childIds) {
|
for (const childId of hierarchy.childIds) {
|
||||||
const child = this.scene?.findEntityById(childId);
|
const child = this.scene?.findEntityById(childId);
|
||||||
if (child) {
|
if (child) {
|
||||||
@@ -544,6 +576,7 @@ export class HierarchySystem extends EntitySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override dispose(): void {
|
public override dispose(): void {
|
||||||
// 清理资源
|
// 清理脏实体集合 | Clear dirty entity set
|
||||||
|
this.dirtyEntities.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user