Я собираюсь говорить с небольшим опытом, переходя от жесткого ОО-дизайна к дизайну Entity-Component-System (ECS).
Некоторое время назад я был таким же, как вы , у меня было множество разных типов вещей, которые имели схожие свойства, и я строил различные объекты и пытался использовать наследование для их решения. Очень умный человек сказал мне , не делайте этого, а вместо этого используйте Entity-Component-System.
Сейчас ECS - это большая концепция, и трудно понять, как правильно. В это входит много работы по правильному построению сущностей, компонентов и систем. Однако прежде чем мы сможем это сделать, нам нужно определить термины.
- Сущность : это вещь , игрок, животное, NPC, что угодно . Это вещь, которая нуждается в компонентах, прикрепленных к ней.
- Компонент : это атрибут или свойство , например «Имя», «Возраст» или «Родители», в вашем случае.
- Система : это логика компонента или поведения . Как правило, вы строите одну систему для каждого компонента, но это не всегда возможно. Кроме того, иногда системы должны влиять на другие системы.
Итак, вот где я хотел бы пойти с этим:
Прежде всего, создайте ID
для своих персонажей. Ан int
, Guid
что угодно. Это «Сущность».
Во-вторых, начните думать о различном поведении, которое у вас происходит. Такие вещи, как «Семейное древо» - это поведение. Вместо того, чтобы моделировать это как атрибуты объекта, создайте систему, которая содержит всю эту информацию . Затем система может решить, что с ней делать.
Точно так же мы хотим создать систему для "Живой или мертвый персонаж?" Это одна из самых важных систем в вашем дизайне, потому что она влияет на все остальные. Некоторые системы могут удалять «мертвые» символы (такие как система «спрайт»), другие системы могут внутренне переупорядочивать вещи, чтобы лучше поддерживать новый статус.
Например, вы создадите систему «Sprite», «Drawing» или «Rendering». Эта система будет отвечать за определение того, с каким спрайтом должен отображаться персонаж и как его отображать. Затем, когда персонаж умирает, удалите их.
Кроме того, система «ИИ», которая может сказать персонажу, что делать, куда идти и т. Д. Это должно взаимодействовать со многими другими системами и принимать решения на их основе. Опять же, мертвые персонажи могут быть удалены из этой системы, так как они больше ничего не делают.
Ваша система «Имя» и «Семейное древо», вероятно, должны сохранять персонажа (живого или мертвого) в памяти. Эта система должна вызывать эту информацию, независимо от состояния персонажа. (Джим все еще Джим, даже после того, как мы его похороним.)
Это также дает вам преимущество изменения, когда система реагирует более эффективно: система имеет свой собственный таймер. Некоторые системы должны срабатывать быстро, некоторые нет. Здесь мы начинаем понимать, что делает игру эффективной. Нам не нужно пересчитывать погоду каждую миллисекунду, мы можем делать это каждые 5 или около того.
Это также дает вам больше креативных рычагов: вы можете создать систему «Pathfinder», которая будет обрабатывать расчет пути от A-к-B, и может обновлять по мере необходимости, позволяя системе Movement сказать «куда мне нужно идти дальше? Теперь мы можем полностью разделить эти проблемы и более эффективно рассуждать о них. Движению не нужно искать путь, оно просто должно привести вас туда.
Вы захотите выставить некоторые части системы снаружи. В вашей Pathfinder
системе вы, вероятно, захотите Vector2 NextPosition(int entity)
. Таким образом, вы можете хранить эти элементы в строго контролируемых массивах или списках. Вы можете использовать меньшие struct
типы, которые помогут вам хранить компоненты в меньших, непрерывных блоках памяти, что может значительно ускорить обновление системы . (Особенно, если внешние воздействия на систему минимальны, теперь ей нужно заботиться только о ее внутреннем состоянии, например Name
.)
Но, и я не могу подчеркнуть это достаточно, теперь это Entity
просто ID
, включая плитки, объекты и т. Д. Если сущность не принадлежит системе, то система не будет отслеживать ее. Это означает , что мы можем создать «дерево» объектов, хранить их в Sprite
и Movement
системах (деревья не будут двигаться, но у них есть «Позиция» компонент), и держать их из других систем. Нам больше не нужен специальный список для деревьев, так как рендеринг дерева ничем не отличается от символа, кроме бумажного сглаживания. (То, что Sprite
система может контролировать, или Paperdoll
система может контролировать.) Теперь наша версия NextPosition
может быть слегка переписана: Vector2? NextPosition(int entity)
и она может вернуть null
позицию для объектов, которые ей не нужны. Мы также применяем это к нашему NameSystem.GetName(int entity)
, оно возвращается null
для деревьев и камней.
Я нарисую это к концу, но идея здесь , чтобы дать вам представление о ECS, и как вы можете действительно использовать это , чтобы дать вам лучший дизайн на вашей игре. Вы можете повысить производительность, отделить несвязанные элементы и поддерживать порядок в более организованном режиме. (Это также хорошо сочетается с функциональными языками / настройками, такими как F # и LINQ, которые я настоятельно рекомендую проверить F #, если вы этого еще не сделали, он очень хорошо сочетается с C #, когда вы используете их вместе).