Объектно-ориентированные прикладные проблемы в разработке игр - PullRequest
9 голосов
/ 26 декабря 2009

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

Скажем, у меня есть класс Игрока. Этот класс Player делает такие вещи, как изменение своей позиции в игровом мире. Я вызываю этот метод warp (), который принимает экземпляр класса Position в качестве параметра для изменения внутренней позиции Player. Это имеет смысл для меня с точки зрения ОО, потому что я прошу игрока «сделать» что-то.

Проблема возникает, когда мне нужно сделать что-то еще, кроме изменения позиции игрока. Например, скажем, мне нужно отправить это событие деформации другим игрокам в онлайн-игре. Этот код также должен быть в методе игрока warp ()? Если нет, то я хотел бы представить объявление какого-то вторичного метода, скажем, класса Server, такого как warpPlayer (player, position). Выполнение этого, кажется, уменьшает все, что игрок делает с собой как серию добытчиков и сеттеров, или я просто ошибаюсь? Это что-то совершенно нормальное? Я не раз читал, что класс, который представляет все как серию методов получения / установки, указывает на довольно плохую абстракцию (используется как структура данных вместо класса).

Та же проблема возникает, когда вам нужно сохранить данные, сохранив их в файл. Поскольку «сохранение» проигрывателя в файл находится на уровне абстракции, отличном от класса Player, имеет ли смысл иметь метод save () в классе проигрывателя? В противном случае объявление его внешне как savePlayer (player) означает, что методу savePlayer потребуется способ получить все нужные ему данные из класса Player, что в итоге обнажит всю частную реализацию класса.

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

Заранее спасибо, и, надеюсь, я не слишком похож на идиота. Для тех, кому действительно нужно знать языки, связанные с этим проектом, это Java на стороне сервера и ActionScript 3 на стороне клиента.

Ответы [ 7 ]

4 голосов
/ 26 декабря 2009

Советую не бояться того, что игрок будет классом добытчиков и сеттеров. Что такое объект в любом случае? Это сборник атрибутов и поведения. На самом деле, чем проще ваши занятия, тем больше преимуществ ООП вы получите в процессе разработки.

Я бы разбил ваши задачи / функции на такие классы:

Игрок:

  • имеет атрибут хитпоинтов
  • имеет атрибут позиции
  • can walkTo (позиция), запуск событий "прогулки"
  • может лечить (хитпоинты)
  • может забрать урон (хитпоинты), вызывая событие isHurt
  • можно проверить на наличие жизни, как метод isAlive ()

Fighter расширяет возможности игрока (вы должны иметь возможность разыграть Player в Fighter, когда это необходимо):

  • имеет силу и другие боевые параметры для расчета урона
  • может атаковать (), вызывая событие «атаки»

Мир отслеживает всех игроков:

  • слушает "ходячие" события (и предотвращает незаконные перемещения)
  • прослушивает события isHurt (и проверяет, живы ли они)

Битва управляет битвами между двумя бойцами:

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

PlayerPersister расширяет AbstractPersister:

  • сохраняет состояние игрока в базе данных
  • восстанавливает состояние игрока из базы данных

Конечно, разбивка вашей игры будет намного сложнее, но я надеюсь, что это поможет вам начать думать о проблемах "более ООП":)

1 голос
/ 27 декабря 2009

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

Я думаю, вы должны использовать warpPlayer(player, position) подход, который вы предложили. Он поддерживает класс Player в чистоте. Если вы не хотите передавать игрока в функцию, возможно, у вас может быть класс PlayerController, который содержит объект Player и метод warp(Position p). Таким образом, вы можете добавить публикацию событий в контроллер и исключить ее из модели.

Что касается сохранения плеера, я бы сделал это, заставив Player реализовать некоторый интерфейс сериализации. Класс player отвечает за сериализацию и десериализацию, а другой класс отвечает за запись сериализованных данных в / из файла.

0 голосов
/ 26 декабря 2009

Я хотел бы расширить последний абзац GrayWizardx, чтобы сказать, что не все объекты должны иметь одинаковый уровень сложности. Это может очень хорошо соответствовать вашему дизайну, чтобы иметь объекты, которые являются простыми коллекциями свойств get / set. С другой стороны, важно помнить, что объекты могут представлять задачи или коллекции задач, а не объекты реального мира.

Например, объект игрока может не отвечать за перемещение игрока, а представлять его позицию и текущее состояние. Объект PlayerMovement может содержать логику для изменения позиции игрока на экране или в игровом мире.

Прежде чем я начну просто повторять то, что уже было сказано, я укажу на ТВЕРДЫЕ принципы проектирования ООП (Авиад П. уже упомянул два из них). Они могут предоставить некоторые руководящие принципы высокого уровня для создания хорошей объектной модели для игры.

0 голосов
/ 26 декабря 2009

Иногда уловка ООП заключается в понимании того, что является объектом и какова функциональность объекта. Я думаю, что нам часто довольно легко концептуально привязать такие объекты, как Player, Monster, Item и т. Д. Как «объекты» в системе, а затем нам нужно создать объекты, такие как Environment, Transporter и т. Д., Чтобы связать их. эти объекты вместе, и это может выйти из-под контроля в зависимости от того, как концепции работают вместе, и что нам нужно сделать.

Действительно хорошие инженеры, с которыми я работал в прошлом, имели возможность рассматривать системы как совокупности объектов. Иногда в одной системе они были бы бизнес-объектами (такими как элемент, счет-фактура и т. Д.), А иногда они были бы объектами, которые инкапсулировали логику обработки (DyeInjectionProcessor, PersistanceManager), которые пересекают несколько операций и «объекты» в системе. В обоих случаях метафоры работали для этой конкретной системы и облегчали реализацию, описание и сопровождение всего процесса.

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

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

0 голосов
/ 26 декабря 2009

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

В этом случае я бы посоветовал вам спроектировать данные, которые должны быть синхронизированы между всеми клиентами, и хранить их в одном классе (например, GameState). Этот объект будет обрабатывать всю синхронизацию между различными ПК, а также позволять вашему локальному коду запрашивать изменения данных. Затем он «изгонит» игровые объекты (Player, EnemyTank и т. Д.) Из своего собственного состояния. [править: причина этого в том, что поддержание этого состояния как можно меньшим и эффективная его передача между клиентами будет ключевой частью вашего дизайна. Храня все это в одном месте, это делает это намного проще, и рекомендует вам помещать в этот класс только самые необходимые элементы, чтобы ваши связи не были раздутыми из-за ненужных данных]

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

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

0 голосов
/ 26 декабря 2009

Проблемы, которые вы описываете, относятся не только к игровому дизайну, но и к архитектуре программного обеспечения в целом. Общий подход заключается в использовании механизмов Dependency Injection (DI) и Inversion of Control (IoC) . Короче говоря, то, что вы пытаетесь достичь, - это иметь возможность доступа к локальной службе своего рода из ваших объектов, например, для распространения какого-либо события (например, деформации), журнала и т. Д.

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

0 голосов
/ 26 декабря 2009

Я бы, вероятно, подумал о наличии объекта Game, который отслеживает объект игрока. Таким образом, вы можете сделать что-то вроде game.WarpPlayerTo (WarpLocations.Forest); Если есть несколько игроков, возможно, передайте объект игрока или направьте его. Я чувствую, что вы все еще можете оставить его в ОО, и игровой объект решит большинство ваших проблем, я думаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...