Feature/editor optimization (#251)
* refactor: 编辑器/运行时架构拆分与构建系统升级 * feat(core): 层级系统重构与UI变换矩阵修复 * refactor: 移除 ecs-components 聚合包并修复跨包组件查找问题 * fix(physics): 修复跨包组件类引用问题 * feat: 统一运行时架构与浏览器运行支持 * feat(asset): 实现浏览器运行时资产加载系统 * fix: 修复文档、CodeQL安全问题和CI类型检查错误 * fix: 修复文档、CodeQL安全问题和CI类型检查错误 * fix: 修复文档、CodeQL安全问题、CI类型检查和测试错误 * test: 补齐核心模块测试用例,修复CI构建配置 * fix: 修复测试用例中的类型错误和断言问题 * fix: 修复 turbo build:npm 任务的依赖顺序问题 * fix: 修复 CI 构建错误并优化构建性能
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Core, Entity } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { TransformComponent, SpriteComponent, SpriteAnimatorComponent } from '@esengine/ecs-components';
|
||||
import { TransformComponent } from '@esengine/engine-core';
|
||||
import { SpriteComponent, SpriteAnimatorComponent } from '@esengine/sprite';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
/**
|
||||
@@ -28,13 +29,15 @@ export class CreateAnimatedSpriteEntityCommand extends BaseCommand {
|
||||
this.entity = scene.createEntity(this.entityName);
|
||||
this.entityId = this.entity.id;
|
||||
|
||||
// 添加Transform、Sprite和Animator组件
|
||||
// 添加 Transform、Sprite、Animator 和 Hierarchy 组件
|
||||
this.entity.addComponent(new TransformComponent());
|
||||
this.entity.addComponent(new SpriteComponent());
|
||||
this.entity.addComponent(new SpriteAnimatorComponent());
|
||||
this.entity.addComponent(new HierarchyComponent());
|
||||
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(this.entity);
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
hierarchySystem?.setParent(this.entity, this.parentEntity);
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(this.entity, this.parentEntity);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Core, Entity } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { TransformComponent, CameraComponent } from '@esengine/ecs-components';
|
||||
import { TransformComponent } from '@esengine/engine-core';
|
||||
import { CameraComponent } from '@esengine/camera';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
/**
|
||||
@@ -28,12 +29,14 @@ export class CreateCameraEntityCommand extends BaseCommand {
|
||||
this.entity = scene.createEntity(this.entityName);
|
||||
this.entityId = this.entity.id;
|
||||
|
||||
// 添加Transform和Camera组件
|
||||
// 添加 Transform、Camera 和 Hierarchy 组件
|
||||
this.entity.addComponent(new TransformComponent());
|
||||
this.entity.addComponent(new CameraComponent());
|
||||
this.entity.addComponent(new HierarchyComponent());
|
||||
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(this.entity);
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
hierarchySystem?.setParent(this.entity, this.parentEntity);
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(this.entity, this.parentEntity);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Core, Entity } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { TransformComponent } from '@esengine/ecs-components';
|
||||
import { TransformComponent } from '@esengine/engine-core';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
/**
|
||||
@@ -28,11 +28,15 @@ export class CreateEntityCommand extends BaseCommand {
|
||||
this.entity = scene.createEntity(this.entityName);
|
||||
this.entityId = this.entity.id;
|
||||
|
||||
// 自动添加Transform组件
|
||||
// 自动添加 Transform 组件
|
||||
this.entity.addComponent(new TransformComponent());
|
||||
|
||||
// 添加 HierarchyComponent 支持层级结构
|
||||
this.entity.addComponent(new HierarchyComponent());
|
||||
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(this.entity);
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
hierarchySystem?.setParent(this.entity, this.parentEntity);
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(this.entity, this.parentEntity);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Core, Entity } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { TransformComponent, SpriteComponent } from '@esengine/ecs-components';
|
||||
import { TransformComponent } from '@esengine/engine-core';
|
||||
import { SpriteComponent } from '@esengine/sprite';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
/**
|
||||
@@ -28,12 +29,14 @@ export class CreateSpriteEntityCommand extends BaseCommand {
|
||||
this.entity = scene.createEntity(this.entityName);
|
||||
this.entityId = this.entity.id;
|
||||
|
||||
// 添加Transform和Sprite组件
|
||||
// 添加 Transform、Sprite 和 Hierarchy 组件
|
||||
this.entity.addComponent(new TransformComponent());
|
||||
this.entity.addComponent(new SpriteComponent());
|
||||
this.entity.addComponent(new HierarchyComponent());
|
||||
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(this.entity);
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
hierarchySystem?.setParent(this.entity, this.parentEntity);
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(this.entity, this.parentEntity);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Core, Entity } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { TransformComponent } from '@esengine/ecs-components';
|
||||
import { TransformComponent } from '@esengine/engine-core';
|
||||
import { TilemapComponent } from '@esengine/tilemap';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
@@ -48,8 +48,9 @@ export class CreateTilemapEntityCommand extends BaseCommand {
|
||||
this.entity = scene.createEntity(this.entityName);
|
||||
this.entityId = this.entity.id;
|
||||
|
||||
// 添加Transform组件
|
||||
// 添加 Transform 和 Hierarchy 组件
|
||||
this.entity.addComponent(new TransformComponent());
|
||||
this.entity.addComponent(new HierarchyComponent());
|
||||
|
||||
// 创建并配置Tilemap组件
|
||||
const tilemapComponent = new TilemapComponent();
|
||||
@@ -79,7 +80,8 @@ export class CreateTilemapEntityCommand extends BaseCommand {
|
||||
this.entity.addComponent(tilemapComponent);
|
||||
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(this.entity);
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
hierarchySystem?.setParent(this.entity, this.parentEntity);
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(this.entity, this.parentEntity);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Core, Entity, Component } from '@esengine/ecs-framework';
|
||||
import { Core, Entity, Component, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
@@ -8,9 +8,9 @@ import { BaseCommand } from '../BaseCommand';
|
||||
export class DeleteEntityCommand extends BaseCommand {
|
||||
private entityId: number;
|
||||
private entityName: string;
|
||||
private parentEntity: Entity | null;
|
||||
private parentEntityId: number | null;
|
||||
private components: Component[] = [];
|
||||
private childEntities: Entity[] = [];
|
||||
private childEntityIds: number[] = [];
|
||||
|
||||
constructor(
|
||||
private entityStore: EntityStoreService,
|
||||
@@ -20,18 +20,28 @@ export class DeleteEntityCommand extends BaseCommand {
|
||||
super();
|
||||
this.entityId = entity.id;
|
||||
this.entityName = entity.name;
|
||||
this.parentEntity = entity.parent;
|
||||
|
||||
// 通过 HierarchyComponent 获取父实体 ID
|
||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||
this.parentEntityId = hierarchy?.parentId ?? null;
|
||||
|
||||
// 保存组件状态用于撤销
|
||||
this.components = [...entity.components];
|
||||
// 保存子实体
|
||||
this.childEntities = [...entity.children];
|
||||
|
||||
// 保存子实体 ID
|
||||
this.childEntityIds = hierarchy?.childIds ? [...hierarchy.childIds] : [];
|
||||
}
|
||||
|
||||
execute(): void {
|
||||
const scene = Core.scene;
|
||||
if (!scene) return;
|
||||
|
||||
// 先移除子实体
|
||||
for (const child of this.childEntities) {
|
||||
this.entityStore.removeEntity(child);
|
||||
for (const childId of this.childEntityIds) {
|
||||
const child = scene.findEntityById(childId);
|
||||
if (child) {
|
||||
this.entityStore.removeEntity(child);
|
||||
}
|
||||
}
|
||||
|
||||
this.entityStore.removeEntity(this.entity);
|
||||
@@ -46,12 +56,17 @@ export class DeleteEntityCommand extends BaseCommand {
|
||||
throw new Error('场景未初始化');
|
||||
}
|
||||
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
|
||||
// 重新创建实体
|
||||
const newEntity = scene.createEntity(this.entityName);
|
||||
|
||||
// 设置父实体
|
||||
if (this.parentEntity) {
|
||||
this.parentEntity.addChild(newEntity);
|
||||
if (this.parentEntityId !== null && hierarchySystem) {
|
||||
const parentEntity = scene.findEntityById(this.parentEntityId);
|
||||
if (parentEntity) {
|
||||
hierarchySystem.setParent(newEntity, parentEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复组件
|
||||
@@ -71,12 +86,20 @@ export class DeleteEntityCommand extends BaseCommand {
|
||||
}
|
||||
|
||||
// 恢复子实体
|
||||
for (const child of this.childEntities) {
|
||||
newEntity.addChild(child);
|
||||
this.entityStore.addEntity(child, newEntity);
|
||||
for (const childId of this.childEntityIds) {
|
||||
const child = scene.findEntityById(childId);
|
||||
if (child && hierarchySystem) {
|
||||
hierarchySystem.setParent(child, newEntity);
|
||||
this.entityStore.addEntity(child, newEntity);
|
||||
}
|
||||
}
|
||||
|
||||
this.entityStore.addEntity(newEntity, this.parentEntity ?? undefined);
|
||||
// 获取父实体
|
||||
const parentEntity = this.parentEntityId !== null
|
||||
? scene.findEntityById(this.parentEntityId) ?? undefined
|
||||
: undefined;
|
||||
|
||||
this.entityStore.addEntity(newEntity, parentEntity);
|
||||
this.entityStore.selectEntity(newEntity);
|
||||
|
||||
// 更新引用
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
import { Core, Entity, HierarchySystem, HierarchyComponent } from '@esengine/ecs-framework';
|
||||
import { EntityStoreService, MessageHub } from '@esengine/editor-core';
|
||||
import { BaseCommand } from '../BaseCommand';
|
||||
|
||||
/**
|
||||
* 拖放位置类型
|
||||
*/
|
||||
export enum DropPosition {
|
||||
/** 在目标之前 */
|
||||
BEFORE = 'before',
|
||||
/** 在目标内部(作为子级) */
|
||||
INSIDE = 'inside',
|
||||
/** 在目标之后 */
|
||||
AFTER = 'after'
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新设置实体父级命令
|
||||
*
|
||||
* 支持拖拽重排功能,可以将实体移动到:
|
||||
* - 另一个实体之前 (BEFORE)
|
||||
* - 另一个实体内部作为子级 (INSIDE)
|
||||
* - 另一个实体之后 (AFTER)
|
||||
*/
|
||||
export class ReparentEntityCommand extends BaseCommand {
|
||||
private oldParentId: number | null;
|
||||
private oldSiblingIndex: number;
|
||||
|
||||
constructor(
|
||||
private entityStore: EntityStoreService,
|
||||
private messageHub: MessageHub,
|
||||
private entity: Entity,
|
||||
private targetEntity: Entity,
|
||||
private dropPosition: DropPosition
|
||||
) {
|
||||
super();
|
||||
|
||||
// 保存原始状态用于撤销
|
||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||
this.oldParentId = hierarchy?.parentId ?? null;
|
||||
|
||||
// 获取在兄弟列表中的原始索引
|
||||
this.oldSiblingIndex = this.getSiblingIndex(entity);
|
||||
}
|
||||
|
||||
execute(): void {
|
||||
const scene = Core.scene;
|
||||
if (!scene) {
|
||||
console.warn('[ReparentEntityCommand] No scene available');
|
||||
return;
|
||||
}
|
||||
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
if (!hierarchySystem) {
|
||||
console.warn('[ReparentEntityCommand] No HierarchySystem found');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保目标实体有 HierarchyComponent
|
||||
if (!this.targetEntity.getComponent(HierarchyComponent)) {
|
||||
this.targetEntity.addComponent(new HierarchyComponent());
|
||||
}
|
||||
|
||||
console.log(`[ReparentEntityCommand] Moving ${this.entity.name} to ${this.targetEntity.name} (${this.dropPosition})`);
|
||||
|
||||
switch (this.dropPosition) {
|
||||
case DropPosition.INSIDE:
|
||||
// 移动到目标实体内部作为最后一个子级
|
||||
hierarchySystem.setParent(this.entity, this.targetEntity);
|
||||
break;
|
||||
|
||||
case DropPosition.BEFORE:
|
||||
case DropPosition.AFTER:
|
||||
// 移动到目标实体的同级
|
||||
this.moveToSibling(hierarchySystem);
|
||||
break;
|
||||
}
|
||||
|
||||
this.entityStore.syncFromScene();
|
||||
this.messageHub.publish('entity:reparented', {
|
||||
entityId: this.entity.id,
|
||||
targetId: this.targetEntity.id,
|
||||
position: this.dropPosition
|
||||
});
|
||||
}
|
||||
|
||||
undo(): void {
|
||||
const scene = Core.scene;
|
||||
if (!scene) return;
|
||||
|
||||
const hierarchySystem = scene.getSystem(HierarchySystem);
|
||||
if (!hierarchySystem) return;
|
||||
|
||||
// 恢复到原始父级
|
||||
const oldParent = this.oldParentId !== null
|
||||
? scene.findEntityById(this.oldParentId)
|
||||
: null;
|
||||
|
||||
if (oldParent) {
|
||||
// 恢复到原始父级的指定位置
|
||||
hierarchySystem.insertChildAt(oldParent, this.entity, this.oldSiblingIndex);
|
||||
} else {
|
||||
// 恢复到根级
|
||||
hierarchySystem.setParent(this.entity, null);
|
||||
}
|
||||
|
||||
this.entityStore.syncFromScene();
|
||||
this.messageHub.publish('entity:reparented', {
|
||||
entityId: this.entity.id,
|
||||
targetId: null,
|
||||
position: 'undo'
|
||||
});
|
||||
}
|
||||
|
||||
getDescription(): string {
|
||||
const positionText = this.dropPosition === DropPosition.INSIDE
|
||||
? '移入'
|
||||
: this.dropPosition === DropPosition.BEFORE ? '移动到前面' : '移动到后面';
|
||||
return `${positionText}: ${this.entity.name} -> ${this.targetEntity.name}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动到目标的同级位置
|
||||
*/
|
||||
private moveToSibling(hierarchySystem: HierarchySystem): void {
|
||||
const targetHierarchy = this.targetEntity.getComponent(HierarchyComponent);
|
||||
const targetParentId = targetHierarchy?.parentId ?? null;
|
||||
|
||||
const scene = Core.scene;
|
||||
if (!scene) return;
|
||||
|
||||
// 获取目标的父实体
|
||||
const targetParent = targetParentId !== null
|
||||
? scene.findEntityById(targetParentId)
|
||||
: null;
|
||||
|
||||
// 获取目标在兄弟列表中的索引
|
||||
let targetIndex = this.getSiblingIndex(this.targetEntity);
|
||||
|
||||
// 根据放置位置调整索引
|
||||
if (this.dropPosition === DropPosition.AFTER) {
|
||||
targetIndex++;
|
||||
}
|
||||
|
||||
// 如果移动到同一父级下,需要考虑原位置对索引的影响
|
||||
const entityHierarchy = this.entity.getComponent(HierarchyComponent);
|
||||
const entityParentId = entityHierarchy?.parentId ?? null;
|
||||
|
||||
const bSameParent = entityParentId === targetParentId;
|
||||
if (bSameParent) {
|
||||
const currentIndex = this.getSiblingIndex(this.entity);
|
||||
if (currentIndex < targetIndex) {
|
||||
targetIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[ReparentEntityCommand] moveToSibling: targetParent=${targetParent?.name ?? 'ROOT'}, targetIndex=${targetIndex}`);
|
||||
|
||||
if (targetParent) {
|
||||
// 有父级,插入到父级的指定位置
|
||||
hierarchySystem.insertChildAt(targetParent, this.entity, targetIndex);
|
||||
} else {
|
||||
// 目标在根级
|
||||
// 先确保实体移动到根级
|
||||
if (entityParentId !== null) {
|
||||
hierarchySystem.setParent(this.entity, null);
|
||||
}
|
||||
// 然后调整根级顺序
|
||||
this.entityStore.reorderEntity(this.entity.id, targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体在兄弟列表中的索引
|
||||
*/
|
||||
private getSiblingIndex(entity: Entity): number {
|
||||
const scene = Core.scene;
|
||||
if (!scene) return 0;
|
||||
|
||||
const hierarchy = entity.getComponent(HierarchyComponent);
|
||||
const parentId = hierarchy?.parentId;
|
||||
|
||||
if (parentId === null || parentId === undefined) {
|
||||
// 根级实体,从 EntityStoreService 获取
|
||||
return this.entityStore.getRootEntityIds().indexOf(entity.id);
|
||||
}
|
||||
|
||||
const parent = scene.findEntityById(parentId);
|
||||
if (!parent) return 0;
|
||||
|
||||
const parentHierarchy = parent.getComponent(HierarchyComponent);
|
||||
return parentHierarchy?.childIds.indexOf(entity.id) ?? 0;
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,5 @@ export { CreateAnimatedSpriteEntityCommand } from './CreateAnimatedSpriteEntityC
|
||||
export { CreateCameraEntityCommand } from './CreateCameraEntityCommand';
|
||||
export { CreateTilemapEntityCommand } from './CreateTilemapEntityCommand';
|
||||
export { DeleteEntityCommand } from './DeleteEntityCommand';
|
||||
export { ReparentEntityCommand, DropPosition } from './ReparentEntityCommand';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user