Я разработчик, который только сейчас начинает возиться с разработкой игр. Я парень .Net, так что я испортил XNA и сейчас играю с Cocos2d для iPhone. Мой вопрос действительно более общий, хотя.
Допустим, я строю простую игру в понг. У меня был бы Ball
класс и Paddle
класс. Исходя из развития делового мира, мой первый инстинкт - не иметь никакого кода рисования или обработки ввода ни в одном из этих классов.
//pseudo code
class Ball
{
Vector2D position;
Vector2D velocity;
Color color;
void Move(){}
}
Ничто в классе шара не обрабатывает ввод и не занимается рисованием. Затем у меня был бы другой класс, мой Game
класс или мой Scene.m
(в Cocos2d), который бы начал новый шар, и во время игрового цикла он манипулировал мячом по мере необходимости.
Дело в том, что во многих руководствах для XNA и Cocos2d я вижу такую схему:
//pseudo code
class Ball : SomeUpdatableComponent
{
Vector2D position;
Vector2D velocity;
Color color;
void Update(){}
void Draw(){}
void HandleInput(){}
}
Мой вопрос, это правильно? Это тот шаблон, который люди используют при разработке игр? Это как - то идет против всего , я привык, чтобы мой Болл класса всех. Кроме того, в этом втором примере, где мой Ball
знает , как двигаться, как бы я справиться обнаружение столкновения с Paddle
? Будет ли Ball
необходимость иметь знания о Paddle
? В моем первом примере, Game
класс должен иметь ссылки на как Ball
и Paddle
, а затем отправить оба эти прочь к какому - то CollisionDetection
менеджеру или что - то, но как я могу справиться со сложностью различных компонентов, если каждый отдельный компонент делает все сам по себе? (Я надеюсь, что я имею смысл .....)
Ответы:
Разработчики игр склонны использовать все, что работает. Это не строгое, но эй, это отправляет.
Итак, более обобщенная идиома для того, что у вас есть, это handleMessages / update / draw. В системах, которые интенсивно используют сообщения (которые, как и следовало ожидать, имеют плюсы и минусы), игровая сущность захватывает все сообщения, которые ей нужны, выполняет логику этих сообщений и затем рисует сама.
Обратите внимание, что этот вызов draw () может на самом деле не означать, что объект вызывает putPixel или что-то внутри себя; в некоторых случаях это может означать просто обновление данных, которые затем опрашиваются кодом, ответственным за рисование. В более сложных случаях он «рисует» себя, вызывая методы, предоставляемые средством визуализации. В технологии, над которой я сейчас работаю, объект будет рисовать сам себя, используя вызовы рендерера, а затем каждый кадр потока рендеринга организует все вызовы, сделанные всеми объектами, оптимизирует для таких вещей, как изменения состояния, а затем вытягивает всю вещь (все это происходит в потоке, отдельном от логики игры, поэтому мы получаем асинхронный рендеринг).
Делегирование ответственности зависит от программиста; для простой игры в понг имеет смысл, что каждый объект полностью обрабатывает свой собственный рисунок (с низкоуровневыми вызовами). Это вопрос стиля и мудрости.
Итак, один естественный способ решения этой проблемы состоит в том, чтобы каждый объект принимал каждый другой объект как своего рода параметр для проверки столкновений. Это плохо масштабируется и может иметь странные результаты.
Каждый класс реализует своего рода интерфейс Collidable, а затем имеет высокоуровневый бит кода, который просто перебирает все объекты Collidable на этапе обновления вашей игры и обрабатывает столкновения, устанавливая положение объектов по мере необходимости.
Опять же, вы просто должны понять (или принять решение) о том, как следует делегировать ответственность за разные вещи в вашей игре. Рендеринг - это уединенное занятие, которым может управлять объект в вакууме; столкновение и физика вообще не могут.
Смотрите выше для исследования этого. Если вы говорите на языке, который легко поддерживает интерфейсы (например, Java, C #), это легко. Если вы находитесь на C ++, это может быть ... интересно. Я предпочитаю использовать обмен сообщениями для решения этих проблем (классы обрабатывают сообщения, которые они могут, игнорируют другие), некоторые другие люди, такие как композиция компонентов.
Опять же, все, что работает и легче для вас.
источник
Недавно я сделал простую игру Space Invadors, используя «систему сущностей». Это шаблон, который очень хорошо разделяет атрибуты и поведение. Мне потребовалось несколько итераций, чтобы полностью понять это, но как только вы разработали несколько компонентов, стало чрезвычайно просто создавать новые объекты, используя ваши существующие компоненты.
Вы должны прочитать это:
http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/
Это часто обновляется чрезвычайно знающим парнем. Это также единственное обсуждение системы сущностей с конкретными примерами кода.
Мои итерации проходили следующим образом:
Первая итерация имела объект "EntitySystem", который был, как описывает Адам; однако у моих компонентов все еще были методы - у моего компонента «рендеринг» был метод paint (), а у моего компонента позиции был метод move () и т. д. Когда я начал выделять сущности, я понял, что мне нужно начать передавать сообщение между компоненты и порядок выполнения обновлений компонентов .... слишком грязно.
Итак, я вернулся и перечитал блог T-machines. В потоках комментариев содержится много информации, и в них он действительно подчеркивает, что компоненты не имеют поведения - поведение обеспечивается системами сущностей. Таким образом, вам не нужно передавать сообщения между компонентами и заказывать обновления компонентов, потому что порядок определяется глобальным порядком выполнения системы. Хорошо. Может быть, это слишком абстрактно.
Во всяком случае для итерации №2 это то, что я почерпнул из блога:
EntityManager - выступает в качестве компонента «баз данных», которые могут быть запрошены для лиц, которые содержат определенные типы компонентов. Это может даже быть поддержано базой данных в памяти для быстрого доступа ... см. T-machine часть 5 для получения дополнительной информации.
EntitySystem - каждая система по сути является просто методом, который работает с набором объектов. Каждая система будет использовать компоненты x, y и z объекта, чтобы выполнить свою работу. Поэтому вы должны запросить у менеджера сущности с компонентами x, y и z, а затем передать этот результат в систему.
Entity - просто идентификатор, как долго. Сущность - это то, что группирует набор экземпляров компонентов вместе в «сущность».
Компонент - набор полей .... без поведения! когда вы начинаете добавлять поведение, оно начинает становиться грязным ... даже в простой игре Space Invadors.
Редактировать : кстати, 'dt' - это время дельты с момента последнего вызова основного цикла
Итак, мой основной цикл Invadors такой:
Поначалу это выглядит немного странно, но невероятно гибко. Это также очень легко оптимизировать; для разных типов компонентов вы можете иметь разные хранилища данных, чтобы ускорить поиск. Для класса 'form' вы можете получить его с помощью дерева quadtree для ускорения доступа для обнаружения столкновений.
Я, как вы; Я опытный разработчик, но не имел опыта написания игр. Я потратил некоторое время на изучение шаблонов разработки, и это привлекло мое внимание. Это ни в коем случае не единственный способ сделать что-то, но я нашел это очень интуитивным и надежным. Я считаю, что закономерность официально обсуждалась в книге 6 серии «Драгоценности при программировании игр» - http://www.amazon.com/Game-Programming-Gems/dp/1584500492 . Я сам не читал ни одной книги, но слышал, что они являются фактическим справочником по программированию игр.
источник
Нет явных правил, которым вы должны следовать при программировании игр. Я считаю, что оба паттерна вполне приемлемы, если вы придерживаетесь одного и того же паттерна во всей игре. Вы будете удивлены, что существует множество других шаблонов дизайна для игр, некоторые из которых даже не входят в ООП.
Теперь, исходя из своих личных предпочтений, я предпочитаю разделять код по поведению (один класс / поток для рисования, другой для обновления), имея минималистичные объекты. Мне легче распараллеливать, и я часто работаю над меньшим количеством файлов одновременно. Я бы сказал, что это скорее процедурный способ ведения дел.
Но если вы приехали из делового мира, вам, вероятно, удобнее писать классы, которые знают, как сделать все для себя.
Еще раз, я рекомендую вам написать то, что вы считаете наиболее естественным для вас.
источник
у объекта 'Ball' есть атрибуты и поведение. Я считаю, что имеет смысл включить уникальные атрибуты и поведение объекта в их собственный класс. Способ обновления объекта Ball отличается от способа обновления весла, поэтому имеет смысл, что это уникальное поведение, гарантирующее включение в класс. То же самое с рисунком. Часто существует уникальное различие в способе рисования весла и мяча, и мне легче модифицировать метод рисования отдельного объекта в соответствии с этими потребностями, чем выполнять условные вычисления в другом классе для их решения.
Понг - это относительно простая игра с точки зрения количества объектов и поведения, но когда вы попадаете на десятки или сотни уникальных игровых объектов, вам может показаться, что ваш второй пример немного проще для модуляции всего.
Большинство людей используют входной класс, результаты которого доступны для всех игровых объектов через сервис или статический класс.
источник
Я думаю, что в деловом мире вы, вероятно, привыкли разделять абстракцию и реализацию.
В игровом мире разработчиков вы обычно хотите думать с точки зрения скорости. Чем больше у вас объектов, тем больше переключений контекста, что может замедлить процесс в зависимости от текущей нагрузки.
Это только мое предположение, так как я являюсь сторонним разработчиком игр, но профессиональным разработчиком.
источник
Нет, это не «правильно» или «неправильно», это просто упрощение.
Некоторые бизнес-код точно так же, если вы не работаете с системой, которая принудительно разделяющей представления и логики.
Вот пример VB.NET, где «бизнес-логика» (добавление числа) записывается в обработчике событий GUI - http://www.homeandlearn.co.uk/net/nets1p12.html.
Если и когда он получает этот комплекс, то вы можете фактор его.
источник
Исходя из моего опыта в развитии, нет правильного или неправильного способа делать вещи, если только в группе, с которой вы работаете, нет общепринятой практики. Я встречал противодействие со стороны разработчиков, которые не разделяют поведение, скины и т.д. Помните, что вы должны не только написать его, но и иметь возможность читать свой код завтра и в будущем, отлаживать его и, возможно, использовать его в следующей итерации. Вы должны выбрать путь, который работает для вас (и команды). Выбор маршрута, который используют другие (и который вам не понятен), замедлит вас.
источник