Feature/editor optimization (#251)
* refactor: 编辑器/运行时架构拆分与构建系统升级 * feat(core): 层级系统重构与UI变换矩阵修复 * refactor: 移除 ecs-components 聚合包并修复跨包组件查找问题 * fix(physics): 修复跨包组件类引用问题 * feat: 统一运行时架构与浏览器运行支持 * feat(asset): 实现浏览器运行时资产加载系统 * fix: 修复文档、CodeQL安全问题和CI类型检查错误 * fix: 修复文档、CodeQL安全问题和CI类型检查错误 * fix: 修复文档、CodeQL安全问题、CI类型检查和测试错误 * test: 补齐核心模块测试用例,修复CI构建配置 * fix: 修复测试用例中的类型错误和断言问题 * fix: 修复 turbo build:npm 任务的依赖顺序问题 * fix: 修复 CI 构建错误并优化构建性能
This commit is contained in:
@@ -37,12 +37,14 @@ export class EntityComparer {
|
||||
*
|
||||
* ECS架构中的实体(Entity),作为组件的容器。
|
||||
* 实体本身不包含游戏逻辑,所有功能都通过组件来实现。
|
||||
* 支持父子关系,可以构建实体层次结构。
|
||||
*
|
||||
* 层级关系通过 HierarchyComponent 和 HierarchySystem 管理,
|
||||
* 而非 Entity 内置属性,符合 ECS 组合原则。
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 创建实体
|
||||
* const entity = new Entity("Player", 1);
|
||||
* const entity = scene.createEntity("Player");
|
||||
*
|
||||
* // 添加组件
|
||||
* const healthComponent = entity.addComponent(new HealthComponent(100));
|
||||
@@ -50,12 +52,9 @@ export class EntityComparer {
|
||||
* // 获取组件
|
||||
* const health = entity.getComponent(HealthComponent);
|
||||
*
|
||||
* // 添加位置组件
|
||||
* entity.addComponent(new PositionComponent(100, 200));
|
||||
*
|
||||
* // 添加子实体
|
||||
* const weapon = new Entity("Weapon", 2);
|
||||
* entity.addChild(weapon);
|
||||
* // 层级关系使用 HierarchySystem
|
||||
* const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
* hierarchySystem.setParent(childEntity, parentEntity);
|
||||
* ```
|
||||
*/
|
||||
export class Entity {
|
||||
@@ -89,16 +88,6 @@ export class Entity {
|
||||
*/
|
||||
private _isDestroyed: boolean = false;
|
||||
|
||||
/**
|
||||
* 父实体引用
|
||||
*/
|
||||
private _parent: Entity | null = null;
|
||||
|
||||
/**
|
||||
* 子实体集合
|
||||
*/
|
||||
private _children: Entity[] = [];
|
||||
|
||||
/**
|
||||
* 激活状态
|
||||
*/
|
||||
@@ -201,32 +190,6 @@ export class Entity {
|
||||
this._componentCache = components;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取父实体
|
||||
* @returns 父实体,如果没有父实体则返回null
|
||||
*/
|
||||
public get parent(): Entity | null {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子实体数组的只读副本
|
||||
*
|
||||
* @returns 子实体数组的副本
|
||||
*/
|
||||
public get children(): readonly Entity[] {
|
||||
return [...this._children];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取子实体数量
|
||||
*
|
||||
* @returns 子实体的数量
|
||||
*/
|
||||
public get childCount(): number {
|
||||
return this._children.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃状态
|
||||
*
|
||||
@@ -239,8 +202,6 @@ export class Entity {
|
||||
/**
|
||||
* 设置活跃状态
|
||||
*
|
||||
* 设置实体的活跃状态,会影响子实体的有效活跃状态。
|
||||
*
|
||||
* @param value - 新的活跃状态
|
||||
*/
|
||||
public set active(value: boolean) {
|
||||
@@ -250,19 +211,6 @@ export class Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体的有效活跃状态
|
||||
*
|
||||
* 考虑父实体的活跃状态,只有当实体本身和所有父实体都处于活跃状态时才返回true。
|
||||
*
|
||||
* @returns 有效的活跃状态
|
||||
*/
|
||||
public get activeInHierarchy(): boolean {
|
||||
if (!this._active) return false;
|
||||
if (this._parent) return this._parent.activeInHierarchy;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体标签
|
||||
*
|
||||
@@ -690,185 +638,6 @@ export class Entity {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加子实体
|
||||
*
|
||||
* @param child - 要添加的子实体
|
||||
* @returns 添加的子实体
|
||||
*/
|
||||
public addChild(child: Entity): Entity {
|
||||
if (child === this) {
|
||||
throw new Error('Entity cannot be its own child');
|
||||
}
|
||||
|
||||
if (child._parent === this) {
|
||||
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);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除子实体
|
||||
*
|
||||
* @param child - 要移除的子实体
|
||||
* @returns 是否成功移除
|
||||
*/
|
||||
public removeChild(child: Entity): boolean {
|
||||
const index = this._children.indexOf(child);
|
||||
if (index === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._children.splice(index, 1);
|
||||
child._parent = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除所有子实体
|
||||
*/
|
||||
public removeAllChildren(): void {
|
||||
const childrenToRemove = [...this._children];
|
||||
|
||||
for (const child of childrenToRemove) {
|
||||
this.removeChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称查找子实体
|
||||
*
|
||||
* @param name - 子实体名称
|
||||
* @param recursive - 是否递归查找
|
||||
* @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);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签查找子实体
|
||||
*
|
||||
* @param tag - 标签
|
||||
* @param recursive - 是否递归查找
|
||||
* @returns 找到的子实体数组
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根实体
|
||||
*
|
||||
* @returns 层次结构的根实体
|
||||
*/
|
||||
public getRoot(): Entity {
|
||||
if (!this._parent) {
|
||||
return this;
|
||||
}
|
||||
return this._parent.getRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否是指定实体的祖先
|
||||
*
|
||||
* @param entity - 要检查的实体
|
||||
* @returns 如果是祖先则返回true
|
||||
*/
|
||||
public isAncestorOf(entity: Entity): boolean {
|
||||
let current = entity._parent;
|
||||
while (current) {
|
||||
if (current === this) {
|
||||
return true;
|
||||
}
|
||||
current = current._parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否是指定实体的后代
|
||||
*
|
||||
* @param entity - 要检查的实体
|
||||
* @returns 如果是后代则返回true
|
||||
*/
|
||||
public isDescendantOf(entity: Entity): boolean {
|
||||
return entity.isAncestorOf(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取层次深度
|
||||
*
|
||||
* @returns 在层次结构中的深度(根实体为0)
|
||||
*/
|
||||
public getDepth(): number {
|
||||
let depth = 0;
|
||||
let current = this._parent;
|
||||
while (current) {
|
||||
depth++;
|
||||
current = current._parent;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历所有子实体(深度优先)
|
||||
*
|
||||
* @param callback - 对每个子实体执行的回调函数
|
||||
* @param recursive - 是否递归遍历
|
||||
*/
|
||||
public forEachChild(callback: (child: Entity, index: number) => void, recursive: boolean = false): void {
|
||||
this._children.forEach((child, index) => {
|
||||
callback(child, index);
|
||||
if (recursive) {
|
||||
child.forEachChild(callback, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 活跃状态改变时的回调
|
||||
*/
|
||||
@@ -882,8 +651,7 @@ export class Entity {
|
||||
if (this.scene && this.scene.eventSystem) {
|
||||
this.scene.eventSystem.emitSync('entity:activeChanged', {
|
||||
entity: this,
|
||||
active: this._active,
|
||||
activeInHierarchy: this.activeInHierarchy
|
||||
active: this._active
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -891,7 +659,8 @@ export class Entity {
|
||||
/**
|
||||
* 销毁实体
|
||||
*
|
||||
* 移除所有组件、子实体并标记为已销毁
|
||||
* 移除所有组件并标记为已销毁。
|
||||
* 层级关系的清理由 HierarchySystem 处理。
|
||||
*/
|
||||
public destroy(): void {
|
||||
if (this._isDestroyed) {
|
||||
@@ -905,15 +674,6 @@ export class Entity {
|
||||
this.scene.referenceTracker.unregisterEntityScene(this.id);
|
||||
}
|
||||
|
||||
const childrenToDestroy = [...this._children];
|
||||
for (const child of childrenToDestroy) {
|
||||
child.destroy();
|
||||
}
|
||||
|
||||
if (this._parent) {
|
||||
this._parent.removeChild(this);
|
||||
}
|
||||
|
||||
this.removeAllComponents();
|
||||
|
||||
if (this.scene) {
|
||||
@@ -927,43 +687,6 @@ export class Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量销毁所有子实体
|
||||
*/
|
||||
public destroyAllChildren(): void {
|
||||
if (this._children.length === 0) return;
|
||||
|
||||
const scene = this.scene;
|
||||
const toDestroy: Entity[] = [];
|
||||
|
||||
const collectChildren = (entity: Entity) => {
|
||||
for (const child of entity._children) {
|
||||
toDestroy.push(child);
|
||||
collectChildren(child);
|
||||
}
|
||||
};
|
||||
collectChildren(this);
|
||||
|
||||
for (const entity of toDestroy) {
|
||||
entity.setDestroyedState(true);
|
||||
}
|
||||
|
||||
for (const entity of toDestroy) {
|
||||
entity.removeAllComponents();
|
||||
}
|
||||
|
||||
if (scene) {
|
||||
for (const entity of toDestroy) {
|
||||
scene.entities.remove(entity);
|
||||
scene.querySystem.removeEntity(entity);
|
||||
}
|
||||
|
||||
scene.clearSystemEntityCaches();
|
||||
}
|
||||
|
||||
this._children.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较实体
|
||||
*
|
||||
@@ -993,31 +716,21 @@ export class Entity {
|
||||
id: number;
|
||||
enabled: boolean;
|
||||
active: boolean;
|
||||
activeInHierarchy: boolean;
|
||||
destroyed: boolean;
|
||||
componentCount: number;
|
||||
componentTypes: string[];
|
||||
componentMask: string;
|
||||
parentId: number | null;
|
||||
childCount: number;
|
||||
childIds: number[];
|
||||
depth: number;
|
||||
cacheBuilt: boolean;
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
name: this.name,
|
||||
id: this.id,
|
||||
enabled: this._enabled,
|
||||
active: this._active,
|
||||
activeInHierarchy: this.activeInHierarchy,
|
||||
destroyed: this._isDestroyed,
|
||||
componentCount: this.components.length,
|
||||
componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
|
||||
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
||||
parentId: this._parent?.id || null,
|
||||
childCount: this._children.length,
|
||||
childIds: this._children.map((c) => c.id),
|
||||
depth: this.getDepth(),
|
||||
componentMask: BitMask64Utils.toString(this._componentMask, 2),
|
||||
cacheBuilt: this._componentCache !== null
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user