172 lines
5.3 KiB
TypeScript
172 lines
5.3 KiB
TypeScript
|
|
/**
|
|||
|
|
* Engine render system for ECS.
|
|||
|
|
* 用于ECS的引擎渲染系统。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { EntitySystem, Matcher, Entity, ComponentType, ECSSystem, Component } from '@esengine/ecs-framework';
|
|||
|
|
import type { EngineBridge } from '../core/EngineBridge';
|
|||
|
|
import { RenderBatcher } from '../core/RenderBatcher';
|
|||
|
|
import { SpriteComponent } from '../components/SpriteComponent';
|
|||
|
|
import type { SpriteRenderData } from '../types';
|
|||
|
|
import type { ITransformComponent } from '../core/SpriteRenderHelper';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Type for transform component constructor.
|
|||
|
|
* 变换组件构造函数类型。
|
|||
|
|
*/
|
|||
|
|
export type TransformComponentType = ComponentType & (new (...args: any[]) => Component & ITransformComponent);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* ECS System for rendering sprites using the Rust engine.
|
|||
|
|
* 使用Rust引擎渲染精灵的ECS系统。
|
|||
|
|
*
|
|||
|
|
* This system extends EntitySystem and integrates with the ECS lifecycle.
|
|||
|
|
* 此系统扩展EntitySystem并与ECS生命周期集成。
|
|||
|
|
*
|
|||
|
|
* @example
|
|||
|
|
* ```typescript
|
|||
|
|
* // Create transform component | 创建变换组件
|
|||
|
|
* @ECSComponent('Transform')
|
|||
|
|
* class Transform extends Component implements ITransformComponent {
|
|||
|
|
* position = { x: 0, y: 0 };
|
|||
|
|
* rotation = 0;
|
|||
|
|
* scale = { x: 1, y: 1 };
|
|||
|
|
* }
|
|||
|
|
*
|
|||
|
|
* // Initialize bridge | 初始化桥接
|
|||
|
|
* const bridge = new EngineBridge({ canvasId: 'canvas' });
|
|||
|
|
* await bridge.initialize();
|
|||
|
|
*
|
|||
|
|
* // Add system to scene | 将系统添加到场景
|
|||
|
|
* const renderSystem = new EngineRenderSystem(bridge, Transform);
|
|||
|
|
* scene.addSystem(renderSystem);
|
|||
|
|
* ```
|
|||
|
|
*/
|
|||
|
|
@ECSSystem('EngineRender', { updateOrder: 1000 }) // Render system executes last | 渲染系统最后执行
|
|||
|
|
export class EngineRenderSystem extends EntitySystem {
|
|||
|
|
private bridge: EngineBridge;
|
|||
|
|
private batcher: RenderBatcher;
|
|||
|
|
private transformType: TransformComponentType;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Create a new engine render system.
|
|||
|
|
* 创建新的引擎渲染系统。
|
|||
|
|
*
|
|||
|
|
* @param bridge - Engine bridge instance | 引擎桥接实例
|
|||
|
|
* @param transformType - Transform component class (must implement ITransformComponent) | 变换组件类(必须实现ITransformComponent)
|
|||
|
|
*/
|
|||
|
|
constructor(bridge: EngineBridge, transformType: TransformComponentType) {
|
|||
|
|
// Match entities with both Sprite and Transform components
|
|||
|
|
// 匹配同时具有Sprite和Transform组件的实体
|
|||
|
|
super(Matcher.empty().all(SpriteComponent, transformType));
|
|||
|
|
|
|||
|
|
this.bridge = bridge;
|
|||
|
|
this.batcher = new RenderBatcher();
|
|||
|
|
this.transformType = transformType;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called when system is initialized.
|
|||
|
|
* 系统初始化时调用。
|
|||
|
|
*/
|
|||
|
|
public override initialize(): void {
|
|||
|
|
super.initialize();
|
|||
|
|
this.logger.info('EngineRenderSystem initialized | 引擎渲染系统初始化完成');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called before processing entities.
|
|||
|
|
* 处理实体之前调用。
|
|||
|
|
*/
|
|||
|
|
protected begin(): void {
|
|||
|
|
// Clear the batch | 清空批处理
|
|||
|
|
this.batcher.clear();
|
|||
|
|
|
|||
|
|
// Clear screen | 清屏
|
|||
|
|
this.bridge.clear(0, 0, 0, 1);
|
|||
|
|
|
|||
|
|
// Update input | 更新输入
|
|||
|
|
this.bridge.updateInput();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Process all matched entities.
|
|||
|
|
* 处理所有匹配的实体。
|
|||
|
|
*
|
|||
|
|
* @param entities - Entities to process | 要处理的实体
|
|||
|
|
*/
|
|||
|
|
protected process(entities: readonly Entity[]): void {
|
|||
|
|
for (const entity of entities) {
|
|||
|
|
const sprite = entity.getComponent(SpriteComponent);
|
|||
|
|
const transform = entity.getComponent(this.transformType) as unknown as ITransformComponent | null;
|
|||
|
|
|
|||
|
|
if (!sprite || !transform || !sprite.visible) {
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Calculate UV with flip | 计算带翻转的UV
|
|||
|
|
let uv = sprite.uv;
|
|||
|
|
if (sprite.flipX || sprite.flipY) {
|
|||
|
|
uv = [...sprite.uv] as [number, number, number, number];
|
|||
|
|
if (sprite.flipX) {
|
|||
|
|
[uv[0], uv[2]] = [uv[2], uv[0]];
|
|||
|
|
}
|
|||
|
|
if (sprite.flipY) {
|
|||
|
|
[uv[1], uv[3]] = [uv[3], uv[1]];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const renderData: SpriteRenderData = {
|
|||
|
|
x: transform.position.x,
|
|||
|
|
y: transform.position.y,
|
|||
|
|
rotation: transform.rotation,
|
|||
|
|
scaleX: transform.scale.x,
|
|||
|
|
scaleY: transform.scale.y,
|
|||
|
|
originX: sprite.originX,
|
|||
|
|
originY: sprite.originY,
|
|||
|
|
textureId: sprite.textureId,
|
|||
|
|
uv,
|
|||
|
|
color: sprite.color
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
this.batcher.addSprite(renderData);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Called after processing entities.
|
|||
|
|
* 处理实体之后调用。
|
|||
|
|
*/
|
|||
|
|
protected end(): void {
|
|||
|
|
// Submit batch and render | 提交批处理并渲染
|
|||
|
|
if (!this.batcher.isEmpty) {
|
|||
|
|
this.bridge.submitSprites(this.batcher.getSprites());
|
|||
|
|
}
|
|||
|
|
this.bridge.render();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get the number of sprites rendered.
|
|||
|
|
* 获取渲染的精灵数量。
|
|||
|
|
*/
|
|||
|
|
get spriteCount(): number {
|
|||
|
|
return this.batcher.count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Get engine statistics.
|
|||
|
|
* 获取引擎统计信息。
|
|||
|
|
*/
|
|||
|
|
getStats() {
|
|||
|
|
return this.bridge.getStats();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Load a texture.
|
|||
|
|
* 加载纹理。
|
|||
|
|
*/
|
|||
|
|
loadTexture(id: number, url: string): void {
|
|||
|
|
this.bridge.loadTexture(id, url);
|
|||
|
|
}
|
|||
|
|
}
|