Component
Описание
Модуль Component является одним из ключевых элементов ECS архитектуры EmpressCore. Он предоставляет механизм для создания и управления компонентами - объектами, которые хранят данные игровых сущностей.
Назначение
Решаемые проблемы
- Разделение данных и логики в игровых объектах
- Гибкое управление состоянием сущностей
- Эффективный поиск и фильтрация сущностей по их компонентам
Ключевые кейсы
- Хранение позиции, скорости, здоровья и других характеристик игровых объектов
- Включение/отключение определенных аспектов сущности
- Фильтрация сущностей для обработки в системах
Преимущества
- Чистое разделение данных и логики
- Гибкость в композиции сущностей
- Строгая типизация через TypeScript
- Эффективная система фильтрации
Ограничения
- Компоненты не могут содержать логику
- Один тип компонента может быть добавлен к сущности только один раз
Архитектура
Основные классы и типы
Component
- базовый тип для всех компонентовComponentType
- тип конструктора компонентаComponentsRaritySorter
- утилита для отслеживания частоты использования компонентов
Взаимодействие с другими модулями
Entity
- использует компоненты для хранения состоянияSystem
- обрабатывает сущности на основе их компонентов
Использование
Начало работы
Предварительные требования
- TypeScript версии 4.0 или выше
- Понимание принципов ECS
Основные сценарии
Создание компонента
- Определите класс компонента
- Добавьте необходимые свойства
- Реализуйте конструктор
Управление компонентами
- Добавление компонента к сущности
- Получение компонента из сущности
- Включение/отключение компонентов
Примеры
Простые примеры
Создание компонента позиции
// Определяем компонент позиции
export class Position {
constructor(
public x: number = 0,
public y: number = 0
) {}
}
// Создаем сущность и добавляем компонент
const entity = new Entity();
entity.addComponent(new Position(10, 20));
// Получаем и используем компонент
const position = entity.getComponent(Position);
console.log(position.x, position.y); // 10, 20
Включение/отключение компонентов
// Создаем сущность с несколькими компонентами
const entity = new Entity();
entity.addComponent(new Position());
entity.addComponent(new Velocity());
// Отключаем компонент скорости
entity.disableComponent(Velocity);
// Включаем его обратно
entity.enableComponent(Velocity);
Продвинутые примеры
Использование редкости компонентов
// Создаем несколько сущностей с разными компонентами
const entities = [
new Entity().addComponent(new Position()),
new Entity().addComponent(new Position()).addComponent(new Health()),
new Entity().addComponent(new Position())
];
// Проверяем частоту использования
console.log(ComponentsRaritySorter.rarity(Position)); // 3
console.log(ComponentsRaritySorter.rarity(Health)); // 1
// Сортируем компоненты по редкости
const sorted = ComponentsRaritySorter.sortByRarity([Position, Health]);
// sorted: [Health, Position] (от редких к частым)
API
Классы и типы
Component
type Component = object & { length?: never; constructor: any };
Базовый тип для всех компонентов. Не требует реализации интерфейсов.
ComponentType
type ComponentType<T extends Component> = new (...args: any[]) => T;
Тип конструктора компонента.
ComponentsRaritySorter
Класс для отслеживания частоты использования компонентов.
class ComponentsRaritySorter {
static increment(component: ComponentType<any>): void;
static decrement(component: ComponentType<any>): void;
static rarity(component: ComponentType<any>): number;
static sortByRarity(components: ComponentType<any>[]): ComponentType<any>[];
}
Частые вопросы
Можно ли добавить один и тот же компонент дважды?
Нет, каждый тип компонента может быть добавлен к сущности только один раз.
Можно ли добавить логику в компонент?
Нет, компоненты должны содержать только данные. Вся логика должна быть реализована в системах.
Как правильно организовать компоненты?
Создавайте маленькие, узкоспециализированные компоненты, каждый из которых отвечает за один аспект состояния сущности.