Спасибо, простым языком о сложном. Но тем не менее, не уверен, что я всё понял.
Я так понимаю, что вместо одного метода DealDamage(20), мы теперь:
- создаем компонент DamageEvent с параметром int hp
- когда хотим нанести вред игроку, спавним этот компонент на его сущности и выставляем параметром 20 хп
- система Health в Run() гуляет по EcsFilter<DamageEvent>, вызывает на ентити Get<HP> и там вычитает 20, а потом убирает компонент DamageEvent с сущности.
Я правильно понял? Жесть конечно.
А если надо, чтобы метод DealDamage(20) что-то возвращал, то после вычета хп, система Health должна создать какой-то евент в ответ, так что ли?
При этом если у нас много разных евентов в одной системе, то этот Run() начнет разрастаться, в итоге мы его порубим на кучу функций, и в итоге Run() будет выглядеть как длинный список if(...) method(), else if(...) method(), else if(...) method(), что не добавляет читаемости. Выйдет что-то типа когда по сокету получаешь сообщение и у тебя огромный switch case на тип сообщения. И еще похожее в плане кучи кода видел в Defold, где нельзя вызывать напрямую методы классов, можно лишь посылать сообщения, а объект класса увидев это сообщение сам нужный метод вызовет. Вот такое же ощущение от ЕЦС. Перекладывание из одного кармана в другой, потом третий, потом чертвертый. Хотелось бы когда-нибудь пощупать, но задач таких не встречал.
Попробуй посмотреть исходный код Terasology, технодемо в стиле Minecraft на языке Java. Это п*здец. Модульность ради модульности. Посмотри как в ходе программирования они добавляли стрижку овце - отдельные правки в модуле Pathfinding, отдельные правки в модуле Wildanimals, Behaviors и т.п.
И еще. Ведь если мы фактически вызываем методы в системах посредством постоянного добавления компонентов (евентов) на сущности, архетипам-то в итоге от этого плохо не становится? Сущности же нонстоп из архетипов должно выбивать.
Одна из существенных причин перехода в том, что MonoBehavior и многое, связанное с ним, не являются потокобезопасными. Все действия с MonoBehavior, соответственно, выполняются в основном потоке выполнения Unity. И это никак не обойти, хоть даже если свой контекст для потоков написать. И тут целый гигантский пласт задач, которые нельзя распараллелить. В моём случае, это касается генерации во время выполнения десятков тысяч объектов и обеспечение их поведения. С ECS многократно ускоряется и генерацию и последующая работа. В тех же самых игрушках на Unity. Пример, загрузка уровня с прогресс баром. Если надо сделать, чтобы всё намертво не зависало, пока уровень не загрузится, , т.е. не в основном потоке грузить, то приходится использовать корутины (асинки, и даже если создавать новый поток), то на самом деле всё это работает неоптимально. А почему? Да потому что основная работа делается в основном потоке, всё равно. В одном. Тут во многих случая псевдо-параллелизм. А сам подход к ECS, тут не только новые функции, но и переделка самого движка. Если традиционный движок по сути - однопоточный, то при ECS всё ориентировано на многопоточность.
Спасибо, простым языком о сложном. Но тем не менее, не уверен, что я всё понял.
Я так понимаю, что вместо одного метода DealDamage(20), мы теперь:
- создаем компонент DamageEvent с параметром int hp
- когда хотим нанести вред игроку, спавним этот компонент на его сущности и выставляем параметром 20 хп
- система Health в Run() гуляет по EcsFilter<DamageEvent>, вызывает на ентити Get<HP> и там вычитает 20, а потом убирает компонент DamageEvent с сущности.
Я правильно понял? Жесть конечно.
А если надо, чтобы метод DealDamage(20) что-то возвращал, то после вычета хп, система Health должна создать какой-то евент в ответ, так что ли?
При этом если у нас много разных евентов в одной системе, то этот Run() начнет разрастаться, в итоге мы его порубим на кучу функций, и в итоге Run() будет выглядеть как длинный список if(...) method(), else if(...) method(), else if(...) method(), что не добавляет читаемости.
Выйдет что-то типа когда по сокету получаешь сообщение и у тебя огромный switch case на тип сообщения. И еще похожее в плане кучи кода видел в Defold, где нельзя вызывать напрямую методы классов, можно лишь посылать сообщения, а объект класса увидев это сообщение сам нужный метод вызовет. Вот такое же ощущение от ЕЦС. Перекладывание из одного кармана в другой, потом третий, потом чертвертый. Хотелось бы когда-нибудь пощупать, но задач таких не встречал.
Попробуй посмотреть исходный код Terasology, технодемо в стиле Minecraft на языке Java.
Это п*здец. Модульность ради модульности.
Посмотри как в ходе программирования они добавляли стрижку овце - отдельные правки в модуле Pathfinding, отдельные правки в модуле Wildanimals, Behaviors и т.п.
И еще. Ведь если мы фактически вызываем методы в системах посредством постоянного добавления компонентов (евентов) на сущности, архетипам-то в итоге от этого плохо не становится? Сущности же нонстоп из архетипов должно выбивать.
Одна из существенных причин перехода в том, что MonoBehavior и многое, связанное с ним, не являются потокобезопасными. Все действия с MonoBehavior, соответственно, выполняются в основном потоке выполнения Unity. И это никак не обойти, хоть даже если свой контекст для потоков написать. И тут целый гигантский пласт задач, которые нельзя распараллелить.
В моём случае, это касается генерации во время выполнения десятков тысяч объектов и обеспечение их поведения. С ECS многократно ускоряется и генерацию и последующая работа.
В тех же самых игрушках на Unity. Пример, загрузка уровня с прогресс баром. Если надо сделать, чтобы всё намертво не зависало, пока уровень не загрузится, , т.е. не в основном потоке грузить, то приходится использовать корутины (асинки, и даже если создавать новый поток), то на самом деле всё это работает неоптимально. А почему? Да потому что основная работа делается в основном потоке, всё равно. В одном. Тут во многих случая псевдо-параллелизм.
А сам подход к ECS, тут не только новые функции, но и переделка самого движка. Если традиционный движок по сути - однопоточный, то при ECS всё ориентировано на многопоточность.