Обновления объектов, внутренние и внешние?


8

Название немного сбивает с толку, но я не могу понять, как объяснить мой вопрос в короткой фразе. Итак, вот оно:

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

Вот простой пример: перемещение вещей. Должен ли каждый объект видеть окружающий его мир (проверять наличие столкновений) и двигаться на основе этого.

[обратите внимание, что это игра на основе тайлов, в которой объекты перемещаются за плитку, поэтому я не использую физику для перемещения от тайла к тайлу]

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            if (world.getTile(location) != solid && world.objAtTile(location) == null)
            {
                Tweener.addTween(this, location);
            }
          }
        }

Или движение каждого объекта должно управляться в мире, где мир все проверяет?

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            world.moveTo(location);
          }
        }

public class World
{

    public void moveObject(GameObject obj, Vector2 location)
    {
      //called from object

      if (getTile(location) != solid && objAtTile(location) == null)
         {
                Tweener.addTween(obj, location);
         }
    }
}

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


1
Больше к вопросу, должны Actorзнать о worldвообще?
замедленная

1
Я думаю, что вы смешиваете Объекты с Компонентами, и это сбивает с толку вопрос о том, кто что делает. Это может быть семантическая проблема, так как компонент является сильно перегруженным термином. Я думаю, что если вы поясните, что такое Объект, что вы имеете в виду под Компонентом и как вы организовываете небольшие движки, которые фактически выполняют работу, то вы можете ответить на свой собственный вопрос.
Патрик Хьюз

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

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

@daniel Актеры, несомненно, должны быть осведомлены об окружающем их мире, чтобы эффективно двигаться, хотя я бы обычно проектировал контейнер, в котором заключены оба, но никто не знает об этом. например. Мир содержит и Актера и Уровень; Актер знает об Уровне (или, скорее, ему сообщают об Уровне, когда это необходимо, но не постоянную ссылку), но не о Мире.
Джоккинг

Ответы:


2

Я вижу, что ваши примеры написаны на Java, но в ваших тегах не указан язык. В C ++ ответ ни один - вы не должны использовать функцию-член для этого!

void move_to(actor *a, world *w, vec2 location);

4
Должен сказать, огромный поклонник книг, которые написал автор статьи. Однако, насколько я могу судить, аргументация статьи - хорошая теория, а не практический код. Вынося подобные методы из объектов, к которым они относятся, вы добавляете больше мест для поиска функциональности, относящейся к ним, которая только вызывает путаницу и повышает уровень необходимого обслуживания. Просто мой взгляд на это, поэтому нет + или -. Всего два цента.
Джеймс

1
Кроме того, нужно сказать, что выглядит как C # с наследованием, используя: ClassName вместо extends ClassName.
Джеймс

Это псевдокод, основанный на C #, но это не должно относиться к моему вопросу :)
omgnoseat

1
@omgnoseat: Это важно, потому что совет невозможен на языке без голых функций, а его полезность снижается на любом языке без ADL. Хорошая архитектура не зависит от выбора языка.

2
@James: Нет ничего не оО в голых функциях, если сами функции вызывают методы, которые следуют принципам разработки ОО. В этом суть статьи. (OO также не является синонимом хорошего дизайна. Если ясный или простой дизайн требует, чтобы вы не использовали OO, канаву OO, а не дизайн.)

1

Там нет простого ответа.

Как и в большинстве вещей в программировании, это компромисс. Предоставление большей мощности отдельным объектам делает их больше - и, следовательно, медленнее - но облегчает понимание и расширение двигателя. Наличие мега-класса, который может обрабатывать все вместе, может быть быстрее, но за счет наличия мега-класса; то есть вообще считается плохой формой делать сверхмассивные занятия.

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

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


Вы несколько недооцениваете вещи, говоря, что стиль разработки компонентов и данных, который вы описали, «винтик со всей суть ОО» - это вовсе не ОО . По крайней мере, как описано в «Entity Systems - это будущее разработки MMOG» (ссылка на него приведена в ответе pek), Entity Systems - это совершенно другая парадигма программирования, и если вы обнаружите, что пытаетесь сделать свои компоненты или объекты OO выходящими за рамки простого удобства упаковки, вы ' делать это неправильно.
Дейв Шерохман

6
Они идеально ориентированы на объект. Это просто не ОО, к которому привыкло большинство людей, но это нормально. Ориентация объекта заключается в соединении состояния с методами, которые работают с этим состоянием, вот и все. Не требуется, чтобы каждый объект был реальным объектом или чем-то подобным.
Kylotan

@Kylotan: Опять же, я говорю конкретно о моделях, таких как описанные в «Entity Systems - будущее разработки MMOG», где компоненты - это глупые данные, управляемые внешними «системами». Они не являются объектами, поскольку у них нет поведения / методов; это отношения (например, строки базы данных или структуры C). Ошибочная эквивалентность между ООП и повседневным использованием «объекта» не имеет к этому никакого отношения. Из части 3: «Я категорически против использования ООП где-либо в реализации ES; слишком легко скрыть некоторые ООП туда, где это неуместно, и обмануть себя, думая, что это хорошая идея».
Дейв Шерохман

Мне известна эта статья, но это всего лишь мнение одного человека о том, как эти вещи должны быть выполнены - это не стандартный способ или не обязательно лучший способ, поэтому неверно говорить, что компонентно-ориентированный дизайн - это совсем другое парадигма программирования. Вполне возможно - и гораздо более распространено - реализовать компонентную архитектуру с помощью ОО-кода, и использование ОО-кода никоим образом не наносит ущерба ее «компонентности» больше, чем использование хранимых процедур повреждает реляционный аспект базы данных. ,
Kylotan

@ Дэйв, этот вопрос ни в коем случае не касается систем сущностей-компонентов. Ни ES, ни управляемый данными дизайн не являются OO, это распространенная, но большая ошибка, чтобы предполагать это. Если вы заглянете в Google, вы найдете несколько хороших статей, раскрывающих этот миф. Тем не менее, этот вопрос касается общих ОО-принципов проектирования ваших объектов, шаблоны проектирования более высокого уровня вообще не отвечают на этот вопрос.
Майк Земдер

0

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

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

Таким образом, если мир должен управлять всем, это означает, что у него низкая сплоченность и тесная связь (потому что он должен знать и делать все). Однако это также тот случай, когда игровой объект должен делать все. Обновить его местоположение, визуализировать его текстуру и т. Д. И т. Д.

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

Если пойти немного дальше, игровая сущность - это просто мешок свойств. Этими свойствами управляют системы, ориентированные на конкретные свойства. И именно здесь вступают в действие системы сущностей на основе компонентов (CBES), где свойства = компоненты.

В частности, CBES с системами (или подсистемами). Этот дизайн имеет тенденцию иметь несколько систем, которые ориентированы на конкретные компоненты объекта, не заботясь о том, какие другие компоненты есть у объекта. Кроме того, Системы связаны только с информацией, которая им необходима для обработки этих компонентов.

Давайте возьмем ваш пример. Так как ввод, куда перемещать объект, основан на контроллере игрока, у вас, вероятно, будет PlayerControllerSystem. Эта система, помимо всего прочего, будет контролировать PositionComponent объекта. В этом случае PlayerControllerSystem необходимо знать об уровне и PositionComponent. Если позже вы решите добавить обнаружение столкновений, вы создадите систему CollisionSystem, которая снова будет использовать положение сущностей, но на этот раз для вычисления ограничивающих рамок (или вы можете иметь BoundingBoxComponent, ваш вызов). Дело в том, что вы можете легко включать и выключать поведение (даже на лету), просто добавляя / удаляя компоненты. Таким образом, большее поведение означает, что больше систем манипулируют компонентами сущности, но все они находятся в четко определенном классе с низкой связью. Хотите сценарии? Добавьте ScriptComponent. BAM! Вы только что добавили возможности сценариев с 2 классами. Физика? Звук? Опять то же самое.

Итак, причина, по которой я защищаю CBES с подсистемами, заключается в том, что это идеально ОО и в целом простая в обслуживании / расширяемая система. Добавить поведение к объекту так же просто, как решить, какие данные нужны этому поведению и какие объекты нужны.

Для получения дополнительной информации о Компонентных Entity Systems с Подсистемами, есть отличная серия постов в блоге от T = Machine на Entity Systems - будущее разработки MMOG . Автор даже дошел до создания вики для сбора различных реализаций под названием Entity Systems Project.

Общим (и хорошо известным) постом о компонентных системах сущностей в целом является Evolve, ваша иерархия , создавшая систему для Tony Hawk Pro.

Наконец, если вы ищете библиотеку с примером кода, не идите дальше, чем библиотека Artemis . Артемида в основном на Java, но здесь есть порт на C # (который я сейчас использую в своем проекте XNA).


2
-1, так как это не решает проблему, просто перемещает ее. У него все еще не будет четкого ответа относительно того, какой объект принимает решение, состоит ли он из компонентов или нет.
Kylotan

1
Вторая ссылка содержит обширное руководство о том, почему поведение игровых сущностей должно быть перенесено в Entity Systems. Артемида следует точно такой же архитектуре.
Пек

Вторая ссылка является частью мнения. Многие предпочитают компоненты, но они не являются решением всех проблем, и они определенно не имеют внутреннего решения этой проблемы.
Kylotan

Ответ на этот вопрос, получивший наибольшее количество голосов, звучит так: «Простого ответа не существует. Как и в большинстве случаев в программировании, это компромисс». Вторая ссылка предоставляет одно из многих решений. На самом деле, он выступает за полную противоположность этого ответа. Возможно я должен отредактировать свой ответ, чтобы сделать его более ясным. Но опять же, возможно, это не изменит отрицательных голосов: P
pek

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

0

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

class World {
  var walls = [];
  var actors = [];
  function update() {
    for each (actor in actors) {
      actor.update(walls);
    }
  }
}

class Actor {
  function update(walls) {
    this.move();
    for each (wall in walls) {
      this.collide(wall);
    }
  }
}

0

Держи это сухим, застенчивым и скажи другому парню.

Лучше попросить мир переместить своего актера, чем спросить мир, можете ли вы переместиться туда, куда вы хотите. Таким образом, вы можете легко изменить алгоритм поиска пути в мировом классе и тому подобное. Конечно, вы можете просто оставить это до базового класса для актера, но я бы выбрал направление и причину.


-1

РЕДАКТИРОВАТЬ: переписано из-за обратной связи, заявив, что я не сделал достаточно четкую линию для этого ответа на исходный вопрос.

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

Мой простой ответ высокого уровня - сохранить всю логику, которая воздействует на объект внутри этого объекта.

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

Для решения основной части вопроса и достижения долговечности дизайна я бы предложил компонентно-ориентированную архитектуру. Компонентные архитектуры разбивают объект на отдельные наборы данных и функциональные возможности (при условии, что вы ответите на мой ответ выше, в котором говорится, что логика должна соответствовать данным). Если ваша структура выглядит как CEntity-> CHuman-> CSoldier-> CPlayerCharacter, то вы неизменно будете сталкиваться с проблемами, когда вам нужно изменить какую-то логику и в зависимости от того, куда она идет в этом дереве (например, сколько других типов людей существует?) это может иметь огромное влияние на несколько типов объектов.

Вместо этого система компонентов будет иметь набор интерфейсов, которые определяют, из чего состоит объект CEntity, таких как ICompRenderable, ICompMoveable, ICompHealth, ICompInventory и так далее. Где вы должны иметь CCompMoveableHuman и, возможно, CCompMoveableSoldier и CCompMoveablePlayer, чтобы разделить их отдельные шаблоны движения. Так скажем, Солдат переделан, чтобы бежать в строю. Это изменение повлияет только на объекты, созданные с использованием этого компонента.

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

Надеюсь это поможет.


Я изучал шаблон компонентов последние пару часов. (ссылки Пека очень хороши). Но до сих пор не ясно, где должно происходить реальное «поведение». Понятно, что у сущности есть разные компоненты для ввода, рендеринга, физики. Но, если я правильно понял, компоненты содержат только данные, необходимые для работы, но на самом деле не содержат реализацию. Давайте снова вернемся к перемещению: как мне заставить объект двигаться с использованием компонентов? Должен ли я расширить входной компонент и кодировать реализацию там? Или что-то еще управляет реализацией?
omgnoseat

Для меня я сохраняю логику в объектах, но на самом деле я делаю систему компонентов поверх Data Oriented Design, а это означает, что большинство моих объектов на самом деле просто логика, которые в любом случае отображаются на места внутри данных для непрерывной быстрой обработки ... И в конце дня выучите по одному шаблону дизайна за раз: D Что касается -1, буду признателен, если узнает, почему это так помечено, даже если это просто «мне больше нравится мой ответ», я все равно хотел бы знаю, почему.
Джеймс

1
@ Джеймс, достаточно справедливо. Я понизил голос, потому что системы компонентов не отвечают на первоначальный вопрос. Компонент позиции все еще может перемещаться сам, или мир может перебирать все компоненты позиции и перемещать их. По той же причине Килотан отказался от ответа Пека, поэтому я подумал, что причина -1 очевидна. И даже если компонентная система будет вынуждена перемещаться сама по себе (а это не так), она все равно не будет ответом, а лишь вариантом использования 1 из опций. Но вопрос был о причинах использования того или другого, их плюсах и минусах. Ответ не распространяется на это.
Майк Земдер

@Maik Semder. Спасибо за ответ. Я переписал ответ, чтобы попытаться более четко обозначить начальный вопрос и общее стремление к нему в первую очередь, как указано в конце вопроса.
Джеймс

@James, спасибо, что нашли время отредактировать ответ в ответ на мой комментарий, очень признателен. Предложенный ответ «сохранить всю логику, которая действует на объект в этом объекте», побеждает основную особенность ОО, а именно инкапсуляцию. Как показывает ссылка Джо, использование не связанных друг с другом функций, не являющихся членами, повышает уровень инкапсуляции объекта. Кроме того, он вводит четкий метод, как на самом деле измерить инкапсуляцию. Помещение функции перемещения в мир или действующее лицо уменьшает инкапсуляцию проекта, в результате чего код становится менее гибким и сложным в обслуживании.
Майк Земдер

-1

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

AltDevBlogADay имеет довольно много сообщений об этом, очень хороший, являющийся этой серией о игровых объектах: http://altdevblogaday.com/2011/07/10/the-game-entity-–-part-ia-retrospect/ Есть несколько частей, посвященных проблеме, которую вы пытаетесь решить.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.