2025-12-05 23:03:31 +08:00
|
|
|
|
import type { ComponentRegistry as ComponentRegistryType, IScene } from '@esengine/ecs-framework';
|
|
|
|
|
|
import type { IRuntimeModule, IPlugin, ModuleManifest, SystemContext } from '@esengine/engine-core';
|
2025-12-07 01:00:35 +08:00
|
|
|
|
import { assetManager as globalAssetManager, type AssetManager } from '@esengine/asset-system';
|
2025-12-05 23:03:31 +08:00
|
|
|
|
import { ParticleSystemComponent } from './ParticleSystemComponent';
|
|
|
|
|
|
import { ParticleUpdateSystem } from './systems/ParticleSystem';
|
2025-12-07 01:00:35 +08:00
|
|
|
|
import { ParticleLoader, ParticleAssetType } from './loaders/ParticleLoader';
|
2025-12-08 09:38:37 +08:00
|
|
|
|
import type { IPhysics2DQuery } from './modules/Physics2DCollisionModule';
|
2025-12-05 23:03:31 +08:00
|
|
|
|
|
|
|
|
|
|
export type { SystemContext, ModuleManifest, IRuntimeModule as IRuntimeModuleLoader, IPlugin as IPluginLoader };
|
|
|
|
|
|
|
2025-12-07 01:00:35 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 引擎桥接接口(用于直接加载纹理)
|
|
|
|
|
|
* Engine bridge interface (for direct texture loading)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface IEngineBridge {
|
|
|
|
|
|
loadTexture(id: number, url: string): Promise<void>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 引擎集成接口(用于加载纹理)
|
|
|
|
|
|
* Engine integration interface (for loading textures)
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface IEngineIntegration {
|
|
|
|
|
|
loadTextureForComponent(texturePath: string): Promise<number>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-05 23:03:31 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 粒子系统上下文
|
|
|
|
|
|
* Particle system context
|
|
|
|
|
|
*/
|
|
|
|
|
|
export interface ParticleSystemContext extends SystemContext {
|
|
|
|
|
|
particleUpdateSystem?: ParticleUpdateSystem;
|
|
|
|
|
|
/** Transform 组件类型 | Transform component type */
|
|
|
|
|
|
transformType?: new (...args: any[]) => any;
|
|
|
|
|
|
/** 渲染系统(用于注册渲染数据提供者)| Render system (for registering render data provider) */
|
|
|
|
|
|
renderSystem?: {
|
|
|
|
|
|
addRenderDataProvider(provider: any): void;
|
|
|
|
|
|
removeRenderDataProvider(provider: any): void;
|
|
|
|
|
|
};
|
2025-12-07 01:00:35 +08:00
|
|
|
|
/** 引擎集成(用于加载纹理)| Engine integration (for loading textures) */
|
|
|
|
|
|
engineIntegration?: IEngineIntegration;
|
|
|
|
|
|
/** 引擎桥接(用于直接加载纹理)| Engine bridge (for direct texture loading) */
|
|
|
|
|
|
engineBridge?: IEngineBridge;
|
|
|
|
|
|
/** 资产管理器(用于注册加载器)| Asset manager (for registering loaders) */
|
|
|
|
|
|
assetManager?: AssetManager;
|
2025-12-08 09:38:37 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 2D 物理查询接口(可选)
|
|
|
|
|
|
* 2D Physics query interface (optional)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 如果提供,将自动注入到使用 Physics2DCollisionModule 的粒子系统中。
|
|
|
|
|
|
* 通常传入 Physics2DService 实例。
|
|
|
|
|
|
*
|
|
|
|
|
|
* If provided, will be auto-injected into particle systems using Physics2DCollisionModule.
|
|
|
|
|
|
* Typically pass a Physics2DService instance.
|
|
|
|
|
|
*/
|
|
|
|
|
|
physics2DQuery?: IPhysics2DQuery;
|
2025-12-05 23:03:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ParticleRuntimeModule implements IRuntimeModule {
|
|
|
|
|
|
private _updateSystem: ParticleUpdateSystem | null = null;
|
2025-12-07 01:00:35 +08:00
|
|
|
|
private _loaderRegistered = false;
|
2025-12-05 23:03:31 +08:00
|
|
|
|
|
|
|
|
|
|
registerComponents(registry: typeof ComponentRegistryType): void {
|
|
|
|
|
|
registry.register(ParticleSystemComponent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
createSystems(scene: IScene, context: SystemContext): void {
|
|
|
|
|
|
const particleContext = context as ParticleSystemContext;
|
|
|
|
|
|
|
2025-12-07 01:00:35 +08:00
|
|
|
|
// 注册粒子资产加载器到上下文的 assetManager 和全局单例
|
|
|
|
|
|
// Register particle asset loader to context assetManager AND global singleton
|
|
|
|
|
|
if (!this._loaderRegistered) {
|
|
|
|
|
|
const loader = new ParticleLoader();
|
|
|
|
|
|
|
|
|
|
|
|
// Register to context's assetManager (used by GameRuntime)
|
|
|
|
|
|
if (particleContext.assetManager) {
|
|
|
|
|
|
particleContext.assetManager.registerLoader(ParticleAssetType as any, loader);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Also register to global singleton (used by ParticleSystemComponent.loadAsset)
|
|
|
|
|
|
// 同时注册到全局单例(ParticleSystemComponent.loadAsset 使用的是全局单例)
|
|
|
|
|
|
globalAssetManager.registerLoader(ParticleAssetType as any, loader);
|
|
|
|
|
|
|
|
|
|
|
|
this._loaderRegistered = true;
|
|
|
|
|
|
console.log('[ParticleRuntimeModule] Registered ParticleLoader to both context and global assetManager');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-05 23:03:31 +08:00
|
|
|
|
this._updateSystem = new ParticleUpdateSystem();
|
|
|
|
|
|
|
|
|
|
|
|
// 设置 Transform 组件类型 | Set Transform component type
|
|
|
|
|
|
if (particleContext.transformType) {
|
|
|
|
|
|
this._updateSystem.setTransformType(particleContext.transformType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-07 01:00:35 +08:00
|
|
|
|
// 设置引擎集成(用于加载纹理)| Set engine integration (for loading textures)
|
|
|
|
|
|
if (particleContext.engineIntegration) {
|
|
|
|
|
|
this._updateSystem.setEngineIntegration(particleContext.engineIntegration);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置引擎桥接(用于加载默认纹理)| Set engine bridge (for loading default texture)
|
|
|
|
|
|
if (particleContext.engineBridge) {
|
|
|
|
|
|
this._updateSystem.setEngineBridge(particleContext.engineBridge);
|
2025-12-05 23:03:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-08 09:38:37 +08:00
|
|
|
|
// 设置 2D 物理查询(用于粒子与场景碰撞)| Set 2D physics query (for particle-scene collision)
|
|
|
|
|
|
if (particleContext.physics2DQuery) {
|
|
|
|
|
|
this._updateSystem.setPhysics2DQuery(particleContext.physics2DQuery);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-05 23:03:31 +08:00
|
|
|
|
scene.addSystem(this._updateSystem);
|
|
|
|
|
|
particleContext.particleUpdateSystem = this._updateSystem;
|
|
|
|
|
|
|
|
|
|
|
|
// 注册渲染数据提供者 | Register render data provider
|
|
|
|
|
|
if (particleContext.renderSystem) {
|
|
|
|
|
|
const renderDataProvider = this._updateSystem.getRenderDataProvider();
|
|
|
|
|
|
particleContext.renderSystem.addRenderDataProvider(renderDataProvider);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取粒子更新系统
|
|
|
|
|
|
* Get particle update system
|
|
|
|
|
|
*/
|
|
|
|
|
|
get updateSystem(): ParticleUpdateSystem | null {
|
|
|
|
|
|
return this._updateSystem;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const manifest: ModuleManifest = {
|
|
|
|
|
|
id: 'particle',
|
|
|
|
|
|
name: '@esengine/particle',
|
|
|
|
|
|
displayName: 'Particle System',
|
|
|
|
|
|
version: '1.0.0',
|
|
|
|
|
|
description: 'Particle system for 2D effects',
|
|
|
|
|
|
category: 'Rendering',
|
|
|
|
|
|
icon: 'Sparkles',
|
|
|
|
|
|
isCore: false,
|
2025-12-07 01:00:35 +08:00
|
|
|
|
defaultEnabled: true,
|
2025-12-05 23:03:31 +08:00
|
|
|
|
isEngineModule: true,
|
|
|
|
|
|
canContainContent: true,
|
|
|
|
|
|
dependencies: ['core', 'math', 'sprite'],
|
|
|
|
|
|
exports: { components: ['ParticleSystemComponent'] },
|
|
|
|
|
|
editorPackage: '@esengine/particle-editor',
|
|
|
|
|
|
requiresWasm: false
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export const ParticlePlugin: IPlugin = {
|
|
|
|
|
|
manifest,
|
|
|
|
|
|
runtimeModule: new ParticleRuntimeModule()
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export { ParticleRuntimeModule };
|