0 Главная
Grigory a édité cette page il y a 6 ans

Добро пожаловать в вики Svelto.ECS!

Первый взгляд

Svelto.ECS — результат многолетних исследований и применения принципов SOLID в разработке игр на Unity. Это одна из многих реализаций паттерна ECS, доступная для C# с различными уникальными функциями, введенными для устранения недостатков самого паттерна.

Эта вики ни в коем случае не является заменой многих статей, написанных в моем блоге http://www.sebaslab.com/, но является их дополнением. Любой, кто хорошо понимает Svelto, может внести свой вклад в нее.

Самый простой способ увидеть основные возможности Svelto.ECS - загрузить Vanilla Example. Если вы хотите убедиться в простоте его использования, я покажу вам пример:

//Устанавливаем фреймворк
void ApplicationCompositionRoot()
{
    var simpleSubmissionEntityViewScheduler = new SimpleSubmissionEntityViewScheduler();
    _enginesRoot = new EnginesRoot(simpleSubmissionEntityViewScheduler);

    var entityFactory   = _enginesRoot.GenerateEntityFactory();
    var entityFunctions = _enginesRoot.GenerateEntityFunctions();

    _enginesRoot.AddEngine(new BehaviourForSimpleEntityEngine(entityFunctions));

    entityFactory.BuildEntity<SimpleEntityDescriptor>(new EGID(1), new[] 
	{
		new SimpleImplementor()
	});
}

//Определяем сущность
class SimpleEntityDescriptor : GenericEntityDescriptor<BehaviourEntityViewForSimpleEntity>
{
}

public class BehaviourEntityViewForSimpleEntity : EntityView
{
    public ISimpleComponent simpleComponent;
}

public interface ISimpleComponent
{
    public int counter {get; set;}
}

class SimpleImplementor : ISimpleComponent
{
    public int counter { get; set; }
}

//Определяем движок (систему) как поведение сущности
public class BehaviourForSimpleEntityAsStructEngine : IQueryingEntityViewEngine
{
    public IEntityViewsDB entityViewsDB { private get; set; }

    public void Ready()
    {
        Update().Run();
    }

    //Так выглядит цикл движка. 
	//Движок предназначен для обработки N сущностей, где N также может быть 0 и 1.
    IEnumerator Update()
    {
        Console.Log("Task Waiting");

        while (true)
        {
            var entityViews =
                entityViewsDB
                .QueryGroupedEntityViews<BehaviourEntityViewForSimpleEntity>(0);

            if (entityViews.Length> 0)
            {
                for (var i = 0; i < entityViews.Length; i++)
                    AddOne(entityViews[i].counter);

                    Console.Log("Task Done");

                    yield break;
            }

            yield return null;
        }
    }

    static void AddOne(int counter)
    {
        counter += 1;
    }
}

К сожалению, невозможно быстро понять теорию, лежащую в основе этого кода, который может выглядеть простым, но одновременно запутанным. Для понимания потребуется потратить время на чтение «стены текста» и опробовать приведенные примеры.

Введение

В последнее время я много обсуждал Svelto.ECS с несколькими, более или менее опытными программистами. Я собрал много отзывов и сделал много заметок, которые буду использовать в качестве отправной точки для своих следующих статей, где я буду больше говорить о теории и хороших практиках. Небольшой спойлер: я понял, что, когда начинаешь использовать Svelto.ECS, самое большое препятствие — смена парадигмы программирования. Удивительно, сколько я должен написать, чтобы объяснить новые концепции, представленные Svelto.ECS, по сравнению с тем небольшим количеством кода, написанного для разработки фреймворка. Фактически, в то время как сам фреймворк очень простой и облегченный, переход от ООП с активным применением наследования или обычных компонентов Unity, к «новому» модульному и слабосвязанному дизайну, который Svelto.ECS предлагает использовать, мешает людям адаптироваться к фреймворку.

Svelto.ECS активно используется в Freejam (прим. переводчика - Автор является техническим директором в этой компании). Поскольку я всегда могу объяснить коллегам основные концепции фреймворка, у них уходит меньше времени на понимание работы с ним. Хотя Svelto.ECS является настолько жестким, насколько это возможно, вредные привычки трудно побороть, поэтому пользователи склонны злоупотреблять некоторой гибкостью, позволяющей адаптировать фреймворк к «старым» парадигмам, с которыми им удобно. Это может привести к катастрофе из-за недопонимания или извращения концепций, лежащих в основе логики фреймворка. Вот почему я намерен написать как можно больше статей, тем более, что я уверен, что парадигма ECS - лучшее на данный момент решение, для написания эффективного и поддерживаемого кода для крупных проектов, которые меняются и переделываются по многу раз за несколько лет. Robocraft и Cardlife являются тому доказательством.

Я не собираюсь много говорить о теориях, лежащих в основе этой статьи. Я лишь напомню, почему я отказался от использования IoC контейнера и начал использовать исключительно ECS фреймворк: IoC контейнер - это очень опасный инструмент, если он используется без понимания самой сути инверсии управления. Как вы могли узнать из моих предыдущих статей, я различаю между собой инверсию управления созданием (Inversion of Creation Control) и инверсию управления потоком (Inversion of Flow Control). Инверсия управления потоком - это как принцип Голливуда: «Не звоните нам, мы позвоним вам». Это означает, что внедренные зависимости никогда не должны использоваться напрямую через публичные методы, так как при этом вы просто используете IoC контейнер в качестве замены любой другой формы глобальной инъекции, например синглтонов. Однако, если IoC контейнер используется по принципу Инверсии управления (IoC), то в основном всё сводится к многократному использованию паттерна “Шаблонный метод” для внедрения менеджеров, используемых только для регистрации объектов, которыми они управляют. В реальном контексте инверсии управления потоком менеджеры всегда отвечают за управление сущностями. Это похоже на паттерн ECS? Безусловно. Исходя из этого рассуждения я взял паттерн ECS и разработал на его основе жесткий фреймворк, и его использование равносильно применению новой парадигмы программирования.