Я в настоящее время изучаю разработку игр и практикую создание игр.
Я использую много ООП в своих играх. Например, каждая выпущенная ракета является экземпляром Missile
объекта и добавляется в список Missile
объектов. Каждый танк в игре является Tank
объектом. И т.п.
Весь дизайн программы основан на этом. Например, наличие списка Missile
объектов позволяет мне в каждом кадре перемещать ракеты, рисовать их и т. Д. А наличие экземпляра Tank
объекта для каждого танка позволяет мне проверять каждый танк на предмет столкновения с чем-либо и т. Д.
Мне трудно представить, как можно программировать игру (которая более сложна, чем Pac-Man) на языке не-OO. (Без неуважения к не-ОО программистам конечно). Не только с точки зрения того, сколько времени это займет, но в основном с точки зрения того, как игра может быть разработана таким образом.
Я не могу представить разработку игры без использования объектно-ориентированного программирования, потому что все мое понимание того, как разрабатывать игровую программу, основано на ООП.
Я хотел бы спросить: есть ли сегодня игры, которые не запрограммированы с использованием ООП, аналогично тому, что я описал выше? Существуют ли «профессиональные» игры, в которых ООП не является основным фактором в процессе разработки?
Если да, не могли бы вы дать мне представление о том, как, например, обнаружение столкновений между танком и N ракетами без ООП?
источник
Ответы:
Тогда вам, вероятно, будет полезно попробовать написать несколько программ в не-ОО стиле. Даже если вы обнаружите, что это не прагматично для вас, вы, вероятно, многому научитесь на этом пути, который поможет вам в будущем.
Стиль ОО довольно хорошо подходит для игр, потому что игры почти всегда связаны с манипулированием объектами с состоянием. Лазерный луч попадает в робота, и состояние робота меняется, а его идентичность остается неизменной.
Однако можно программировать игры в функциональном стиле. В функциональном стиле состояние само по себе не меняется. Объекты неизменны. Вместо того, чтобы менять объекты, вы задаете вопрос, как изменилась бы вселенная, если бы я изменил это? а затем создать совершенно новую вселенную с измененным свойством. Конечно, вы можете повторно использовать множество ранее существовавшей вселенной, потому что она неизменна .
В функциональном программировании каждая функция должна вычислять свое возвращаемое значение исключительно из переданной информации; нет чтения из "глобального состояния".
Если вы сделаете это, основная проблема, с которой вам придется столкнуться, заключается в том, что каждое обновление является неразрушающим . Когда лазер попадает в робота, вы не меняете его состояние. В конечном итоге вы вычисляете совершенно новую вселенную, идентичную старой, за исключением того, что у робота другое состояние; если вам нужна эта старая вселенная, она все еще там, без изменений.
Эта серия статей в блоге посвящена написанию игр в функциональном стиле:
http://prog21.dadgum.com/23.html
Эта статья специально посвящена вашему вопросу "снаряд бьет по танку":
http://prog21.dadgum.com/189.html
На самом деле, просто прочитайте весь блог. Там есть хорошие вещи и статьи короткие.
источник
Любая объектно-ориентированная программа может быть преобразована в процедурную программу путем замены всех классов структурами и преобразования всех функций-членов в автономную функцию, которая принимает объект, который будет
this
аргументом.Так
становится
или когда эта функция тривиальна, вы просто делаете
Основное различие между объектно-ориентированным программированием и процедурным программированием заключается в том, как вы обрабатываете свои данные. В ООП данные умные . Он управляет собой и манипулирует собой. Но в процедурном программировании данные глупы . Он ничего не делает сам по себе и нуждается в манипулировании извне.
Когда вы даже считаете структуры слишком объектно-ориентированными, вы можете заменить один массив структур несколькими массивами, один для всего, что будет переменной ракеты. Так
становится
В этом проекте функция, которая выполняет операцию с несколькими атрибутами одной ракеты, теперь будет получать индекс массива вместо ссылки на структуру. Его реализация будет выглядеть так:
источник
missile
это экземпляр объекта. В не-ООП экземплярах нет, я прав? Если так, как вы могли бы сделать setMissileVelocity (missile, 100)?Missile
, который представляет собой структуру с несколькими полями, какx
,y
,angle
иvelocity
.Я делаю это следующим образом:
this
. Чтобы использоватьthis
подход без ОО, просто передайте вthis
качестве первого параметра любой экземпляр (см. Следующий пункт) .struct
s в свои функции какthis
, но я считаю, что лучший способ добиться хорошей производительности кэша для объектов, которые являются плодовитыми, таких как объекты или частицы, - это просто передать один индекс в несколько массивов примитивов. или маленькийstruct
с. Таким образом, этот индекс используется для каждого отдельного члена данных исходного класса. Так, например, если у вас было...
Вы бы заменили это на
Так что теперь вы передаете индекс в функцию, чтобы получить то, что обычно будет
this
.Имейте в виду, что вы можете использовать либо массивы примитивов, как указано выше, либо массивы
struct
s, в зависимости от того, как наилучшим образом чередовать ваши данные для хорошей локализации кэша (местность ссылки). Конечно, приличная производительность кэша зависит от гораздо большего, особенно от того, на каком языке / платформе вы пишете свой код, но даже в динамически выделяемых языках на основе виртуальных машин, таких как Java, большие линейные массивы примитивов имеют тенденцию отображать лучшие характеристики производительности, чем экземпляры объектов. Основная причина этого в том, что доступ к объектам осуществляется по ссылке, и это означает, что вы перепрыгиваете всю память для доступа к данным - неэффективно по сравнению с непрерывным доступом к примитивам из большого массива.Для получения дополнительной информации о построении сущностей и т. Д. В виде массива структур или примитивов см. Mick West's Evolve your Hierarchy .
источник
В дополнение к существующим ответам вы можете узнать, как сделать полиморфизм на процедурном языке.
Есть два подхода:
Хранение типа
В этом случае структура имеет поле для идентификатора типа, возможно, enum, которое проверяется с помощью
switch
оператора, когда необходимо выполнить действие, специфичное для типа.Другой способ:
Хранение указателей на функции
Вы не упомянули, на каком языке программирования у вас есть опыт, но на разных языках их также называют обратными вызовами, делегатами, событиями или функциями высокого порядка или просто функциональными объектами.
В этом случае вы не будете хранить тип, но будете хранить указатель / ссылку на функцию, которая выполняет определенное действие. Когда нужно выполнить действие, специфичное для типа, вы просто вызываете эту функцию. Этот очень похож на обычные виртуальные методы.
Позволяя устанавливать каждую функцию независимо, вы получаете шаблон стратегии бесплатно.
Относительно вашего последнего параграфа с обнаружением столкновений. Я думаю, что у вас, вероятно, есть несколько типов танков, и у вас есть несколько видов ракет, и каждая комбинация может иметь разные результаты, когда они сталкиваются. Если это то, что вы ищете, у вас есть проблема, которая еще не решена даже ООП-языками: множественная диспетчеризация и множественные методы, которые могут иметь несколько
this
параметров разных типов. Для этой проблемы снова есть две альтернативы:источник