移除 Entity._localComponents/强制Entity必须属于Scene/简化组件操作逻辑
This commit is contained in:
@@ -14,7 +14,9 @@ export class EntityBuilder {
|
|||||||
constructor(scene: IScene, storageManager: ComponentStorageManager) {
|
constructor(scene: IScene, storageManager: ComponentStorageManager) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.storageManager = storageManager;
|
this.storageManager = storageManager;
|
||||||
this.entity = new Entity("", scene.identifierPool.checkOut());
|
const id = scene.identifierPool.checkOut();
|
||||||
|
this.entity = new Entity("", id);
|
||||||
|
this.entity.scene = this.scene as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -145,12 +145,6 @@ export class Entity {
|
|||||||
*/
|
*/
|
||||||
private _componentCache: Component[] | null = null;
|
private _componentCache: Component[] | null = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 本地组件存储(用于没有 Scene 的 Entity)
|
|
||||||
* 当 Entity 添加到 Scene 时,组件会迁移到 Scene 的 componentStorageManager
|
|
||||||
*/
|
|
||||||
private _localComponents: Map<ComponentType, Component> = new Map();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
*
|
*
|
||||||
@@ -186,28 +180,23 @@ export class Entity {
|
|||||||
*/
|
*/
|
||||||
private _rebuildComponentCache(): void {
|
private _rebuildComponentCache(): void {
|
||||||
const components: Component[] = [];
|
const components: Component[] = [];
|
||||||
const mask = this._componentMask;
|
|
||||||
|
|
||||||
|
if (!this.scene?.componentStorageManager) {
|
||||||
|
this._componentCache = components;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mask = this._componentMask;
|
||||||
const maxBitIndex = ComponentRegistry.getRegisteredCount();
|
const maxBitIndex = ComponentRegistry.getRegisteredCount();
|
||||||
|
|
||||||
for (let bitIndex = 0; bitIndex < maxBitIndex; bitIndex++) {
|
for (let bitIndex = 0; bitIndex < maxBitIndex; bitIndex++) {
|
||||||
if (BitMask64Utils.getBit(mask, bitIndex)) {
|
if (BitMask64Utils.getBit(mask, bitIndex)) {
|
||||||
const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex);
|
const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex);
|
||||||
if (componentType) {
|
if (componentType) {
|
||||||
let component: Component | null = null;
|
const component = this.scene.componentStorageManager.getComponent(
|
||||||
|
|
||||||
// 优先从 Scene 存储获取
|
|
||||||
if (this.scene?.componentStorageManager) {
|
|
||||||
component = this.scene.componentStorageManager.getComponent(
|
|
||||||
this.id,
|
this.id,
|
||||||
componentType
|
componentType
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback 到本地存储
|
|
||||||
if (!component) {
|
|
||||||
component = this._localComponents.get(componentType) || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component) {
|
if (component) {
|
||||||
components.push(component);
|
components.push(component);
|
||||||
@@ -378,9 +367,6 @@ export class Entity {
|
|||||||
ComponentRegistry.register(componentType);
|
ComponentRegistry.register(componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 存储到本地 Map
|
|
||||||
this._localComponents.set(componentType, component);
|
|
||||||
|
|
||||||
// 更新位掩码
|
// 更新位掩码
|
||||||
const componentMask = ComponentRegistry.getBitMask(componentType);
|
const componentMask = ComponentRegistry.getBitMask(componentType);
|
||||||
BitMask64Utils.orInPlace(this._componentMask, componentMask);
|
BitMask64Utils.orInPlace(this._componentMask, componentMask);
|
||||||
@@ -407,15 +393,21 @@ export class Entity {
|
|||||||
public addComponent<T extends Component>(component: T): T {
|
public addComponent<T extends Component>(component: T): T {
|
||||||
const componentType = component.constructor as ComponentType<T>;
|
const componentType = component.constructor as ComponentType<T>;
|
||||||
|
|
||||||
|
if (!this.scene) {
|
||||||
|
throw new Error(`Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.scene.componentStorageManager) {
|
||||||
|
throw new Error(`Scene does not have componentStorageManager`);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.hasComponent(componentType)) {
|
if (this.hasComponent(componentType)) {
|
||||||
throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`);
|
throw new Error(`Entity ${this.name} already has component ${getComponentTypeName(componentType)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addComponentInternal(component);
|
this.addComponentInternal(component);
|
||||||
|
|
||||||
if (this.scene && this.scene.componentStorageManager) {
|
|
||||||
this.scene.componentStorageManager.addComponent(this.id, component);
|
this.scene.componentStorageManager.addComponent(this.id, component);
|
||||||
}
|
|
||||||
|
|
||||||
component.onAddedToEntity();
|
component.onAddedToEntity();
|
||||||
|
|
||||||
@@ -459,16 +451,13 @@ export class Entity {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优先从 Scene 存储获取
|
// 从Scene存储获取
|
||||||
if (this.scene?.componentStorageManager) {
|
if (!this.scene?.componentStorageManager) {
|
||||||
const component = this.scene.componentStorageManager.getComponent(this.id, type);
|
return null;
|
||||||
if (component) {
|
|
||||||
return component as T;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback 到本地存储
|
const component = this.scene.componentStorageManager.getComponent(this.id, type);
|
||||||
return (this._localComponents.get(type) as T) || null;
|
return component as T | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -538,17 +527,14 @@ export class Entity {
|
|||||||
|
|
||||||
const bitIndex = ComponentRegistry.getBitIndex(componentType);
|
const bitIndex = ComponentRegistry.getBitIndex(componentType);
|
||||||
|
|
||||||
// 从本地存储移除
|
|
||||||
this._localComponents.delete(componentType);
|
|
||||||
|
|
||||||
// 更新位掩码
|
// 更新位掩码
|
||||||
BitMask64Utils.clearBit(this._componentMask, bitIndex);
|
BitMask64Utils.clearBit(this._componentMask, bitIndex);
|
||||||
|
|
||||||
// 使缓存失效
|
// 使缓存失效
|
||||||
this._componentCache = null;
|
this._componentCache = null;
|
||||||
|
|
||||||
// 从 Scene 存储移除
|
// 从Scene存储移除
|
||||||
if (this.scene && this.scene.componentStorageManager) {
|
if (this.scene?.componentStorageManager) {
|
||||||
this.scene.componentStorageManager.removeComponent(this.id, componentType);
|
this.scene.componentStorageManager.removeComponent(this.id, componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,9 +579,6 @@ export class Entity {
|
|||||||
public removeAllComponents(): void {
|
public removeAllComponents(): void {
|
||||||
const componentsToRemove = [...this.components];
|
const componentsToRemove = [...this.components];
|
||||||
|
|
||||||
// 清除本地存储
|
|
||||||
this._localComponents.clear();
|
|
||||||
|
|
||||||
// 清除位掩码
|
// 清除位掩码
|
||||||
BitMask64Utils.clear(this._componentMask);
|
BitMask64Utils.clear(this._componentMask);
|
||||||
|
|
||||||
@@ -605,7 +588,7 @@ export class Entity {
|
|||||||
for (const component of componentsToRemove) {
|
for (const component of componentsToRemove) {
|
||||||
const componentType = component.constructor as ComponentType;
|
const componentType = component.constructor as ComponentType;
|
||||||
|
|
||||||
if (this.scene && this.scene.componentStorageManager) {
|
if (this.scene?.componentStorageManager) {
|
||||||
this.scene.componentStorageManager.removeComponent(this.id, componentType);
|
this.scene.componentStorageManager.removeComponent(this.id, componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Entity } from '../Entity';
|
|||||||
import { Component } from '../Component';
|
import { Component } from '../Component';
|
||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import { ComponentType } from '../Core/ComponentStorage';
|
||||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
||||||
|
import { IScene } from '../IScene';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化后的实体数据
|
* 序列化后的实体数据
|
||||||
@@ -108,18 +109,25 @@ export class EntitySerializer {
|
|||||||
* @param componentRegistry 组件类型注册表
|
* @param componentRegistry 组件类型注册表
|
||||||
* @param idGenerator 实体ID生成器(用于生成新ID或保持原ID)
|
* @param idGenerator 实体ID生成器(用于生成新ID或保持原ID)
|
||||||
* @param preserveIds 是否保持原始ID(默认false)
|
* @param preserveIds 是否保持原始ID(默认false)
|
||||||
|
* @param scene 目标场景(可选,用于设置entity.scene以支持添加组件)
|
||||||
* @returns 反序列化后的实体
|
* @returns 反序列化后的实体
|
||||||
*/
|
*/
|
||||||
public static deserialize(
|
public static deserialize(
|
||||||
serializedEntity: SerializedEntity,
|
serializedEntity: SerializedEntity,
|
||||||
componentRegistry: Map<string, ComponentType>,
|
componentRegistry: Map<string, ComponentType>,
|
||||||
idGenerator: () => number,
|
idGenerator: () => number,
|
||||||
preserveIds: boolean = false
|
preserveIds: boolean = false,
|
||||||
|
scene?: IScene
|
||||||
): Entity {
|
): Entity {
|
||||||
// 创建实体(使用原始ID或新生成的ID)
|
// 创建实体(使用原始ID或新生成的ID)
|
||||||
const entityId = preserveIds ? serializedEntity.id : idGenerator();
|
const entityId = preserveIds ? serializedEntity.id : idGenerator();
|
||||||
const entity = new Entity(serializedEntity.name, entityId);
|
const entity = new Entity(serializedEntity.name, entityId);
|
||||||
|
|
||||||
|
// 如果提供了scene,先设置entity.scene以支持添加组件
|
||||||
|
if (scene) {
|
||||||
|
entity.scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
// 恢复实体属性
|
// 恢复实体属性
|
||||||
entity.tag = serializedEntity.tag;
|
entity.tag = serializedEntity.tag;
|
||||||
entity.active = serializedEntity.active;
|
entity.active = serializedEntity.active;
|
||||||
@@ -142,7 +150,8 @@ export class EntitySerializer {
|
|||||||
childData,
|
childData,
|
||||||
componentRegistry,
|
componentRegistry,
|
||||||
idGenerator,
|
idGenerator,
|
||||||
preserveIds
|
preserveIds,
|
||||||
|
scene
|
||||||
);
|
);
|
||||||
entity.addChild(childEntity);
|
entity.addChild(childEntity);
|
||||||
}
|
}
|
||||||
@@ -181,13 +190,15 @@ export class EntitySerializer {
|
|||||||
* @param componentRegistry 组件类型注册表
|
* @param componentRegistry 组件类型注册表
|
||||||
* @param idGenerator 实体ID生成器
|
* @param idGenerator 实体ID生成器
|
||||||
* @param preserveIds 是否保持原始ID
|
* @param preserveIds 是否保持原始ID
|
||||||
|
* @param scene 目标场景(可选,用于设置entity.scene以支持添加组件)
|
||||||
* @returns 反序列化后的实体数组
|
* @returns 反序列化后的实体数组
|
||||||
*/
|
*/
|
||||||
public static deserializeEntities(
|
public static deserializeEntities(
|
||||||
serializedEntities: SerializedEntity[],
|
serializedEntities: SerializedEntity[],
|
||||||
componentRegistry: Map<string, ComponentType>,
|
componentRegistry: Map<string, ComponentType>,
|
||||||
idGenerator: () => number,
|
idGenerator: () => number,
|
||||||
preserveIds: boolean = false
|
preserveIds: boolean = false,
|
||||||
|
scene?: IScene
|
||||||
): Entity[] {
|
): Entity[] {
|
||||||
const result: Entity[] = [];
|
const result: Entity[] = [];
|
||||||
|
|
||||||
@@ -196,7 +207,8 @@ export class EntitySerializer {
|
|||||||
serialized,
|
serialized,
|
||||||
componentRegistry,
|
componentRegistry,
|
||||||
idGenerator,
|
idGenerator,
|
||||||
preserveIds
|
preserveIds,
|
||||||
|
scene
|
||||||
);
|
);
|
||||||
result.push(entity);
|
result.push(entity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,7 +269,8 @@ export class SceneSerializer {
|
|||||||
serializedScene.entities,
|
serializedScene.entities,
|
||||||
componentRegistry,
|
componentRegistry,
|
||||||
idGenerator,
|
idGenerator,
|
||||||
opts.preserveIds || false
|
opts.preserveIds || false,
|
||||||
|
scene
|
||||||
);
|
);
|
||||||
|
|
||||||
// 将实体添加到场景
|
// 将实体添加到场景
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component } from '../../src/ECS/Component';
|
import { Component } from '../../src/ECS/Component';
|
||||||
import { Entity } from '../../src/ECS/Entity';
|
import { Entity } from '../../src/ECS/Entity';
|
||||||
|
import { Scene } from '../../src/ECS/Scene';
|
||||||
|
|
||||||
// 测试组件
|
// 测试组件
|
||||||
class TestComponent extends Component {
|
class TestComponent extends Component {
|
||||||
@@ -23,12 +24,13 @@ class AnotherTestComponent extends Component {
|
|||||||
describe('Component - 组件基类测试', () => {
|
describe('Component - 组件基类测试', () => {
|
||||||
let component: TestComponent;
|
let component: TestComponent;
|
||||||
let entity: Entity;
|
let entity: Entity;
|
||||||
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Reset component ID generator to avoid BigInt issues
|
|
||||||
Component._idGenerator = 0;
|
Component._idGenerator = 0;
|
||||||
component = new TestComponent();
|
component = new TestComponent();
|
||||||
entity = new Entity('TestEntity', 1);
|
scene = new Scene();
|
||||||
|
entity = scene.createEntity('TestEntity');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('基本功能', () => {
|
describe('基本功能', () => {
|
||||||
|
|||||||
@@ -568,9 +568,9 @@ describe('FluentAPI - 流式API测试', () => {
|
|||||||
let batchOp: EntityBatchOperator;
|
let batchOp: EntityBatchOperator;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
entity1 = new Entity('Entity1', 1);
|
entity1 = scene.createEntity('Entity1');
|
||||||
entity2 = new Entity('Entity2', 2);
|
entity2 = scene.createEntity('Entity2');
|
||||||
entity3 = new Entity('Entity3', 3);
|
entity3 = scene.createEntity('Entity3');
|
||||||
batchOp = new EntityBatchOperator([entity1, entity2, entity3]);
|
batchOp = new EntityBatchOperator([entity1, entity2, entity3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { QuerySystem, QueryBuilder, QueryConditionType } from '../../../src/ECS/
|
|||||||
import { Entity } from '../../../src/ECS/Entity';
|
import { Entity } from '../../../src/ECS/Entity';
|
||||||
import { Component } from '../../../src/ECS/Component';
|
import { Component } from '../../../src/ECS/Component';
|
||||||
import { ComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
|
import { ComponentRegistry, ComponentType } from '../../../src/ECS/Core/ComponentStorage';
|
||||||
|
import { Scene } from '../../../src/ECS/Scene';
|
||||||
|
|
||||||
// 测试组件
|
// 测试组件
|
||||||
class PositionComponent extends Component {
|
class PositionComponent extends Component {
|
||||||
@@ -75,6 +76,7 @@ class PhysicsComponent extends Component {
|
|||||||
describe('QuerySystem - 查询系统测试', () => {
|
describe('QuerySystem - 查询系统测试', () => {
|
||||||
let querySystem: QuerySystem;
|
let querySystem: QuerySystem;
|
||||||
let entities: Entity[];
|
let entities: Entity[];
|
||||||
|
let scene: Scene;
|
||||||
let originalAddComponent: any;
|
let originalAddComponent: any;
|
||||||
let originalRemoveComponent: any;
|
let originalRemoveComponent: any;
|
||||||
let originalRemoveAllComponents: any;
|
let originalRemoveAllComponents: any;
|
||||||
@@ -82,10 +84,11 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
querySystem = new QuerySystem();
|
querySystem = new QuerySystem();
|
||||||
entities = [];
|
entities = [];
|
||||||
|
scene = new Scene();
|
||||||
|
|
||||||
// 创建测试实体
|
// 创建测试实体
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
const entity = new Entity(`Entity_${i}`, i + 1);
|
const entity = scene.createEntity(`Entity_${i}`);
|
||||||
entities.push(entity);
|
entities.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,14 +291,10 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
// 创建大量具有相同组件组合的实体
|
// 创建大量具有相同组件组合的实体
|
||||||
for (let i = 0; i < entityCount; i++) {
|
for (let i = 0; i < entityCount; i++) {
|
||||||
const entity = new Entity(`PerfEntity_${i}`, i + 100);
|
const entity = scene.createEntity(`PerfEntity_${i}`);
|
||||||
testEntities.push(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先添加组件
|
|
||||||
for (const entity of testEntities) {
|
|
||||||
entity.addComponent(new PositionComponent(0, 0));
|
entity.addComponent(new PositionComponent(0, 0));
|
||||||
entity.addComponent(new VelocityComponent(1, 1));
|
entity.addComponent(new VelocityComponent(1, 1));
|
||||||
|
testEntities.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将实体添加到查询系统
|
// 将实体添加到查询系统
|
||||||
@@ -343,15 +342,9 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
const entityCount = 5000;
|
const entityCount = 5000;
|
||||||
const testEntities: Entity[] = [];
|
const testEntities: Entity[] = [];
|
||||||
|
|
||||||
// 创建大量实体
|
// 创建大量实体并分配组件
|
||||||
for (let i = 0; i < entityCount; i++) {
|
for (let i = 0; i < entityCount; i++) {
|
||||||
const entity = new Entity(`MaskEntity_${i}`, i + 200);
|
const entity = scene.createEntity(`MaskEntity_${i}`);
|
||||||
testEntities.push(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先随机分配组件
|
|
||||||
for (let i = 0; i < entityCount; i++) {
|
|
||||||
const entity = testEntities[i];
|
|
||||||
|
|
||||||
entity.addComponent(new PositionComponent(i, i));
|
entity.addComponent(new PositionComponent(i, i));
|
||||||
|
|
||||||
@@ -366,6 +359,8 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
if (i % 5 === 0) {
|
if (i % 5 === 0) {
|
||||||
entity.addComponent(new RenderComponent(true));
|
entity.addComponent(new RenderComponent(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testEntities.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将实体添加到查询系统
|
// 将实体添加到查询系统
|
||||||
@@ -499,7 +494,7 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
// 创建大量实体
|
// 创建大量实体
|
||||||
for (let i = 0; i < entityCount; i++) {
|
for (let i = 0; i < entityCount; i++) {
|
||||||
const entity = new Entity(`MemEntity_${i}`, i + 300);
|
const entity = scene.createEntity(`MemEntity_${i}`);
|
||||||
entity.addComponent(new PositionComponent(i, i));
|
entity.addComponent(new PositionComponent(i, i));
|
||||||
|
|
||||||
if (i % 2 === 0) {
|
if (i % 2 === 0) {
|
||||||
@@ -785,7 +780,7 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
describe('实体管理功能', () => {
|
describe('实体管理功能', () => {
|
||||||
test('应该能够添加和移除单个实体', () => {
|
test('应该能够添加和移除单个实体', () => {
|
||||||
const newEntity = new Entity('NewEntity', 999);
|
const newEntity = scene.createEntity('NewEntity');
|
||||||
|
|
||||||
querySystem.addEntity(newEntity);
|
querySystem.addEntity(newEntity);
|
||||||
let stats = querySystem.getStats();
|
let stats = querySystem.getStats();
|
||||||
@@ -798,9 +793,9 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
test('应该能够批量添加实体', () => {
|
test('应该能够批量添加实体', () => {
|
||||||
const newEntities = [
|
const newEntities = [
|
||||||
new Entity('Batch1', 997),
|
scene.createEntity('Batch1'),
|
||||||
new Entity('Batch2', 998),
|
scene.createEntity('Batch2'),
|
||||||
new Entity('Batch3', 999)
|
scene.createEntity('Batch3')
|
||||||
];
|
];
|
||||||
|
|
||||||
querySystem.addEntities(newEntities);
|
querySystem.addEntities(newEntities);
|
||||||
@@ -810,8 +805,8 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
test('应该能够批量添加实体(无重复检查)', () => {
|
test('应该能够批量添加实体(无重复检查)', () => {
|
||||||
const newEntities = [
|
const newEntities = [
|
||||||
new Entity('Unchecked1', 995),
|
scene.createEntity('Unchecked1'),
|
||||||
new Entity('Unchecked2', 996)
|
scene.createEntity('Unchecked2')
|
||||||
];
|
];
|
||||||
|
|
||||||
querySystem.addEntitiesUnchecked(newEntities);
|
querySystem.addEntitiesUnchecked(newEntities);
|
||||||
@@ -846,43 +841,34 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('组件变动同步问题测试', () => {
|
describe('组件变动同步问题测试', () => {
|
||||||
test('没有Scene时组件变动不会自动同步(符合ECS架构)', () => {
|
test('Entity必须有Scene才能添加组件', () => {
|
||||||
// 创建一个独立的QuerySystem和实体
|
// 创建一个独立的QuerySystem和实体
|
||||||
const independentQuerySystem = new QuerySystem();
|
const independentQuerySystem = new QuerySystem();
|
||||||
const testEntity = new Entity('TestEntity', 9999);
|
const testEntity = scene.createEntity('TestEntity');
|
||||||
|
|
||||||
// 确保实体没有scene
|
// Entity现在必须有scene
|
||||||
expect(testEntity.scene).toBe(null);
|
expect(testEntity.scene).toBeTruthy();
|
||||||
|
|
||||||
// 添加实体到查询系统
|
// 添加实体到查询系统
|
||||||
independentQuerySystem.addEntity(testEntity);
|
independentQuerySystem.addEntity(testEntity);
|
||||||
|
|
||||||
// 初始查询:应该没有PositionComponent的实体
|
// 添加组件
|
||||||
const result1 = independentQuerySystem.queryAll(PositionComponent);
|
|
||||||
expect(result1.entities.length).toBe(0);
|
|
||||||
|
|
||||||
// 添加组件,但没有Scene,不会自动同步
|
|
||||||
testEntity.addComponent(new PositionComponent(100, 200));
|
testEntity.addComponent(new PositionComponent(100, 200));
|
||||||
|
|
||||||
// 查询系统不知道组件变化(这是预期行为)
|
|
||||||
const result2 = independentQuerySystem.queryAll(PositionComponent);
|
|
||||||
expect(result2.entities.length).toBe(0); // 查询系统没有自动更新
|
|
||||||
expect(testEntity.hasComponent(PositionComponent)).toBe(true); // 但实体确实有这个组件
|
|
||||||
|
|
||||||
// 手动同步后应该能找到
|
// 手动同步后应该能找到
|
||||||
independentQuerySystem.updateEntity(testEntity);
|
independentQuerySystem.updateEntity(testEntity);
|
||||||
const result3 = independentQuerySystem.queryAll(PositionComponent);
|
const result = independentQuerySystem.queryAll(PositionComponent);
|
||||||
expect(result3.entities.length).toBe(1);
|
expect(result.entities.length).toBe(1);
|
||||||
expect(result3.entities[0]).toBe(testEntity);
|
expect(result.entities[0]).toBe(testEntity);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('有Scene但没有querySystem时组件变动应该安全', () => {
|
test('有Scene但没有querySystem时组件变动应该安全', () => {
|
||||||
const testEntity = new Entity('TestEntity2', 9998);
|
const testEntity = scene.createEntity('TestEntity2');
|
||||||
|
|
||||||
// 模拟一个没有querySystem的scene
|
// 模拟一个没有querySystem的scene(但保留componentStorageManager)
|
||||||
const mockScene = {
|
const mockScene = {
|
||||||
querySystem: null,
|
querySystem: null,
|
||||||
componentStorageManager: null,
|
componentStorageManager: scene.componentStorageManager,
|
||||||
clearSystemEntityCaches: jest.fn()
|
clearSystemEntityCaches: jest.fn()
|
||||||
};
|
};
|
||||||
testEntity.scene = mockScene as any;
|
testEntity.scene = mockScene as any;
|
||||||
@@ -897,12 +883,12 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
test('有Scene时ArchetypeSystem组件变动能正确同步', () => {
|
test('有Scene时ArchetypeSystem组件变动能正确同步', () => {
|
||||||
const independentQuerySystem = new QuerySystem();
|
const independentQuerySystem = new QuerySystem();
|
||||||
const testEntity = new Entity('ArchetypeTestEntity', 9997);
|
const testEntity = scene.createEntity('ArchetypeTestEntity');
|
||||||
|
|
||||||
// 模拟Scene环境
|
// 模拟Scene环境(保留componentStorageManager)
|
||||||
const mockScene = {
|
const mockScene = {
|
||||||
querySystem: independentQuerySystem,
|
querySystem: independentQuerySystem,
|
||||||
componentStorageManager: null,
|
componentStorageManager: scene.componentStorageManager,
|
||||||
clearSystemEntityCaches: jest.fn()
|
clearSystemEntityCaches: jest.fn()
|
||||||
};
|
};
|
||||||
testEntity.scene = mockScene as any;
|
testEntity.scene = mockScene as any;
|
||||||
@@ -941,12 +927,12 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
test('有Scene时removeAllComponents应该正确同步QuerySystem', () => {
|
test('有Scene时removeAllComponents应该正确同步QuerySystem', () => {
|
||||||
const independentQuerySystem = new QuerySystem();
|
const independentQuerySystem = new QuerySystem();
|
||||||
const testEntity = new Entity('RemoveAllTestEntity', 9996);
|
const testEntity = scene.createEntity('RemoveAllTestEntity');
|
||||||
|
|
||||||
// 模拟Scene环境
|
// 模拟Scene环境(保留componentStorageManager)
|
||||||
const mockScene = {
|
const mockScene = {
|
||||||
querySystem: independentQuerySystem,
|
querySystem: independentQuerySystem,
|
||||||
componentStorageManager: null,
|
componentStorageManager: scene.componentStorageManager,
|
||||||
clearSystemEntityCaches: jest.fn()
|
clearSystemEntityCaches: jest.fn()
|
||||||
};
|
};
|
||||||
testEntity.scene = mockScene as any;
|
testEntity.scene = mockScene as any;
|
||||||
@@ -978,7 +964,7 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
|
|
||||||
test('手动同步updateEntity应该工作正常', () => {
|
test('手动同步updateEntity应该工作正常', () => {
|
||||||
const independentQuerySystem = new QuerySystem();
|
const independentQuerySystem = new QuerySystem();
|
||||||
const testEntity = new Entity('ManualSyncTestEntity', 9995);
|
const testEntity = scene.createEntity('ManualSyncTestEntity');
|
||||||
|
|
||||||
independentQuerySystem.addEntity(testEntity);
|
independentQuerySystem.addEntity(testEntity);
|
||||||
|
|
||||||
@@ -1002,9 +988,9 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
const querySystem = new QuerySystem();
|
const querySystem = new QuerySystem();
|
||||||
|
|
||||||
// 创建带组件的实体
|
// 创建带组件的实体
|
||||||
const entity1 = new Entity('BatchEntity1', 8001);
|
const entity1 = scene.createEntity('BatchEntity1');
|
||||||
const entity2 = new Entity('BatchEntity2', 8002);
|
const entity2 = scene.createEntity('BatchEntity2');
|
||||||
const entity3 = new Entity('BatchEntity3', 8003);
|
const entity3 = scene.createEntity('BatchEntity3');
|
||||||
|
|
||||||
entity1.addComponent(new PositionComponent(10, 20));
|
entity1.addComponent(new PositionComponent(10, 20));
|
||||||
entity2.addComponent(new PositionComponent(30, 40));
|
entity2.addComponent(new PositionComponent(30, 40));
|
||||||
@@ -1053,9 +1039,9 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
describe('组件掩码字符串索引', () => {
|
describe('组件掩码字符串索引', () => {
|
||||||
test('应该为不同的组件组合生成不同的掩码字符串', () => {
|
test('应该为不同的组件组合生成不同的掩码字符串', () => {
|
||||||
// 创建具有不同组件组合的实体
|
// 创建具有不同组件组合的实体
|
||||||
const entity1 = new Entity('Entity1', 101);
|
const entity1 = scene.createEntity('Entity1');
|
||||||
const entity2 = new Entity('Entity2', 102);
|
const entity2 = scene.createEntity('Entity2');
|
||||||
const entity3 = new Entity('Entity3', 103);
|
const entity3 = scene.createEntity('Entity3');
|
||||||
|
|
||||||
entity1.addComponent(new PositionComponent(1, 1));
|
entity1.addComponent(new PositionComponent(1, 1));
|
||||||
entity2.addComponent(new VelocityComponent(2, 2));
|
entity2.addComponent(new VelocityComponent(2, 2));
|
||||||
@@ -1071,22 +1057,22 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
const withBoth = querySystem.queryAll(PositionComponent, VelocityComponent);
|
const withBoth = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||||||
|
|
||||||
// entity1 应该在 withPosition 中
|
// entity1 应该在 withPosition 中
|
||||||
expect(withPosition.entities.some(e => e.id === 101)).toBe(true);
|
expect(withPosition.entities).toContain(entity1);
|
||||||
// entity2 应该在 withVelocity 中
|
// entity2 应该在 withVelocity 中
|
||||||
expect(withVelocity.entities.some(e => e.id === 102)).toBe(true);
|
expect(withVelocity.entities).toContain(entity2);
|
||||||
// entity3 应该在所有查询中(因为它包含 Position 和 Velocity)
|
// entity3 应该在所有查询中(因为它包含 Position 和 Velocity)
|
||||||
expect(withPosition.entities.some(e => e.id === 103)).toBe(true);
|
expect(withPosition.entities).toContain(entity3);
|
||||||
expect(withVelocity.entities.some(e => e.id === 103)).toBe(true);
|
expect(withVelocity.entities).toContain(entity3);
|
||||||
expect(withBoth.entities.some(e => e.id === 103)).toBe(true);
|
expect(withBoth.entities).toContain(entity3);
|
||||||
|
|
||||||
// withBoth 只应该包含同时有两个组件的实体
|
// withBoth 只应该包含同时有两个组件的实体
|
||||||
expect(withBoth.entities.some(e => e.id === 101)).toBe(false); // 只有 Position
|
expect(withBoth.entities).not.toContain(entity1); // 只有 Position
|
||||||
expect(withBoth.entities.some(e => e.id === 102)).toBe(false); // 只有 Velocity
|
expect(withBoth.entities).not.toContain(entity2); // 只有 Velocity
|
||||||
});
|
});
|
||||||
|
|
||||||
test('相同组件组合的实体应该使用相同的掩码索引', () => {
|
test('相同组件组合的实体应该使用相同的掩码索引', () => {
|
||||||
const entity1 = new Entity('Entity1', 201);
|
const entity1 = scene.createEntity('Entity1');
|
||||||
const entity2 = new Entity('Entity2', 202);
|
const entity2 = scene.createEntity('Entity2');
|
||||||
|
|
||||||
// 两个实体都有相同的组件组合
|
// 两个实体都有相同的组件组合
|
||||||
entity1.addComponent(new PositionComponent(1, 1));
|
entity1.addComponent(new PositionComponent(1, 1));
|
||||||
@@ -1101,8 +1087,8 @@ describe('QuerySystem - 查询系统测试', () => {
|
|||||||
// 查询应该同时返回这两个实体
|
// 查询应该同时返回这两个实体
|
||||||
const result = querySystem.queryAll(PositionComponent, VelocityComponent);
|
const result = querySystem.queryAll(PositionComponent, VelocityComponent);
|
||||||
|
|
||||||
expect(result.entities.some(e => e.id === 201)).toBe(true);
|
expect(result.entities).toContain(entity1);
|
||||||
expect(result.entities.some(e => e.id === 202)).toBe(true);
|
expect(result.entities).toContain(entity2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Entity } from '../../src/ECS/Entity';
|
import { Entity } from '../../src/ECS/Entity';
|
||||||
import { Component } from '../../src/ECS/Component';
|
import { Component } from '../../src/ECS/Component';
|
||||||
|
import { Scene } from '../../src/ECS/Scene';
|
||||||
|
|
||||||
// 测试组件类
|
// 测试组件类
|
||||||
class TestPositionComponent extends Component {
|
class TestPositionComponent extends Component {
|
||||||
@@ -48,17 +49,19 @@ class TestRenderComponent extends Component {
|
|||||||
|
|
||||||
describe('Entity - 组件缓存优化测试', () => {
|
describe('Entity - 组件缓存优化测试', () => {
|
||||||
let entity: Entity;
|
let entity: Entity;
|
||||||
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// 创建新的实体
|
scene = new Scene();
|
||||||
entity = new Entity('TestEntity', 1);
|
entity = scene.createEntity('TestEntity');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('基本功能测试', () => {
|
describe('基本功能测试', () => {
|
||||||
test('应该能够创建实体', () => {
|
test('应该能够创建实体', () => {
|
||||||
expect(entity.name).toBe('TestEntity');
|
expect(entity.name).toBe('TestEntity');
|
||||||
expect(entity.id).toBe(1);
|
expect(entity.id).toBeGreaterThanOrEqual(0);
|
||||||
expect(entity.components.length).toBe(0);
|
expect(entity.components.length).toBe(0);
|
||||||
|
expect(entity.scene).toBe(scene);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('应该能够添加组件', () => {
|
test('应该能够添加组件', () => {
|
||||||
@@ -262,7 +265,7 @@ describe('Entity - 组件缓存优化测试', () => {
|
|||||||
const debugInfo = entity.getDebugInfo();
|
const debugInfo = entity.getDebugInfo();
|
||||||
|
|
||||||
expect(debugInfo.name).toBe('TestEntity');
|
expect(debugInfo.name).toBe('TestEntity');
|
||||||
expect(debugInfo.id).toBe(1);
|
expect(debugInfo.id).toBeGreaterThanOrEqual(0);
|
||||||
expect(debugInfo.componentCount).toBe(2);
|
expect(debugInfo.componentCount).toBe(2);
|
||||||
expect(debugInfo.componentTypes).toContain('TestPositionComponent');
|
expect(debugInfo.componentTypes).toContain('TestPositionComponent');
|
||||||
expect(debugInfo.componentTypes).toContain('TestHealthComponent');
|
expect(debugInfo.componentTypes).toContain('TestHealthComponent');
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ class NonSerializableComponent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('ECS Serialization System', () => {
|
describe('ECS Serialization System', () => {
|
||||||
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// 清空测试环境
|
// 清空测试环境
|
||||||
ComponentRegistry.reset();
|
ComponentRegistry.reset();
|
||||||
@@ -91,6 +93,9 @@ describe('ECS Serialization System', () => {
|
|||||||
ComponentRegistry.register(VelocityComponent);
|
ComponentRegistry.register(VelocityComponent);
|
||||||
ComponentRegistry.register(PlayerComponent);
|
ComponentRegistry.register(PlayerComponent);
|
||||||
ComponentRegistry.register(HealthComponent);
|
ComponentRegistry.register(HealthComponent);
|
||||||
|
|
||||||
|
// 创建测试场景
|
||||||
|
scene = new Scene();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Component Serialization', () => {
|
describe('Component Serialization', () => {
|
||||||
@@ -185,22 +190,22 @@ describe('ECS Serialization System', () => {
|
|||||||
|
|
||||||
describe('Entity Serialization', () => {
|
describe('Entity Serialization', () => {
|
||||||
it('should serialize an entity with components', () => {
|
it('should serialize an entity with components', () => {
|
||||||
const entity = new Entity('Player', 1);
|
const entity = scene.createEntity('Player');
|
||||||
entity.addComponent(new PositionComponent(50, 100));
|
entity.addComponent(new PositionComponent(50, 100));
|
||||||
entity.addComponent(new VelocityComponent());
|
entity.addComponent(new VelocityComponent());
|
||||||
entity.tag = 10;
|
entity.tag = 10;
|
||||||
|
|
||||||
const serialized = EntitySerializer.serialize(entity);
|
const serialized = EntitySerializer.serialize(entity);
|
||||||
|
|
||||||
expect(serialized.id).toBe(1);
|
expect(serialized.id).toBe(entity.id);
|
||||||
expect(serialized.name).toBe('Player');
|
expect(serialized.name).toBe('Player');
|
||||||
expect(serialized.tag).toBe(10);
|
expect(serialized.tag).toBe(10);
|
||||||
expect(serialized.components.length).toBe(2);
|
expect(serialized.components.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should serialize entity hierarchy', () => {
|
it('should serialize entity hierarchy', () => {
|
||||||
const parent = new Entity('Parent', 1);
|
const parent = scene.createEntity('Parent');
|
||||||
const child = new Entity('Child', 2);
|
const child = scene.createEntity('Child');
|
||||||
|
|
||||||
parent.addComponent(new PositionComponent(0, 0));
|
parent.addComponent(new PositionComponent(0, 0));
|
||||||
child.addComponent(new PositionComponent(10, 10));
|
child.addComponent(new PositionComponent(10, 10));
|
||||||
@@ -209,7 +214,7 @@ describe('ECS Serialization System', () => {
|
|||||||
const serialized = EntitySerializer.serialize(parent);
|
const serialized = EntitySerializer.serialize(parent);
|
||||||
|
|
||||||
expect(serialized.children.length).toBe(1);
|
expect(serialized.children.length).toBe(1);
|
||||||
expect(serialized.children[0].id).toBe(2);
|
expect(serialized.children[0].id).toBe(child.id);
|
||||||
expect(serialized.children[0].name).toBe('Child');
|
expect(serialized.children[0].name).toBe('Child');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -237,7 +242,8 @@ describe('ECS Serialization System', () => {
|
|||||||
serializedEntity,
|
serializedEntity,
|
||||||
registry,
|
registry,
|
||||||
() => idCounter++,
|
() => idCounter++,
|
||||||
false
|
false,
|
||||||
|
scene
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(entity.name).toBe('TestEntity');
|
expect(entity.name).toBe('TestEntity');
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ describe('EntitySystem', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
system = new ConcreteEntitySystem();
|
system = new ConcreteEntitySystem();
|
||||||
entity = new Entity('test_entity', 1);
|
entity = scene.createEntity('test_entity');
|
||||||
entity.addComponent(new TestComponent(10));
|
entity.addComponent(new TestComponent(10));
|
||||||
|
|
||||||
scene.addEntity(entity);
|
scene.addEntity(entity);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { Scene } from '../../../src/ECS/Scene';
|
||||||
import { PassiveSystem } from '../../../src/ECS/Systems/PassiveSystem';
|
import { PassiveSystem } from '../../../src/ECS/Systems/PassiveSystem';
|
||||||
import { IntervalSystem } from '../../../src/ECS/Systems/IntervalSystem';
|
import { IntervalSystem } from '../../../src/ECS/Systems/IntervalSystem';
|
||||||
import { ProcessingSystem } from '../../../src/ECS/Systems/ProcessingSystem';
|
import { ProcessingSystem } from '../../../src/ECS/Systems/ProcessingSystem';
|
||||||
@@ -78,10 +79,12 @@ class ConcreteProcessingSystem extends ProcessingSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('System Types - 系统类型测试', () => {
|
describe('System Types - 系统类型测试', () => {
|
||||||
|
let scene: Scene;
|
||||||
let entity: Entity;
|
let entity: Entity;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
entity = new Entity('TestEntity', 1);
|
scene = new Scene();
|
||||||
|
entity = scene.createEntity('TestEntity');
|
||||||
// 重置时间系统
|
// 重置时间系统
|
||||||
Time.update(0.016);
|
Time.update(0.016);
|
||||||
// 注册测试组件类型
|
// 注册测试组件类型
|
||||||
@@ -282,10 +285,10 @@ describe('System Types - 系统类型测试', () => {
|
|||||||
const interval = new ConcreteIntervalSystem(0.1);
|
const interval = new ConcreteIntervalSystem(0.1);
|
||||||
const processing = new ConcreteProcessingSystem();
|
const processing = new ConcreteProcessingSystem();
|
||||||
|
|
||||||
const matchingEntity = new Entity('Matching', 1);
|
const matchingEntity = scene.createEntity('Matching');
|
||||||
matchingEntity.addComponent(new TestComponent(100));
|
matchingEntity.addComponent(new TestComponent(100));
|
||||||
|
|
||||||
const nonMatchingEntity = new Entity('NonMatching', 2);
|
const nonMatchingEntity = scene.createEntity('NonMatching');
|
||||||
nonMatchingEntity.addComponent(new AnotherComponent('test'));
|
nonMatchingEntity.addComponent(new AnotherComponent('test'));
|
||||||
|
|
||||||
// 所有系统都应该匹配TestComponent
|
// 所有系统都应该匹配TestComponent
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { ComponentSparseSet } from '../../../src/ECS/Utils/ComponentSparseSet';
|
import { ComponentSparseSet } from '../../../src/ECS/Utils/ComponentSparseSet';
|
||||||
import { Entity } from '../../../src/ECS/Entity';
|
import { Entity } from '../../../src/ECS/Entity';
|
||||||
import { Component } from '../../../src/ECS/Component';
|
import { Component } from '../../../src/ECS/Component';
|
||||||
|
import { Scene } from '../../../src/ECS/Scene';
|
||||||
|
|
||||||
// 测试组件类
|
// 测试组件类
|
||||||
class PositionComponent extends Component {
|
class PositionComponent extends Component {
|
||||||
@@ -32,20 +33,21 @@ describe('ComponentSparseSet', () => {
|
|||||||
let entity1: Entity;
|
let entity1: Entity;
|
||||||
let entity2: Entity;
|
let entity2: Entity;
|
||||||
let entity3: Entity;
|
let entity3: Entity;
|
||||||
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
componentSparseSet = new ComponentSparseSet();
|
componentSparseSet = new ComponentSparseSet();
|
||||||
|
scene = new Scene();
|
||||||
|
|
||||||
// 创建测试实体
|
entity1 = scene.createEntity('entity1');
|
||||||
entity1 = new Entity('entity1', 1);
|
|
||||||
entity1.addComponent(new PositionComponent(10, 20));
|
entity1.addComponent(new PositionComponent(10, 20));
|
||||||
entity1.addComponent(new VelocityComponent(1, 2));
|
entity1.addComponent(new VelocityComponent(1, 2));
|
||||||
|
|
||||||
entity2 = new Entity('entity2', 2);
|
entity2 = scene.createEntity('entity2');
|
||||||
entity2.addComponent(new PositionComponent(30, 40));
|
entity2.addComponent(new PositionComponent(30, 40));
|
||||||
entity2.addComponent(new HealthComponent(80, 100));
|
entity2.addComponent(new HealthComponent(80, 100));
|
||||||
|
|
||||||
entity3 = new Entity('entity3', 3);
|
entity3 = scene.createEntity('entity3');
|
||||||
entity3.addComponent(new VelocityComponent(3, 4));
|
entity3.addComponent(new VelocityComponent(3, 4));
|
||||||
entity3.addComponent(new HealthComponent(50, 100));
|
entity3.addComponent(new HealthComponent(50, 100));
|
||||||
entity3.addComponent(new RenderComponent(true));
|
entity3.addComponent(new RenderComponent(true));
|
||||||
@@ -358,7 +360,7 @@ describe('ComponentSparseSet', () => {
|
|||||||
|
|
||||||
// 创建大量实体
|
// 创建大量实体
|
||||||
for (let i = 0; i < 1000; i++) {
|
for (let i = 0; i < 1000; i++) {
|
||||||
const entity = new Entity(`entity${i}`, i);
|
const entity = scene.createEntity(`entity${i}`);
|
||||||
entity.addComponent(new PositionComponent(i, i));
|
entity.addComponent(new PositionComponent(i, i));
|
||||||
|
|
||||||
if (i % 2 === 0) {
|
if (i % 2 === 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user