Вопросы по архитектуре игр с XNA

12

Итак, я наконец-то нашел время поиграть с XNA и занялся созданием 2D-игры (у меня есть куча художественных ресурсов от друга, который разработал его для iOS)

Многие вещи кажутся легкими для выполнения и выходят из коробки, однако я остаюсь в тупике из-за множества вещей, так как большая часть литературы (например, книги, которые я купил) не уделяет слишком много внимания 2D.

Буду очень признателен за любые разъяснения или указание на дополнительную информацию о следующих квестинах:

  1. В чем смысл игрового сервиса? Я понимаю всю идиому регистрации объекта в качестве службы, чтобы любой другой GameComponent мог его захватить, но как это превзойти, просто сделав его публичным или статичным? Например, моя книга рекомендовала зарегистрировать объект SpriteBatch в классе Game.cs. Я не уверен, насколько это предпочтительнее, чем просто сделать его публичным / статическим, поскольку в любом случае должен быть только один экземпляр Game (синглтон)?

  2. Я запутался, когда мне следует наследовать от GameComponent или RenderableGameComponent. Я пытаюсь следовать дизайну диспетчера / контроллера, чтобы все сущности создавались / принадлежали одному менеджеру и одинаково для других вещей. В настоящее время у меня есть каждый диспетчер / контроллер, унаследованный от GameComponent, однако, как это превосходит, если объект Game владеет всеми менеджерами и вручную вызывает update для них и рисует?

  3. Я заметил, что Initialize вызывается до ContentLoad (), я обнаружил, что это раздражает, поскольку в моей Initialize я хотел бы создать некоторые из своих сущностей (например, Sprite, Player и т. Д.), Однако я не могу дать им их загруженные SpriteSheets или Textures, поскольку вызов для их загрузки еще не произошел. Возможно, я неправильно инициализирую или люди просто назначают текстуру ниже в ContentLoad?

Похоже, это мой самый большой " WTF " не совсем понимающий

Setheron
источник

Ответы:

11

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

Чтобы ответить на первый вопрос, я отошлю вас к моему ответу на вопрос «Зачем пользоваться услугами?» , Короткий ответ заключается в том, что сервисы - хороший способ избежать сопряженных проблем (управление версиями, зависимость, расширяемость), с которыми вы никогда не столкнетесь в автономной игре . В большинстве случаев проще просто стать участником public(и, возможно, даже static, если вы спешите) и беспокоиться о более интересных проблемах.

Чтобы ответить на ваш второй вопрос, я отошлю вас к моему ответу на вопрос «Каковы преимущества использования DrawableGameComponent для каждого экземпляра игрового объекта?» а также мои мысли об игровой архитектуре . Короткий ответ: нет никакой выгоды с использованием GameComponentболее простого создания собственных классов и вызова методов , как Drawи Updateсебя. Если GameComponentточно соответствует вашей желаемой архитектуре, во что бы то ни стало используйте ее - но почти всегда это не так.

Использование сервисов и компонентов становится действительно интересным, только если вы создаете библиотеку для стороннего потребления. Сам XNA делает это - у него есть IGraphicsDeviceServiceи GamerServicesComponent, к примеру. Они удовлетворяют определенным требованиям к развязке, с которыми вы обычно не сталкиваетесь при разработке игры.

Наконец, ответ на ваш третий вопрос довольно прост: просто создайте свои игровые объекты в LoadContent. В этом нет ничего особенного Initialize.

Стоит отметить, что вся Microsoft.Xna.Framework.Gameсборка не является обязательной . Это обеспечивает чрезвычайно полезную отправную точку - но это ни в коем случае не должно рассматриваться как «единственно верный способ» делать вещи.

Эндрю Рассел
источник
Очень интересный способ увидеть это. Гораздо реалистичнее и приземленнее, чем мой ответ. Хорошо заслужено +1, сэр.
Джесси Эмонд
У меня еще один вопрос! Как насчет происхождения, когда вы рисуете для Texture2D. Распространено ли помещать источник в нижнюю середину текстуры? Я пытаюсь сделать анимацию, и я обнаружил, что начало координат в (0,0) заставляет текстуру слегка сдвигаться, если ширина и высота не совпадают
Setheron
@Setheron: Вы должны действительно создать новый вопрос - поскольку это совершенно не связано с первоначальным вопросом. Я собираюсь отменить изменения, внесенные вами в этот вопрос. Начало координат SpriteBatch.Drawуказывается в координатах текстуры-пикселя относительно верхнего левого угла текстуры (или исходного прямоугольника, если вы его используете).
Эндрю Рассел
1
@ Андрей: Я недавно реструктурировать свою игру так , чтобы она была полностью основана на услугах , а не public/ staticсвойств. Почему? Тестируемость. Практически невозможно переключить вещи с помощью подхода со свойством, тогда как это тривиально, если все инициализируется с тем, IServiceProviderчто может быть заполнено всем, что нужно классу вашим методом тестирования. Это также избавляет от необходимости создавать экземпляр самого Gameобъекта в вашем тесте, который очень быстро запутывается.
Мэтью Шарли
Кроме того, у меня все еще есть много открытых свойств Gameобъекта. К ним просто обращаются через интерфейсы, которые проталкиваются, Game.Servicesа затем передаются всему, чтобы получить то, что им нужно.
Мэтью Шарли
3

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

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

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

Для вашего третьего вопроса: да, вы должны загрузить любую форму контента (ресурсы, шрифты и т. Д.) В методе LoadContent. Что касается инициализации, вы обычно создаете объект Player в функции Initialize и затем загружаете его содержимое в LoadContent. Или вы можете просто сделать все это в LoadContent, если хотите.

Джесси Эмонд
источник