Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/NodeComponent.ts

346 lines
11 KiB
TypeScript
Raw Normal View History

import { Component } from '@esengine/ecs-framework';
import { Node, Vec3, Color, Sprite, Label } from 'cc';
/**
* Node组件 - Cocos Creator节点引用
*/
export class NodeComponent extends Component {
/** Cocos Creator节点引用 */
public node: Node | null = null;
/** 子节点列表 */
public children: Node[] = [];
/** 节点配置信息 */
public nodeConfig: {
name: string;
layer: number;
tag: string;
userData: Record<string, any>;
transformData: {
position: Vec3;
rotation: Vec3;
scale: Vec3;
};
renderData: {
color: Color;
opacity: number;
visible: boolean;
};
parentId: number | null; // 避免循环引用使用父节点实体ID
childIds: number[]; // 避免循环引用使用子节点实体ID列表
};
/** 渲染组件引用 */
public sprite: Sprite | null = null;
public label: Label | null = null;
/** 复杂嵌套对象 */
public complexData: {
statistics: {
frameCount: number;
lastUpdateTime: number;
performance: {
avgRenderTime: number;
maxRenderTime: number;
renderHistory: number[];
};
};
cache: {
textureCache: Map<string, any>;
materialCache: Map<string, any>;
shaderCache: Map<string, any>;
};
hierarchy: {
parentId: number | null; // 避免循环引用使用ID
rootId: number | null; // 避免循环引用使用ID
depth: number;
siblingIndex: number;
};
animation: {
isPlaying: boolean;
currentFrame: number;
totalFrames: number;
loopCount: number;
animationQueue: Array<{
name: string;
duration: number;
delay: number;
easing: string;
}>;
};
interaction: {
isInteractable: boolean;
touchEnabled: boolean;
hitTestResults: Array<{
position: Vec3;
timestamp: number;
result: boolean;
}>;
boundingBox: {
min: Vec3;
max: Vec3;
center: Vec3;
};
};
};
/** 复杂的渲染状态 */
public renderState: {
layerInfo: {
currentLayer: number;
layerStack: number[];
sortingOrder: number;
cullingMask: number;
};
materials: Array<{
materialId: string;
properties: Map<string, any>;
textures: Map<string, any>;
shaderParams: Record<string, any>;
}>;
lightingData: {
ambientColor: Color;
diffuseColor: Color;
specularColor: Color;
lightDirection: Vec3;
shadowData: {
castShadows: boolean;
receiveShadows: boolean;
shadowQuality: 'low' | 'medium' | 'high';
shadowDistance: number;
};
};
};
constructor(name: string = "DefaultNode") {
super();
this.nodeConfig = {
name: name,
layer: 0,
tag: "default",
userData: {},
transformData: {
position: new Vec3(),
rotation: new Vec3(),
scale: new Vec3(1, 1, 1)
},
renderData: {
color: new Color(255, 255, 255, 255),
opacity: 1.0,
visible: true
},
parentId: null,
childIds: []
};
this.complexData = {
statistics: {
frameCount: 0,
lastUpdateTime: 0,
performance: {
avgRenderTime: 0,
maxRenderTime: 0,
renderHistory: []
}
},
cache: {
textureCache: new Map(),
materialCache: new Map(),
shaderCache: new Map()
},
hierarchy: {
parentId: null,
rootId: null,
depth: 0,
siblingIndex: 0
},
animation: {
isPlaying: false,
currentFrame: 0,
totalFrames: 60,
loopCount: 0,
animationQueue: []
},
interaction: {
isInteractable: true,
touchEnabled: true,
hitTestResults: [],
boundingBox: {
min: new Vec3(-1, -1, -1),
max: new Vec3(1, 1, 1),
center: new Vec3()
}
}
};
this.renderState = {
layerInfo: {
currentLayer: 0,
layerStack: [0],
sortingOrder: 0,
cullingMask: 0xFFFFFFFF
},
materials: [],
lightingData: {
ambientColor: new Color(128, 128, 128, 255),
diffuseColor: new Color(255, 255, 255, 255),
specularColor: new Color(255, 255, 255, 255),
lightDirection: new Vec3(0, -1, 0),
shadowData: {
castShadows: true,
receiveShadows: true,
shadowQuality: 'medium',
shadowDistance: 100
}
}
};
}
/**
*
*/
public setParent(parentEntityId: number): void {
this.nodeConfig.parentId = parentEntityId;
this.complexData.hierarchy.parentId = parentEntityId;
// 深度需要通过其他方式计算,避免引用
}
/**
*
*/
public addChild(childEntityId: number): void {
if (!this.nodeConfig.childIds.includes(childEntityId)) {
this.nodeConfig.childIds.push(childEntityId);
}
}
/**
*
*/
public updatePerformance(renderTime: number): void {
this.complexData.statistics.frameCount++;
this.complexData.statistics.lastUpdateTime = Date.now();
const perf = this.complexData.statistics.performance;
perf.renderHistory.push(renderTime);
// 保持历史记录在合理范围内
if (perf.renderHistory.length > 100) {
perf.renderHistory.shift();
}
// 计算平均值和最大值
perf.avgRenderTime = perf.renderHistory.reduce((a, b) => a + b, 0) / perf.renderHistory.length;
perf.maxRenderTime = Math.max(perf.maxRenderTime, renderTime);
}
/**
*
*/
public updateAnimation(deltaTime: number): void {
if (this.complexData.animation.isPlaying) {
this.complexData.animation.currentFrame++;
if (this.complexData.animation.currentFrame >= this.complexData.animation.totalFrames) {
this.complexData.animation.currentFrame = 0;
this.complexData.animation.loopCount++;
// 处理动画队列
if (this.complexData.animation.animationQueue.length > 0) {
const nextAnim = this.complexData.animation.animationQueue.shift();
if (nextAnim) {
this.complexData.animation.totalFrames = Math.floor(nextAnim.duration * 60); // 假设60FPS
}
}
}
}
}
/**
*
*/
public addMaterial(materialId: string, properties: Record<string, any>): void {
this.renderState.materials.push({
materialId,
properties: new Map(Object.entries(properties)),
textures: new Map(),
shaderParams: {}
});
}
/**
*
*/
public updateBoundingBox(): void {
if (this.node) {
const worldPos = this.node.getWorldPosition();
const scale = this.node.getScale();
this.complexData.interaction.boundingBox.center = new Vec3(worldPos.x, worldPos.y, worldPos.z);
this.complexData.interaction.boundingBox.min = new Vec3(
worldPos.x - scale.x * 0.5,
worldPos.y - scale.y * 0.5,
worldPos.z - scale.z * 0.5
);
this.complexData.interaction.boundingBox.max = new Vec3(
worldPos.x + scale.x * 0.5,
worldPos.y + scale.y * 0.5,
worldPos.z + scale.z * 0.5
);
}
}
/**
*
*/
public hitTest(point: Vec3): boolean {
const bbox = this.complexData.interaction.boundingBox;
const result = point.x >= bbox.min.x && point.x <= bbox.max.x &&
point.y >= bbox.min.y && point.y <= bbox.max.y &&
point.z >= bbox.min.z && point.z <= bbox.max.z;
// 记录测试结果
this.complexData.interaction.hitTestResults.push({
position: new Vec3(point.x, point.y, point.z),
timestamp: Date.now(),
result
});
// 限制历史记录大小
if (this.complexData.interaction.hitTestResults.length > 50) {
this.complexData.interaction.hitTestResults.shift();
}
return result;
}
/**
*
*/
public reset(): void {
this.node = null;
this.children = [];
this.sprite = null;
this.label = null;
// 清理ID列表不再需要处理循环引用
this.nodeConfig.parentId = null;
this.nodeConfig.childIds = [];
this.complexData.hierarchy.parentId = null;
this.complexData.hierarchy.rootId = null;
this.complexData.hierarchy.depth = 0;
this.complexData.cache.textureCache.clear();
this.complexData.cache.materialCache.clear();
this.complexData.cache.shaderCache.clear();
this.complexData.animation.isPlaying = false;
this.complexData.animation.currentFrame = 0;
this.complexData.animation.animationQueue = [];
this.complexData.interaction.hitTestResults = [];
this.renderState.materials = [];
}
}