@toster_bodnar

Как организовать Tween систему в рамках ECS (entt)?

Возникла потребность в tween системе для игры. Почти вся логика в игре завязана на ecs. Использую библиотеку entt.
Идея появилась следующая: Сделал компонент с данными о твине.
struct TweenComponent
{
    EasingType type;
    float delay;
    float fromValue;
    float toValue;
    float duration;
};


И накидал примерную часть системы, которая будет обрабатывать сущности, на которые был навешан компонент.
void update(entt::registry& registry, float dt)
{
    auto view = registry.view<TweenComponent>();
    for(auto entity: view)
    {
        auto tween = registry.get<TweenComponent>(entity);
        ...
    }
}


Там где многоточие, я планировал реализовать логику изменения параметра в зависимости от функции интерполяции, которая выбрана в компоненте. Но тут как раз и непонимание. Как универсально сделать передачу через компонент нужного параметра, к которому будет применяться твин анимация? И сразу появилась проблема с тем, что на сущность мы можем навесить только один TweenComponent. А как быть с тем, что нужно будет анимировать сразу несколько параметров (например позицию и цвет)? В общем такая архитектура применения tween анимации как то не очень..
Может кто в курсе как лучше реализовать эту систему в рамках ecs?

Были мысли делать на каждый параметр сущности, который нужно анимировать, свой tween компонент (PositionTweenComponent, ColorTweenComponent). А потом в системе делать выборки по сущностям каждого типа. Так мы сразу будем понимать, какой параметр нужно доставать из какого компонента.
Еще были идеи передавать в TweenComponent в качестве одного из параметров некий handle, в котором описывать нужные действия над нужным параметром других компонентов. В общем подскажите пожалуйста, как это делается?
  • Вопрос задан
  • 177 просмотров
Решения вопроса 1
@MarkusD Куратор тега C++
все время мелю чепуху :)
Одним компонентом и одной системой в таком случае не обойтись. Когда затронуто произвольное количество иных компонентов, связывать их все с каким-то одним компонентом - это зарывать ECS обратно в землю.

Почему дизайн с одним компонентом обречен. Каждая система в ECS должна работать с выборкой по компонентам. В EnTT это делается с помощью представления потока компонентов - entt::registry::view.
Такое представление оптимальным образом организует последовательность сущностей, в которых точно присутствуют обозначенные в представлении компоненты. Если начать проверять наличие у сущности иных компонент, помимо того что это противоречит концепции ECS, это затронет выборку из памяти за пределами отображения и сильно снизит производительность системы. Поэтому системе не стоит работать с компонентами за пределами своей выборки.

По дизайну ты хочешь сделать систему, которая будет интерполировать произвольные значения произвольных полей произвольных компонент используя данные одного конкретного компонента. Такой дизайн приведет тебя только к тому, что в этой системе тебе придется делать выборку по всем компонентам, что, собственно, сделает эту систему дисфункциональной. Это просто потому что далеко не все сущности, значения компонентов которых тебе захочется интерполировать, будут обладать всеми другими компонентами, значения которых система тоже может интерполировать.

Как быть в таком случае. Нужно выделять функциональность в более локальные системы вместо одной большой системы интерполяции. Вот есть у тебя компонент цвета сущности - ColorComponent, и этот цвет у тебя может интерполироваться. Значит тебе нужен компонент интерполируемости цвета - ColorInterpolationComponent. В этом компоненте интерполируемости нужно определить закон интерполяции, начальное и конечное значение, а так же время интерполяции. ColorInterpolationComponent говорит о том, что все данные ColorComponent интерполируются по определенному закону между определенными значениями и за определенное время.

Функции интерполяции у тебя всегда чистые, т.е. зависят только от переданных им аргументов. Для любого типа данных, от скаляра и до матрицы, можно определить функцию интерполяции между двумя значениями. Это все - внешние относительно ECS вещи, а внутри ECS на каждый ***InterpolationComponent у тебя будет своя система, которая делает выборку по целевому компоненту и по компоненту интерполируемости. Таким образом, уже на стадии выборки компонентов у тебя останутся только подходящие сущности, а все остальные - отфильтруются.
Заметить стоит еще то, что такой подход позволяет одно конкретное значение интерполировать только одной функцией за раз. Если для одного значения требуется несколько одновременных интерполяций, такой подход уже не подходит. С другой стороны, для того чтобы правильно свести несколько таких анимаций для одного значения, требуется значительно более сложная система, чем просто функция интерполяции.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы