ECS с Go - круговой импорт
Я изучаю как Go, так и Entity-Component-Systems. Я понимаю, как работает ECS, и я пытаюсь воспроизвести то, что кажется документом ECS, а именно http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/
Для обеспечения эффективности документ рекомендует использовать статические массивы каждого типа компонентов. То есть не массивы компонентных интерфейсов (массивы указателей). Проблема с этим в Go заключается в круговом импорте.
У меня есть один пакет, ecs, который содержит определения для типов / интерфейсов Entity, Component и System, а также EntityManager. Другой пакет, ecs / components, содержит различные компоненты. Очевидно, пакет ecs / components зависит от ecs. Но, чтобы объявить массивы определенных компонентов в EntityManager, ecs будет зависеть от ecs / компонентов, поэтому создается циклический импорт.
Есть ли способ избежать этого? Я знаю, что обычно система высокого уровня не должна зависеть от систем более низкого уровня. Я также хочу отметить, что использование массива указателей, вероятно, достаточно быстро для моих целей, но меня интересуют возможные обходные пути (для дальнейшего использования)
Спасибо за помощь!
1 ответ
Для обеспечения эффективности документ рекомендует использовать статические массивы каждого типа компонентов.
Я просто начну с того, что скажу, что могу быть слепым, но я несколько раз прочитал этот документ и не увидел ничего похожего на это. (Конечно, некоторые оптимизации могут быть сделаны таким образом в отношении таких вещей, как предотвращение промахов кэша, но я сомневаюсь, что это в любом случае перевешивает служебные расходы).
Существует простой ответ на точный вопрос, который вы задали в первую очередь, .
Импортировать. Любой пакет с оператором импорта, например import . "some/other/package"
будет обрабатывать содержимое этого пакета как свое собственное, игнорируя циклические зависимости. Не делай этого.
К сожалению, без объединения пакетов вы не сможете сделать это (я имею в виду без использования интерфейсов). Не бойся, хотя. В статье, которую вы опубликовали, об этом говорится в разделе "Детали реализации".
Предоставление каждому компоненту общего интерфейса означает вывод из базового класса с виртуальными функциями. Это вводит некоторые дополнительные издержки. Не позволяйте этому повернуть вас против идеи, поскольку дополнительные накладные расходы малы по сравнению с экономией за счет упрощения объектов.
Это прямо говорит вам использовать интерфейсы (хорошо, виртуальное наследование C++, но достаточно близко). Это нормально, это необходимо. Особенно, если вы хотите два слегка отличных компонента ИИ или что-то еще, тогда это просто находка.