Pull to refresh

Формат описания Компонентов и Префабов (Entity) для ECS. Часть 1. Спецификация

Level of difficultyEasy
Reading time3 min
Views1.3K

Привет, читатель! В этой статье не будет практики, а только спецификация формата и примеры для его объяснения. Код парсера будет в следующей части статьи!

Что такое ECS

ECS - Entity Component System (Сущности Компоненты Системы), это распространённый паттер программирования игр, используемый для упрощения разработки. В этом паттерне есть 3 определения:

  • Entity (Сущность) - контейнеры, хранящие в себе Компоненты (Данные). Сами не хранят свойства.

  • Component (Компонент) - классы/структуры, хранящие в себе всевозможные данные, нужные для игровой логики (Систем).

  • System (Системы) - Логические ядра игры. Они манипулируют сущностями и данными внутри них. Чаще всего реализуются классами

Если же вы хотите разобраться в теме подробнее, предлагаю вам вот эту статью.

Хочу отметить, что в Формате будет возможно описывать только ПЕРВЫЕ два определения, так как для описания игровой логики нужен язык программирования, а это задача сложная.

Зачем?

"Зачем?" - задаст вопрос читатель. И я отвечу - упрощение. Вот пример объявления компонента во ECS-фреймворке BrokenBricksECS:

namespace ECSExample {
    [Serializable]
    public struct FloatComponent : IComponent {
        public float value;
 
        public FloatComponent(float value) {
            this.value = value;
        }
    }
 
    public class FloatDataComponent : ComponentDataWrapper<FloatComponent> { }
}

Сначала мы здесь должны создать структуру, внутри которой будет значения и конструктор. Потом мы создаем FloatDataComponent. Это обёрнутый в ComponentDataWrapper FloatComponent. Разве это нужно?

Решение

Для этого я предлагаю создать формат описания компонентов и прототипов сущностей (префабов). И все что мне пришло на ум, так только это.

@component Component1 {
  value: int,
}
@component Comp2(Component1) {
  value2: str = "default_value" # Будет иметь value: int и value2: str
} # Родитель - Component1

Используя ключевое слово @component, мы создаем новый компонент. Внутри фигурных скобок типы объявляются так: <name>: <type>, также можно указать дефолтное значение <name>: <type> = <value>

Комментарии начинаются с символа решётки # Комментарий

Наследование компонентов?

Компоненты могут наследоваться друг от друга. Это делается так:

@component <name>(<parent>) {
  data_from_parent,
  ...,
  new_and_overriden_data
}
# Пример
@component Component1 {
  value: int,
}
@component Comp2(Component1) {
  value2: str = "default_value" # Будет иметь value: int и value2: str
} # Родитель - Component1

Множественного наследования формат не поддерживает, так как есть проблема ромба.

Хочу заметить, ради оптимизации компоненты при наследовании просто сливаются.

Прототипы сущностей (Префабы)

А тут, во время написания, мне приходит мысль? А почему бы и не добавить в формат описание сущностей! И я добавил их:

@entity Name {
  Component1(value=10)
}
@entity Name2(Name) {
  Comp2(10, 'default_value')
}
@entity Name3 { # Равен Name
  Component1(10),
  Comp2(value=10)
}

Используя ключевое слово @entity <name>, мы создаем новый прототип сущности. Внутри фигурных скобок компоненты добавляются так: <name>(<value>, <field_name>=<value>)

Наследование же работает также, как у компонентов.

Итог

Итого, у нас есть вот такой example-файл:

@component Component1 {
  value: int,
}
@component Comp2(Component1) {
  value2: str = "default_value" # Будет иметь value: int и value2: str
} # Родитель - Component1
@entity Name {
  Component1(value=10)
}
@entity Name2(Name) {
  Comp2(10, 'default_value')
}
@entity Name3 { # Равен Name
  Component1(10),
  Comp2(value=10)
}

В следующей части я напишу парсинговый механизм для этого формата. Удачи!

Tags:
Hubs:
Total votes 2: ↑1 and ↓10
Comments14

Articles