Как игровой движок, который моделирует объекты как «наборы компонентов», работает во время выполнения? - PullRequest
4 голосов
/ 14 октября 2008

Я пишу облегченный игровой движок и, проводя некоторые исследования для него, я натолкнулся на ряд убедительных статей, пропагандирующих реализацию игровых объектов посредством модели «набора компонентов», а не «наследования от конкретных классов» модель. Есть много преимуществ:

  • объекты могут быть составлены с использованием данных управляемые методы проектирования, позволяющие дизайнеры, чтобы придумать новые объекты без участия программист;
  • там, как правило, меньше исходного файла зависимости, позволяющие коду быть компилируется быстрее;
  • двигатель в целом становится больше общий;
  • непредвиденные последствия необходимости изменить конкретные классы высоко иерархия наследования может быть избегать;
  • и т. Д.

Но есть части системы, которые остаются непрозрачными. Главным среди них является то, как компоненты одного и того же объекта взаимодействуют друг с другом. Например, скажем, объект, который моделирует пулю в игре, реализован в терминах этих компонентов:

  • немного геометрии для визуального представление
  • Положение в мире
  • объем, используемый для столкновения с другие объекты
  • другие вещи

Во время рендеринга геометрия должна знать свою позицию в мире, чтобы правильно отображать ее, но как она находит эту позицию среди всех своих родственных компонентов в объекте? И во время обновления, как объем столкновения находит положение объекта в мире, чтобы проверить его пересечение с другими объектами?

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

Ответы [ 7 ]

1 голос
/ 12 ноября 2008

Я всегда находил блог Кайла Уилсона интересным источником информации от того, кто работает с этим и, похоже, много об этом думает. Особенно эта запись может представлять интерес: http://gamearchitect.net/2008/06/01/an-anatomy-of-despair-aggregation-over-inheritance/. Это не ключевой момент статьи, но в основном он говорит о том, что они (при разработке ' Fracture ') имели отдельные иерархии. Один для GameObjects и SceneGraph для визуального представления. Лично я думаю, что это очень хороший дизайн, но я не эксперт в этой области.

1 голос
/ 04 ноября 2008

Я видел (и пытался) несколько способов реализовать это:

1) Компоненты не существуют в вакууме, но собираются в объекте «сущность» (или «игровой объект»). Все компоненты имеют ссылку на свою сущность, поэтому ваше столкновение может сделать что-то вроде GetEntity () -> GetComponent ("Position") -> GetCoords () (возможно, проверка на нулевые векторы и т. Д. - детали зависят от языка, который вы работает в).

В этом случае иногда бывает удобно поместить некоторую общую информацию непосредственно в сущность (позиция, уникальный идентификатор, статус «активный / неактивный») - существует компромисс между созданием чего-то «чистого» и родового, и сделать что-то быстрое и эффективное.

2) Нет сущности, есть только компоненты (я использую это для собственного легкого игрового движка). В этом случае компоненты должны быть явно связаны с другими компонентами, поэтому, возможно, ваши «столкновение» и «графика» будут держать указатель на «положение».

1 голос
/ 15 октября 2008

Еще одна веская причина для реализации этой стратегии - способность составлять поведение объекта из компонентов поведения, что позволяет вам повторно использовать поведение для нескольких игровых объектов.

Так, например, у вас есть базовый класс игровых объектов со следующими свойствами: горючий , подвижный , живой . По умолчанию каждый содержит ссылку на ноль. Если вы хотите, чтобы ваш объект горел, установите:

object.burnable = new Burnable(object);

Теперь, когда вы хотите сжечь объект, используйте:

if (object.burnable != null)
{
   object.burnable.burn();
}

И записываемое поведение изменит игровой объект так, как вы пожелаете.

1 голос
/ 14 октября 2008

Композитные архитектуры обычно полагаются на интерфейсы. В этом случае компонент представляет собой реализацию + данные, что позволяет разработчикам повторно использовать доступные реализации с различными данными. например использование кода ракеты один раз с изображением ракеты и один раз с изображением стрелки. Гибкость достигается за счет возможности «конфигурировать» такие комбинации вне фактического времени выполнения.

Во время выполнения объекты получают и предоставляют необходимую информацию через интерфейсы. Например, объект получит происхождение и направление ссылки позиционировать себя в мире. Для фактического рисования я бы предположил, что вокруг будет передан некоторый графический контекст, и инфраструктура позаботится о выравнивании смещения / проекции по умолчанию для текущего объекта.

0 голосов
/ 16 апреля 2011

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

Цель наличия основанного на компонентах приложения состоит в том, что вы можете добавлять и удалять компоненты в любое время во время выполнения и практически или вообще без связи; компоненты могут сосуществовать, даже не зная друг о друге.

Итак, как компонент "рендеринга" узнает, где он должен рендериться или хуже, что он должен рендерить? Мой ответ заключается в том, что каждый компонент-брат имеет доступ к общей таблице свойств, хранящихся в их контейнере (обычно это игровая сущность или игровой объект)

Например, предположим, что игровой объект с компонентом движения, компонентом рендеринга и компонентом персонажа

Компоненты рендеринга запрашивают в своем контейнере свойства с именами «positionx», «positiony» и «positionz» (если это 3D-игра), а затем запрашивают свойство «rendermodel». Исходя из этого, компоненты рендеринга отображают свойство, возвращаемое rendermodel в positionx, positiony и positionz. Свойства позиционирования изменяются компонентом движения, который сам запрашивает у контейнера свойство «скорость», которое, в свою очередь, настраивается компонентом символа на основе ввода с клавиатуры.

Если эти свойства не существуют, они создаются в момент их запроса и инициализируются действительным значением (например, 0).

На мой взгляд, компоненты никогда не должны запрашивать другие компоненты, так как они должны рассматриваться как максимально общие.

0 голосов
/ 14 октября 2008

Возможно ли вернуть объекту ссылку на объект Game?

Это позволило бы определить положение в мире, вернувшись к игровому объекту, а затем свернуть до положения в мире.

0 голосов
/ 14 октября 2008

Звучит немного перегружено; что вы получаете, делая местоположение абстрактным компонентом объекта вместо фундаментального свойства?

Но если вы действительно хотите сделать это таким образом, я думаю, вы могли бы установить граф зависимости, где все явно связано. Таким образом, (например) collision-volume имеет вход местоположения, который подключен к выходу компонента position. Взгляните на внутренности Майи, чтобы понять, как это может работать.

Но опять же, ИМХО, это выглядит как перебор.

...