Перейти к основному содержимому

Сравнение с другими решениями

Empress Core vs bitecs vs ecsy

ХарактеристикаEmpress Corebitecsecsy
ЯзыкTypeScript (TS-first)TypeScript/JavaScriptJavaScript + типизация вручную
ПодходData Oriented + OOP Style + DIЧисто Data Oriented, низкоуровневыйOOP, высокоуровневый
Типизация✅ Полная TS-типизация⚠️ Частичная, много ручного кода❌ Почти нет встроенной типизации
Производительность🚀 Хорошая, с кэшами и асинхронностью🚀🚀 Очень высокая (bitwise data + AoS/SoA)🐢 Средняя, ориентирована на удобство
Гибкость✅ Высокая (DI, сигналы, async, жизненный цикл, группы Систем)⚠️ Низкая, всё вручную✅ Средняя (удобные API, но не масштабная)
Асинхронность✅ Поддержка async-систем и очередей❌ Нет❌ Нет
DI / Signal system✅ Встроены❌ Нет❌ Нет
Жизненный цикл✅ Поддерживается (onInit, onDestroy)❌ Нет✅ Частично
Документация📘 Подробная📄 Минимальная📘 Хорошая
Идеально дляСредних/больших проектов, чистая архитектураМассивные симуляции, WebGL/3DПрототипы, обучение, простые игры
Кривая обучения⛰️ Средняя🧠 Сложная👶 Низкая

Комментарии по каждому

Empress Core

Прекрасно подойдёт для создания гибких и масштабируемых игр, в которых требуется поддержка асинхронных операций, сигналы и инъекция зависимостей. Ориентирован в первую очередь на удобную работу с архитектурой. И при этом является достаточно производительным, чтобы без пробелм реализовывать любые игровые механики.

bitecs

Невероятно быстрый и максимально data-oriented, почти как на C или Rust. Отличный выбор для создания игр в которых требуется рендеринг тысяч объектов. Но требует глубокого понимания низкоуровневого кода и управления памятью.

ecsy

Простой в использовании, удобен для обучения, является частью A-Frame (VR). Однако не предназначен для сложных или масштабируемых проектов, где важна гибкость и производительность.

Примеры кода

Empress Core

Создание Компонентов

export class Position {
constructor(public x = 0, public y = 0) {}
}

export class Velocity {
constructor(public x = 0, public y = 0) {}
}

Создание Сущности

const player = new Entity('player');

// Добавление Компонентов
player.addComponent(new Position(0, 0));
player.addComponent(new Velocity(1, 1));

Создание Систем

export class MovementSystem extends System<IUpdateLoopData> {
execute(data: IUpdateLoopData): void {
const entities = this.filter({
includes: [Position, Velocity]
});

entities.forEach(entity => {
const pos = entity.getComponent(Position);
const vel = entity.getComponent(Velocity);
pos.x += vel.x * data.deltaTime;
pos.y += vel.y * data.deltaTime;
});
}
}

Создание Груп Выполнения

class MovementGroup extends SystemGroup<IUpdateLoopData> {
public setup(chain: SystemChain, data: IUpdateLoopData): void {
chain.add(MovementSystem, data);
}
}

Инициализация игры и модулей фреймворка

// Создание и инициализация модулей ядра
const empress = new EnpressCore();
empress.init();

// Регистрация Сущностей в игре
const entityStorage = ServiceContainer.instance.get(EntityStorage);
entityStorage.add(player);

// Подпиика на события Сигналов для исполнения логики Систем в группах
const baseSignals: ISignalConfig[] = [
{
signal: OnUpdateSignal,
groups: [MovementGroup]
},
];
empress.listen(baseSignals);

// Запуск игры
empress.start();

bitecs

Создание Компонентов

const Position = defineComponent({ x: Types.f32, y: Types.f32 });
const Velocity = defineComponent({ x: Types.f32, y: Types.f32 });

Создание мира

const world = createWorld();

Создание Сущности

const player = addEntity(world);
addComponent(world, Position, player);
addComponent(world, Velocity, player);

Инициализация значений

Position.x[player] = 100;
Position.y[player] = 100;
Velocity.x[player] = 50;
Velocity.y[player] = 0;

Создание Систем

const moveQuery = defineQuery([Position, Velocity]);
function movementSystem(world, deltaTime: number) {
const entities = moveQuery(world);
for (let eid of entities) {
Position.x[eid] += Velocity.x[eid] * deltaTime;
Position.y[eid] += Velocity.y[eid] * deltaTime;
}
return world;
}

ecsy

Создание Компонентов

class Position extends Component {}
Position.schema = { x: { type: Types.Number }, y: { type: Types.Number } };

class Velocity extends Component {}
Velocity.schema = { x: { type: Types.Number }, y: { type: Types.Number } };

Создание Систем

class MovementSystem extends System {
execute(deltaTime: number) {
this.queries.moving.results.forEach(entity => {
const pos = entity.getComponent(Position);
const vel = entity.getComponent(Velocity);
pos.x += vel.x * deltaTime;
pos.y += vel.y * deltaTime;
entity.getMutableComponent(Position).x = pos.x;
entity.getMutableComponent(Position).y = pos.y;
});
}
}

MovementSystem.queries = {
moving: { components: [Position, Velocity] }
};

Инициализация мира

const world = new World();
world
.registerComponent(Position)
.registerComponent(Velocity)
.registerSystem(MovementSystem);

Создание Сущности

const player = world.createEntity();
player.addComponent(Position, { x: 100, y: 100 });
player.addComponent(Velocity, { x: 50, y: 0 });

Цикл игры

function gameLoop() {
const dt = 1 / 60; // 60 FPS
world.execute(dt);
}