import { Component, ECSComponent, Serializable, Serialize, Property } from '@esengine/ecs-framework'; import type { AssetReference } from '@esengine/asset-system'; /** * 精灵组件 - 管理2D图像渲染 * Sprite component - manages 2D image rendering */ @ECSComponent('Sprite') @Serializable({ version: 2, typeId: 'Sprite' }) export class SpriteComponent extends Component { /** 纹理路径或资源ID | Texture path or asset ID */ @Serialize() @Property({ type: 'asset', label: 'Texture', assetType: 'texture' }) public texture: string = ''; /** * 资产GUID(新的资产系统) * Asset GUID for new asset system */ @Serialize() public assetGuid?: string; /** * 纹理ID(运行时使用) * Texture ID for runtime rendering */ public textureId: number = 0; /** * 资产引用(运行时,不序列化) * Asset reference (runtime only, not serialized) */ private _assetReference?: AssetReference; /** * 精灵宽度(像素) * Sprite width in pixels */ @Serialize() @Property({ type: 'number', label: 'Width', min: 0, actions: [{ id: 'nativeSize', label: 'Native', tooltip: 'Set to texture native size', icon: 'Maximize2' }] }) public width: number = 64; /** * 精灵高度(像素) * Sprite height in pixels */ @Serialize() @Property({ type: 'number', label: 'Height', min: 0, actions: [{ id: 'nativeSize', label: 'Native', tooltip: 'Set to texture native size', icon: 'Maximize2' }] }) public height: number = 64; /** * UV坐标 [u0, v0, u1, v1] * UV coordinates [u0, v0, u1, v1] * 默认为完整纹理 [0, 0, 1, 1] * Default is full texture [0, 0, 1, 1] */ @Serialize() public uv: [number, number, number, number] = [0, 0, 1, 1]; /** 颜色(十六进制)| Color (hex string) */ @Serialize() @Property({ type: 'color', label: 'Color' }) public color: string = '#ffffff'; /** 透明度 (0-1) | Alpha (0-1) */ @Serialize() @Property({ type: 'number', label: 'Alpha', min: 0, max: 1, step: 0.01 }) public alpha: number = 1; /** * 原点X (0-1, 0.5为中心) * Origin point X (0-1, where 0.5 is center) */ @Serialize() @Property({ type: 'number', label: 'Origin X', min: 0, max: 1, step: 0.01 }) public originX: number = 0.5; /** * 原点Y (0-1, 0.5为中心) * Origin point Y (0-1, where 0.5 is center) */ @Serialize() @Property({ type: 'number', label: 'Origin Y', min: 0, max: 1, step: 0.01 }) public originY: number = 0.5; /** * 精灵是否可见 * Whether sprite is visible */ @Serialize() @Property({ type: 'boolean', label: 'Visible' }) public visible: boolean = true; /** 是否水平翻转 | Flip sprite horizontally */ @Serialize() @Property({ type: 'boolean', label: 'Flip X' }) public flipX: boolean = false; /** 是否垂直翻转 | Flip sprite vertically */ @Serialize() @Property({ type: 'boolean', label: 'Flip Y' }) public flipY: boolean = false; /** * 渲染层级/顺序(越高越在上面) * Render layer/order (higher = rendered on top) */ @Serialize() @Property({ type: 'integer', label: 'Sorting Order' }) public sortingOrder: number = 0; /** 锚点X (0-1) - 别名为originX | Anchor X (0-1) - alias for originX */ get anchorX(): number { return this.originX; } set anchorX(value: number) { this.originX = value; } /** 锚点Y (0-1) - 别名为originY | Anchor Y (0-1) - alias for originY */ get anchorY(): number { return this.originY; } set anchorY(value: number) { this.originY = value; } constructor(texture: string = '') { super(); this.texture = texture; } /** * 从精灵图集区域设置UV * Set UV from a sprite atlas region * * @param x - 区域X(像素)| Region X in pixels * @param y - 区域Y(像素)| Region Y in pixels * @param w - 区域宽度(像素)| Region width in pixels * @param h - 区域高度(像素)| Region height in pixels * @param atlasWidth - 图集总宽度 | Atlas total width * @param atlasHeight - 图集总高度 | Atlas total height */ setAtlasRegion( x: number, y: number, w: number, h: number, atlasWidth: number, atlasHeight: number ): void { this.uv = [ x / atlasWidth, y / atlasHeight, (x + w) / atlasWidth, (y + h) / atlasHeight ]; this.width = w; this.height = h; } /** * 设置资产引用 * Set asset reference */ setAssetReference(reference: AssetReference): void { // 释放旧引用 / Release old reference if (this._assetReference) { this._assetReference.release(); } this._assetReference = reference; if (reference) { this.assetGuid = reference.guid; } } /** * 获取资产引用 * Get asset reference */ getAssetReference(): AssetReference | undefined { return this._assetReference; } /** * 异步加载纹理 * Load texture asynchronously */ async loadTextureAsync(): Promise { if (this._assetReference) { try { const textureAsset = await this._assetReference.loadAsync(); // 如果纹理资产有 textureId 属性,使用它 // If texture asset has textureId property, use it if (textureAsset && typeof textureAsset === 'object' && 'textureId' in textureAsset) { this.textureId = (textureAsset as any).textureId; } } catch (error) { console.error('Failed to load texture:', error); } } } /** * 获取有效的纹理源 * Get effective texture source */ getTextureSource(): string { return this.assetGuid || this.texture; } /** * 组件销毁时调用 * Called when component is destroyed */ onDestroy(): void { // 释放资产引用 / Release asset reference if (this._assetReference) { this._assetReference.release(); this._assetReference = undefined; } } }