Files
esengine/packages/core/src/ECS/Entity.ts
YHH ed8f6e283b feat: 纹理路径稳定 ID 与架构改进 (#305)
* feat(asset-system): 实现路径稳定 ID 生成器

使用 FNV-1a hash 算法为纹理生成稳定的运行时 ID:
- 新增 _pathIdCache 静态缓存,跨 Play/Stop 循环保持稳定
- 新增 getStableIdForPath() 方法,相同路径永远返回相同 ID
- 修改 loadTextureForComponent/loadTextureByGuid 使用稳定 ID
- clearTextureMappings() 不再清除 _pathIdCache

这解决了 Play/Stop 后纹理 ID 失效的根本问题。

* fix(runtime-core): 移除 Play/Stop 循环中的 clearTextureMappings 调用

使用路径稳定 ID 后,不再需要在快照保存/恢复时清除纹理缓存:
- saveSceneSnapshot() 移除 clearTextureMappings() 调用
- restoreSceneSnapshot() 移除 clearTextureMappings() 调用
- 组件保存的 textureId 在 Play/Stop 后仍然有效

* fix(editor-core): 修复场景切换时的资源泄漏

在 openScene() 加载新场景前先卸载旧场景资源:
- 调用 sceneResourceManager.unloadSceneResources() 释放旧资源
- 使用引用计数机制,仅卸载不再被引用的资源
- 路径稳定 ID 缓存不受影响,保持 ID 稳定性

* fix(runtime-core): 修复 PluginManager 组件注册类型错误

将 ComponentRegistry 类改为 GlobalComponentRegistry 实例:
- registerComponents() 期望 IComponentRegistry 接口实例
- GlobalComponentRegistry 是 ComponentRegistry 的全局实例

* refactor(core): 提取 IComponentRegistry 接口

将组件注册表抽象为接口,支持场景级组件注册:
- 新增 IComponentRegistry 接口定义
- Scene 持有独立的 componentRegistry 实例
- 支持从 GlobalComponentRegistry 克隆
- 各系统支持传入自定义注册表

* refactor(engine-core): 改进插件服务注册机制

- 更新 IComponentRegistry 类型引用
- 优化 PluginServiceRegistry 服务管理

* refactor(modules): 适配新的组件注册接口

更新各模块 RuntimeModule 使用 IComponentRegistry 接口:
- audio, behavior-tree, camera
- sprite, tilemap, world-streaming

* fix(physics-rapier2d): 修复物理插件组件注册

- PhysicsEditorPlugin 添加 runtimeModule 引用
- 适配 IComponentRegistry 接口
- 修复物理组件在场景加载时未注册的问题

* feat(editor-core): 添加 UserCodeService 就绪信号机制

- 新增 waitForReady()/signalReady() API
- 支持等待用户脚本编译完成
- 解决场景加载时组件未注册的时序问题

* fix(editor-app): 在编译完成后调用 signalReady()

确保用户脚本编译完成后发出就绪信号:
- 编译成功后调用 userCodeService.signalReady()
- 编译失败也要发出信号,避免阻塞场景加载

* feat(editor-core): 改进编辑器核心服务

- EntityStoreService 添加调试日志
- AssetRegistryService 优化资产注册
- PluginManager 改进插件管理
- IFileAPI 添加 getFileMtime 接口

* feat(engine): 改进 Rust 纹理管理器

- 支持任意 ID 的纹理加载(非递增)
- 添加纹理状态追踪 API
- 优化纹理缓存清理机制
- 更新 TypeScript 绑定

* feat(ui): 添加场景切换和文本闪烁组件

新增组件:
- SceneLoadTriggerComponent: 场景切换触发器
- TextBlinkComponent: 文本闪烁效果

新增系统:
- SceneLoadTriggerSystem: 处理场景切换逻辑
- TextBlinkSystem: 处理文本闪烁动画

其他改进:
- UIRuntimeModule 适配新组件注册接口
- UI 渲染系统优化

* feat(editor-app): 添加外部文件修改检测

- 新增 ExternalModificationDialog 组件
- TauriFileAPI 支持 getFileMtime
- 场景文件被外部修改时提示用户

* feat(editor-app): 添加渲染调试面板

- 新增 RenderDebugService 和调试面板 UI
- App/ContentBrowser 添加调试日志
- TitleBar/Viewport 优化
- DialogManager 改进

* refactor(editor-app): 编辑器服务和组件优化

- EngineService 改进引擎集成
- EditorEngineSync 同步优化
- AssetFileInspector 改进
- VectorFieldEditors 优化
- InstantiatePrefabCommand 改进

* feat(i18n): 更新国际化翻译

- 添加新功能相关翻译
- 更新中文、英文、西班牙文

* feat(tauri): 添加文件修改时间查询命令

- 新增 get_file_mtime 命令
- 支持检测文件外部修改

* refactor(particle): 粒子系统改进

- 适配新的组件注册接口
- ParticleSystem 优化
- 添加单元测试

* refactor(platform): 平台适配层优化

- BrowserRuntime 改进
- 新增 RuntimeSceneManager 服务
- 导出优化

* refactor(asset-system-editor): 资产元数据改进

- AssetMetaFile 优化
- 导出调整

* fix(asset-system): 移除未使用的 TextureLoader 导入

* fix(tests): 更新测试以使用 GlobalComponentRegistry 实例

修复多个测试文件以适配 ComponentRegistry 从静态类变为实例类的变更:
- ComponentStorage.test.ts: 使用 GlobalComponentRegistry.reset()
- EntitySerializer.test.ts: 使用 GlobalComponentRegistry 实例
- IncrementalSerialization.test.ts: 使用 GlobalComponentRegistry 实例
- SceneSerializer.test.ts: 使用 GlobalComponentRegistry 实例
- ComponentRegistry.extended.test.ts: 使用 GlobalComponentRegistry,同时注册到 scene.componentRegistry
- SystemTypes.test.ts: 在 Scene 创建前注册组件
- QuerySystem.test.ts: mockScene 添加 componentRegistry
2025-12-16 12:46:14 +08:00

911 lines
26 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Component } from './Component';
import { ComponentType, GlobalComponentRegistry } from './Core/ComponentStorage';
import { EEntityLifecyclePolicy } from './Core/EntityLifecyclePolicy';
import { BitMask64Utils, BitMask64Data } from './Utils/BigIntCompatibility';
import { createLogger } from '../Utils/Logger';
import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators';
import { generateGUID } from '../Utils/GUID';
import type { IScene } from './IScene';
import { EntityHandle, NULL_HANDLE } from './Core/EntityHandle';
/**
* 组件活跃状态变化接口
*/
interface IActiveChangeable {
onActiveChanged(): void;
}
/**
* 实体比较器
*
* 用于比较两个实体的优先级首先按更新顺序比较然后按ID比较。
*/
export class EntityComparer {
/**
* 比较两个实体
*
* @param self - 第一个实体
* @param other - 第二个实体
* @returns 比较结果负数表示self优先级更高正数表示other优先级更高0表示相等
*/
public compare(self: Entity, other: Entity): number {
let compare = self.updateOrder - other.updateOrder;
if (compare == 0) compare = self.id - other.id;
return compare;
}
}
/**
* 游戏实体类
*
* ECS架构中的实体Entity作为组件的容器。
* 实体本身不包含游戏逻辑,所有功能都通过组件来实现。
*
* 层级关系通过 HierarchyComponent 和 HierarchySystem 管理,
* 而非 Entity 内置属性,符合 ECS 组合原则。
*
* @example
* ```typescript
* // 创建实体
* const entity = scene.createEntity("Player");
*
* // 添加组件
* const healthComponent = entity.addComponent(new HealthComponent(100));
*
* // 获取组件
* const health = entity.getComponent(HealthComponent);
*
* // 层级关系使用 HierarchySystem
* const hierarchySystem = scene.getSystem(HierarchySystem);
* hierarchySystem.setParent(childEntity, parentEntity);
* ```
*/
export class Entity {
/**
* Entity专用日志器
*/
private static _logger = createLogger('Entity');
/**
* 实体比较器实例
*/
public static entityComparer: EntityComparer = new EntityComparer();
/**
* 实体名称
*/
public name: string;
/**
* 实体唯一标识符(运行时 ID
*
* Runtime identifier for fast lookups.
*/
public readonly id: number;
/**
* 持久化唯一标识符GUID
*
* 用于序列化/反序列化时保持实体引用一致性。
* 在场景保存和加载时保持不变。
*
* Persistent identifier for serialization.
* Remains stable across save/load cycles.
*/
public readonly persistentId: string;
/**
* 轻量级实体句柄
*
* 数值类型的实体标识符,包含索引和代数信息。
* 用于高性能场景下替代对象引用,支持 Archetype 存储等优化。
*
* Lightweight entity handle.
* Numeric identifier containing index and generation.
* Used for high-performance scenarios instead of object references,
* supports Archetype storage optimizations.
*/
private _handle: EntityHandle = NULL_HANDLE;
/**
* 所属场景引用
*/
public scene: IScene | null = null;
/**
* 销毁状态标志
*/
private _isDestroyed: boolean = false;
/**
* 激活状态
*/
private _active: boolean = true;
/**
* 实体标签
*/
private _tag: number = 0;
/**
* 启用状态
*/
private _enabled: boolean = true;
/**
* 更新顺序
*/
private _updateOrder: number = 0;
/**
* 组件位掩码(用于快速 hasComponent 检查)
*/
private _componentMask: BitMask64Data = BitMask64Utils.clone(BitMask64Utils.ZERO);
/**
* 懒加载的组件数组缓存
*/
private _componentCache: Component[] | null = null;
/**
* 生命周期策略
*
* Lifecycle policy for scene transitions.
*/
private _lifecyclePolicy: EEntityLifecyclePolicy = EEntityLifecyclePolicy.SceneLocal;
/**
* 构造函数
*
* @param name - 实体名称
* @param id - 实体唯一标识符(运行时 ID
* @param persistentId - 持久化标识符(可选,用于反序列化时恢复)
*/
constructor(name: string, id: number, persistentId?: string) {
this.name = name;
this.id = id;
this.persistentId = persistentId ?? generateGUID();
}
/**
* 获取生命周期策略
*
* Get lifecycle policy.
*/
public get lifecyclePolicy(): EEntityLifecyclePolicy {
return this._lifecyclePolicy;
}
/**
* 检查实体是否为持久化实体
*
* Check if entity is persistent (survives scene transitions).
*/
public get isPersistent(): boolean {
return this._lifecyclePolicy === EEntityLifecyclePolicy.Persistent;
}
/**
* 获取实体句柄
*
* 返回轻量级数值句柄,用于高性能场景。
* 如果实体尚未分配句柄,返回 NULL_HANDLE。
*
* Get entity handle.
* Returns lightweight numeric handle for high-performance scenarios.
* Returns NULL_HANDLE if entity has no handle assigned.
*/
public get handle(): EntityHandle {
return this._handle;
}
/**
* 设置实体句柄(内部使用)
*
* 此方法供 Scene 在创建实体时调用。
*
* Set entity handle (internal use).
* Called by Scene when creating entities.
*
* @internal
*/
public setHandle(handle: EntityHandle): void {
this._handle = handle;
}
/**
* 设置实体为持久化(跨场景保留)
*
* 标记后的实体在场景切换时不会被销毁,会自动迁移到新场景。
*
* Mark entity as persistent (survives scene transitions).
* Persistent entities are automatically migrated to the new scene.
*
* @returns this支持链式调用 | Returns this for chaining
*
* @example
* ```typescript
* const player = scene.createEntity('Player')
* .setPersistent()
* .addComponent(new PlayerComponent());
* ```
*/
public setPersistent(): this {
this._lifecyclePolicy = EEntityLifecyclePolicy.Persistent;
return this;
}
/**
* 设置实体为场景本地(随场景销毁)
*
* 将实体恢复为默认行为。
*
* Mark entity as scene-local (destroyed with scene).
* Restores default behavior.
*
* @returns this支持链式调用 | Returns this for chaining
*/
public setSceneLocal(): this {
this._lifecyclePolicy = EEntityLifecyclePolicy.SceneLocal;
return this;
}
/**
* 获取销毁状态
* @returns 如果实体已被销毁则返回true
*/
public get isDestroyed(): boolean {
return this._isDestroyed;
}
/**
* 设置销毁状态(内部使用)
*
* 此方法供Scene和批量操作使用以提高性能。
* 不应在普通业务逻辑中调用应使用destroy()方法。
*
* @internal
*/
public setDestroyedState(destroyed: boolean): void {
this._isDestroyed = destroyed;
}
/**
* 获取组件数组(懒加载)
* @returns 只读的组件数组
*/
public get components(): readonly Component[] {
if (this._componentCache === null) {
this._rebuildComponentCache();
}
return this._componentCache!;
}
/**
* 从存储重建组件缓存
*/
private _rebuildComponentCache(): void {
const components: Component[] = [];
if (!this.scene?.componentStorageManager) {
this._componentCache = components;
return;
}
const mask = this._componentMask;
const registry = this.scene.componentRegistry;
const maxBitIndex = registry.getRegisteredCount();
for (let bitIndex = 0; bitIndex < maxBitIndex; bitIndex++) {
if (BitMask64Utils.getBit(mask, bitIndex)) {
const componentType = registry.getTypeByBitIndex(bitIndex);
if (componentType) {
const component = this.scene.componentStorageManager.getComponent(this.id, componentType);
if (component) {
components.push(component);
}
}
}
}
this._componentCache = components;
}
/**
* 获取活跃状态
*
* @returns 如果实体处于活跃状态则返回true
*/
public get active(): boolean {
return this._active;
}
/**
* 设置活跃状态
*
* @param value - 新的活跃状态
*/
public set active(value: boolean) {
if (this._active !== value) {
this._active = value;
this.onActiveChanged();
}
}
/**
* 获取实体标签
*
* @returns 实体的数字标签
*/
public get tag(): number {
return this._tag;
}
/**
* 设置实体标签
*
* @param value - 新的标签值
*/
public set tag(value: number) {
this._tag = value;
}
/**
* 获取启用状态
*
* @returns 如果实体已启用则返回true
*/
public get enabled(): boolean {
return this._enabled;
}
/**
* 设置启用状态
*
* @param value - 新的启用状态
*/
public set enabled(value: boolean) {
this._enabled = value;
}
/**
* 获取更新顺序
*
* @returns 实体的更新顺序值
*/
public get updateOrder(): number {
return this._updateOrder;
}
/**
* 设置更新顺序
*
* @param value - 新的更新顺序值
*/
public set updateOrder(value: number) {
this._updateOrder = value;
}
/**
* 获取组件位掩码
*
* @returns 实体的组件位掩码
*/
public get componentMask(): BitMask64Data {
return this._componentMask;
}
/**
* 创建并添加组件
*
* @param componentType - 组件类型构造函数
* @param args - 组件构造函数参数
* @returns 创建的组件实例
*
* @example
* ```typescript
* const position = entity.createComponent(Position, 100, 200);
* const health = entity.createComponent(Health, 100);
* ```
*/
public createComponent<T extends Component>(
componentType: ComponentType<T>,
...args: ConstructorParameters<ComponentType<T>>
): T {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const component = new componentType(...args);
return this.addComponent(component);
}
/**
* 内部添加组件方法(不进行重复检查,用于初始化)
*
* @param component - 要添加的组件实例
* @returns 添加的组件实例
*/
private addComponentInternal<T extends Component>(component: T): T {
const componentType = component.constructor as ComponentType<T>;
// 更新位掩码(组件已通过 @ECSComponent 装饰器自动注册)
// Update bitmask (component already registered via @ECSComponent decorator)
const registry = this.scene?.componentRegistry ?? GlobalComponentRegistry;
const componentMask = registry.getBitMask(componentType);
BitMask64Utils.orInPlace(this._componentMask, componentMask);
// 使缓存失效
this._componentCache = null;
return component;
}
/**
* 通知Scene中的QuerySystem实体组件发生变动
*
* Notify the QuerySystem in Scene that entity components have changed
*
* @param changedComponentType 变化的组件类型(可选,用于优化通知) | Changed component type (optional, for optimized notification)
*/
private notifyQuerySystems(changedComponentType?: ComponentType): void {
if (this.scene && this.scene.querySystem) {
this.scene.querySystem.updateEntity(this);
this.scene.clearSystemEntityCaches();
// 事件驱动:立即通知关心该组件的系统 | Event-driven: notify systems that care about this component
if (this.scene.notifyEntityComponentChanged) {
this.scene.notifyEntityComponentChanged(this, changedComponentType);
}
}
}
/**
* 添加组件到实体
*
* @param component - 要添加的组件实例
* @returns 添加的组件实例
* @throws {Error} 如果实体已存在该类型的组件
*
* @example
* ```typescript
* const position = new Position(100, 200);
* entity.addComponent(position);
* ```
*/
public addComponent<T extends Component>(component: T): T {
const componentType = component.constructor as ComponentType<T>;
if (!this.scene) {
throw new Error(
'Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()'
);
}
if (!this.scene.componentStorageManager) {
throw new Error('Scene does not have componentStorageManager');
}
if (this.hasComponent(componentType)) {
throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`);
}
this.addComponentInternal(component);
this.scene.componentStorageManager.addComponent(this.id, component);
component.entityId = this.id;
if (this.scene.referenceTracker) {
this.scene.referenceTracker.registerEntityScene(this.id, this.scene);
}
// 编辑器模式下延迟执行 onAddedToEntity | Defer onAddedToEntity in editor mode
if (this.scene.isEditorMode) {
this.scene.queueDeferredComponentCallback(() => {
component.onAddedToEntity();
});
} else {
component.onAddedToEntity();
}
if (this.scene && this.scene.eventSystem) {
this.scene.eventSystem.emitSync('component:added', {
timestamp: Date.now(),
source: 'Entity',
entityId: this.id,
entityName: this.name,
entityTag: this.tag?.toString(),
componentType: getComponentTypeName(componentType),
component: component
});
}
this.notifyQuerySystems(componentType);
return component;
}
/**
* 获取指定类型的组件
*
* @param type - 组件类型构造函数
* @returns 组件实例如果不存在则返回null
*
* @example
* ```typescript
* const position = entity.getComponent(Position);
* if (position) {
* position.x += 10;
* position.y += 20;
* }
* ```
*/
public getComponent<T extends Component>(type: ComponentType<T>): T | null {
// 快速检查:位掩码
if (!this.hasComponent(type)) {
return null;
}
// 从Scene存储获取
if (!this.scene?.componentStorageManager) {
return null;
}
const component = this.scene.componentStorageManager.getComponent(this.id, type);
return component as T | null;
}
/**
* 检查实体是否拥有指定类型的组件
*
* @param type - 组件类型构造函数
* @returns 如果实体拥有该组件返回true否则返回false
*
* @example
* ```typescript
* if (entity.hasComponent(Position)) {
* const position = entity.getComponent(Position)!;
* position.x += 10;
* }
* ```
*/
public hasComponent<T extends Component>(type: ComponentType<T>): boolean {
const registry = this.scene?.componentRegistry ?? GlobalComponentRegistry;
if (!registry.isRegistered(type)) {
return false;
}
const mask = registry.getBitMask(type);
return BitMask64Utils.hasAny(this._componentMask, mask);
}
/**
* 获取或创建指定类型的组件
*
* 如果组件已存在则返回现有组件,否则创建新组件并添加到实体
*
* @param type - 组件类型构造函数
* @param args - 组件构造函数参数(仅在创建新组件时使用)
* @returns 组件实例
*
* @example
* ```typescript
* // 确保实体拥有Position组件
* const position = entity.getOrCreateComponent(Position, 0, 0);
* position.x = 100;
* ```
*/
public getOrCreateComponent<T extends Component>(
type: ComponentType<T>,
...args: ConstructorParameters<ComponentType<T>>
): T {
let component = this.getComponent(type);
if (!component) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
component = this.createComponent(type, ...args);
}
return component;
}
/**
* 标记组件为已修改
*
* 便捷方法,自动从场景获取当前 epoch 并标记组件。
* 用于帧级变更检测系统。
*
* Mark component(s) as modified.
* Convenience method that auto-gets epoch from scene and marks components.
* Used for frame-level change detection system.
*
* @param components 要标记的组件 | Components to mark
*
* @example
* ```typescript
* const pos = entity.getComponent(Position)!;
* pos.x = 100;
* entity.markDirty(pos);
*
* // 或者标记多个组件
* entity.markDirty(pos, vel);
* ```
*/
public markDirty(...components: Component[]): void {
if (!this.scene) {
return;
}
const epoch = this.scene.epochManager.current;
for (const component of components) {
component.markDirty(epoch);
}
}
/**
* 移除指定的组件
*
* @param component - 要移除的组件实例
*/
public removeComponent(component: Component): void {
const componentType = component.constructor as ComponentType;
const registry = this.scene?.componentRegistry ?? GlobalComponentRegistry;
if (!registry.isRegistered(componentType)) {
return;
}
const bitIndex = registry.getBitIndex(componentType);
// 更新位掩码
BitMask64Utils.clearBit(this._componentMask, bitIndex);
// 使缓存失效
this._componentCache = null;
// 从Scene存储移除
if (this.scene?.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
if (this.scene?.referenceTracker) {
this.scene.referenceTracker.clearComponentReferences(component);
}
if (component.onRemovedFromEntity) {
component.onRemovedFromEntity();
}
component.entityId = null;
if (this.scene && this.scene.eventSystem) {
this.scene.eventSystem.emitSync('component:removed', {
timestamp: Date.now(),
source: 'Entity',
entityId: this.id,
entityName: this.name,
entityTag: this.tag?.toString(),
componentType: getComponentTypeName(componentType),
component: component
});
}
this.notifyQuerySystems(componentType);
}
/**
* 移除指定类型的组件
*
* @param type - 组件类型
* @returns 被移除的组件实例或null
*/
public removeComponentByType<T extends Component>(type: ComponentType<T>): T | null {
const component = this.getComponent(type);
if (component) {
this.removeComponent(component);
return component;
}
return null;
}
/**
* 移除所有组件
*/
public removeAllComponents(): void {
const componentsToRemove = [...this.components];
// 清除位掩码
BitMask64Utils.clear(this._componentMask);
// 使缓存失效
this._componentCache = null;
for (const component of componentsToRemove) {
const componentType = component.constructor as ComponentType;
if (this.scene?.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
component.onRemovedFromEntity();
}
this.notifyQuerySystems();
}
/**
* 批量添加组件
*
* @param components - 要添加的组件数组
* @returns 添加的组件数组
*/
public addComponents<T extends Component>(components: T[]): T[] {
const addedComponents: T[] = [];
for (const component of components) {
try {
addedComponents.push(this.addComponent(component));
} catch (error) {
Entity._logger.warn(`添加组件失败 ${getComponentInstanceTypeName(component)}:`, error);
}
}
return addedComponents;
}
/**
* 批量移除组件类型
*
* @param componentTypes - 要移除的组件类型数组
* @returns 被移除的组件数组
*/
public removeComponentsByTypes<T extends Component>(componentTypes: ComponentType<T>[]): (T | null)[] {
const removedComponents: (T | null)[] = [];
for (const componentType of componentTypes) {
removedComponents.push(this.removeComponentByType(componentType));
}
return removedComponents;
}
/**
* 获取所有指定类型的组件
*
* @param type - 组件类型
* @returns 组件实例数组
*/
public getComponents<T extends Component>(type: ComponentType<T>): T[] {
const result: T[] = [];
for (const component of this.components) {
if (component instanceof type) {
result.push(component as T);
}
}
return result;
}
/**
* 获取指定基类的组件(支持继承查找)
*
* 与 getComponent() 不同,此方法使用 instanceof 检查,支持子类查找。
* 性能比位掩码查询稍慢,但支持继承层次结构。
*
* @param baseType - 组件基类类型
* @returns 第一个匹配的组件实例,如果不存在则返回 null
*
* @example
* ```typescript
* // 查找 CompositeNodeComponent 或其子类
* const composite = entity.getComponentByType(CompositeNodeComponent);
* if (composite) {
* // composite 可能是 SequenceNode, SelectorNode 等
* }
* ```
*/
public getComponentByType<T extends Component>(baseType: ComponentType<T>): T | null {
for (const component of this.components) {
if (component instanceof baseType) {
return component as T;
}
}
return null;
}
/**
* 活跃状态改变时的回调
*/
private onActiveChanged(): void {
for (const component of this.components) {
if ('onActiveChanged' in component && typeof component.onActiveChanged === 'function') {
(component as IActiveChangeable).onActiveChanged();
}
}
if (this.scene && this.scene.eventSystem) {
this.scene.eventSystem.emitSync('entity:activeChanged', {
entity: this,
active: this._active
});
}
}
/**
* 销毁实体
*
* 移除所有组件并标记为已销毁。
* 层级关系的清理由 HierarchySystem 处理。
*/
public destroy(): void {
if (this._isDestroyed) {
return;
}
this._isDestroyed = true;
if (this.scene && this.scene.referenceTracker) {
this.scene.referenceTracker.clearReferencesTo(this.id);
this.scene.referenceTracker.unregisterEntityScene(this.id);
}
this.removeAllComponents();
if (this.scene) {
if (this.scene.querySystem) {
this.scene.querySystem.removeEntity(this);
}
if (this.scene.entities) {
this.scene.entities.remove(this);
}
}
}
/**
* 比较实体
*
* @param other - 另一个实体
* @returns 比较结果
*/
public compareTo(other: Entity): number {
return EntityComparer.prototype.compare(this, other);
}
/**
* 获取实体的字符串表示
*
* @returns 实体的字符串描述
*/
public toString(): string {
return `Entity[${this.name}:${this.id}:${this.persistentId.slice(0, 8)}]`;
}
/**
* 获取实体的调试信息(包含组件缓存信息)
*
* @returns 包含实体详细信息的对象
*/
public getDebugInfo(): {
name: string;
id: number;
persistentId: string;
enabled: boolean;
active: boolean;
destroyed: boolean;
componentCount: number;
componentTypes: string[];
componentMask: string;
cacheBuilt: boolean;
} {
return {
name: this.name,
id: this.id,
persistentId: this.persistentId,
enabled: this._enabled,
active: this._active,
destroyed: this._isDestroyed,
componentCount: this.components.length,
componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
componentMask: BitMask64Utils.toString(this._componentMask, 2),
cacheBuilt: this._componentCache !== null
};
}
}