Разделение рисунка и логики в играх


11

Я разработчик, который только сейчас начинает возиться с разработкой игр. Я парень .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менеджеру или что - то, но как я могу справиться со сложностью различных компонентов, если каждый отдельный компонент делает все сам по себе? (Я надеюсь, что я имею смысл .....)


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

@tenpn, твой комментарий, кажется, говорит о том, что ты не считаешь это хорошей практикой, интересно, ты мог бы объяснить дальше? Я всегда думал, что это было наиболее подходящее расположение из-за методов, содержащих код, который, вероятно, очень специфичен для каждого типа; но у меня есть небольшой опыт себя , так что я бы интересно услышать ваши мысли.
sebf

1
@sebf не работает, если вы увлекаетесь дизайном, ориентированным на данные, и не работает, если вам нравится объектно-ориентированный дизайн. Смотрите SOLID princples дяди Боба: butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
tenpn

@tenpn. Эта статья и документ связан в очень интересно, спасибо!
sebf

Ответы:


10

Мой вопрос, правильно ли это? Это тот шаблон, который люди используют при разработке игр?

Разработчики игр склонны использовать все, что работает. Это не строгое, но эй, это отправляет.

Это как-то противоречит тому, к чему я привык, чтобы мой класс по мячу делал все.

Итак, более обобщенная идиома для того, что у вас есть, это handleMessages / update / draw. В системах, которые интенсивно используют сообщения (которые, как и следовало ожидать, имеют плюсы и минусы), игровая сущность захватывает все сообщения, которые ей нужны, выполняет логику этих сообщений и затем рисует сама.

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

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

Кроме того, во втором примере, где мой мяч знает, как двигаться, как бы я справился с обнаружением столкновений с веслом? Мяч должен был знать о весле?

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

Каждый класс реализует своего рода интерфейс Collidable, а затем имеет высокоуровневый бит кода, который просто перебирает все объекты Collidable на этапе обновления вашей игры и обрабатывает столкновения, устанавливая положение объектов по мере необходимости.

Опять же, вы просто должны понять (или принять решение) о том, как следует делегировать ответственность за разные вещи в вашей игре. Рендеринг - это уединенное занятие, которым может управлять объект в вакууме; столкновение и физика вообще не могут.

В моем первом примере класс Game будет иметь ссылки как на Ball, так и на Paddle, а затем отправлять оба из них в какой-нибудь менеджер CollisionDetection или что-то в этом роде, но как мне справиться со сложностью различных компонентов, если каждый отдельный компонент делает это? все сами?

Смотрите выше для исследования этого. Если вы говорите на языке, который легко поддерживает интерфейсы (например, Java, C #), это легко. Если вы находитесь на C ++, это может быть ... интересно. Я предпочитаю использовать обмен сообщениями для решения этих проблем (классы обрабатывают сообщения, которые они могут, игнорируют другие), некоторые другие люди, такие как композиция компонентов.

Опять же, все, что работает и легче для вас.


2
О, и всегда помни: ЯГНИ (Тебе это не понадобится) действительно важно здесь. Вы можете потратить много времени, пытаясь придумать идеальную гибкую систему для решения всех возможных проблем, а затем никогда ничего не сделаете. Я имею в виду, если бы вы действительно хотели хорошую многопользовательскую опору для всех возможных результатов, вы бы использовали CORBA, верно? :)
ChrisE

5

Недавно я сделал простую игру 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 такой:

Collection<Entity> entitiesWithGuns = manager.getEntitiesWith(Gun.class);
Collection<Entity> entitiesWithDamagable =
manager.getEntitiesWith(BulletDamagable.class);
Collection<Entity> entitiesWithInvadorDamagable = manager.getEntitiesWith(InvadorDamagable.class);

keyboardShipControllerSystem.update(entitiesWithGuns, dt);
touchInputSystem.update(entitiesWithGuns, dt);
Collection<Entity> entitiesWithInvadorMovement = manager.getEntitiesWith(InvadorMovement.class);
invadorMovementSystem.update(entitiesWithInvadorMovement);

Collection<Entity> entitiesWithVelocity = manager.getEntitiesWith(Velocity.class);
movementSystem.move(entitiesWithVelocity, dt);
gunSystem.update(entitiesWithGuns, System.currentTimeMillis());
Collection<Entity> entitiesWithPositionAndForm = manager.getEntitiesWith(Position.class, Form.class);
collisionSystem.checkCollisions(entitiesWithPositionAndForm);

Поначалу это выглядит немного странно, но невероятно гибко. Это также очень легко оптимизировать; для разных типов компонентов вы можете иметь разные хранилища данных, чтобы ускорить поиск. Для класса 'form' вы можете получить его с помощью дерева quadtree для ускорения доступа для обнаружения столкновений.

Я, как вы; Я опытный разработчик, но не имел опыта написания игр. Я потратил некоторое время на изучение шаблонов разработки, и это привлекло мое внимание. Это ни в коем случае не единственный способ сделать что-то, но я нашел это очень интуитивным и надежным. Я считаю, что закономерность официально обсуждалась в книге 6 серии «Драгоценности при программировании игр» - http://www.amazon.com/Game-Programming-Gems/dp/1584500492 . Я сам не читал ни одной книги, но слышал, что они являются фактическим справочником по программированию игр.


1

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

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

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

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


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

Чтобы быть справедливым, в бизнес - программировании , если вы кипятите его, есть два поезда: бизнес - объекты , что нагрузки, сохраняются и выполнять логику на себя, и DTO + AppLogic + Repository / Persitance Layer ...
Nate

1

у объекта 'Ball' есть атрибуты и поведение. Я считаю, что имеет смысл включить уникальные атрибуты и поведение объекта в их собственный класс. Способ обновления объекта Ball отличается от способа обновления весла, поэтому имеет смысл, что это уникальное поведение, гарантирующее включение в класс. То же самое с рисунком. Часто существует уникальное различие в способе рисования весла и мяча, и мне легче модифицировать метод рисования отдельного объекта в соответствии с этими потребностями, чем выполнять условные вычисления в другом классе для их решения.

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

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


0

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

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

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


0

Нет, это не «правильно» или «неправильно», это просто упрощение.

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

Вот пример VB.NET, где «бизнес-логика» (добавление числа) записывается в обработчике событий GUI - http://www.homeandlearn.co.uk/net/nets1p12.html.

как мне справиться со сложностью различных компонентов, если каждый отдельный компонент все делает сам?

Если и когда он получает этот комплекс, то вы можете фактор его.

class Ball
{
    GraphicalModel ballVisual;
    void Draw()
    {
        ballVisual.Draw();
    }
};

0

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

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