Как сделать игру без ООП? [закрыто]

10

Я в настоящее время изучаю разработку игр и практикую создание игр.

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

Весь дизайн программы основан на этом. Например, наличие списка Missileобъектов позволяет мне в каждом кадре перемещать ракеты, рисовать их и т. Д. А наличие экземпляра Tankобъекта для каждого танка позволяет мне проверять каждый танк на предмет столкновения с чем-либо и т. Д.

Мне трудно представить, как можно программировать игру (которая более сложна, чем Pac-Man) на языке не-OO. (Без неуважения к не-ОО программистам конечно). Не только с точки зрения того, сколько времени это займет, но в основном с точки зрения того, как игра может быть разработана таким образом.

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

Я хотел бы спросить: есть ли сегодня игры, которые не запрограммированы с использованием ООП, аналогично тому, что я описал выше? Существуют ли «профессиональные» игры, в которых ООП не является основным фактором в процессе разработки?

Если да, не могли бы вы дать мне представление о том, как, например, обнаружение столкновений между танком и N ракетами без ООП?

user3150201
источник
6
Это философский вопрос? Даже если вы не называете свои танки «объектами», вам, вероятно, понадобятся «сущности», «актеры», «агенты», «структуры» или просто какое-то другое имя для той же идеи, которая представляет собой набор атрибуты и поведение, которые составляют вращающуюся кубовидную вещь с турелью, которая может стрелять в вещи, называемые танком. Языки программирования будут по-разному формализовать эту идею, но, в конце концов, это будет танк.
Анко
Многие игры используют систему на основе компонентов, как описано в этом ответе: gamedev.stackexchange.com/a/31491/9366
Джон Макдональд,
Это очень обширный вариант (который можно исправить, сузив область действия), и он не очень специфичен для разработки игр (поскольку создание программного обеспечения без ОО-технологий разработчик игры не даст вам лучшего ответа, чем любой другой разработчик программного обеспечения), боюсь, это не по теме.
Это может быть подходящим для StackOverflow, или вы можете обратиться в справочный центр, чтобы найти выбор сайтов, которые являются специфическими для разработки игр (например, GDNet), которые позволили бы такого рода широкие, ориентированные на обсуждение темы. Удачи!

Ответы:

16

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

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

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

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

В функциональном программировании каждая функция должна вычислять свое возвращаемое значение исключительно из переданной информации; нет чтения из "глобального состояния".

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

Эта серия статей в блоге посвящена написанию игр в функциональном стиле:

http://prog21.dadgum.com/23.html

Эта статья специально посвящена вашему вопросу "снаряд бьет по танку":

http://prog21.dadgum.com/189.html

На самом деле, просто прочитайте весь блог. Там есть хорошие вещи и статьи короткие.

Эрик Липперт
источник
12

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

Так

 missile.setVelocity(100);

становится

 setMissileVelocity(missile, 100);

или когда эта функция тривиальна, вы просто делаете

 missile.velocity = 100;

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

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

struct Missile {
     int x;
     int y;
     int velocity;
}

Missile missiles[256];

становится

int missileX[256];
int missileY[256];
int missileVelocities[256];

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

function updateMissilePosition(int index) {
     missileX[index] += missileVelocity[index];
}
Philipp
источник
1
Но missileэто экземпляр объекта. В не-ООП экземплярах нет, я прав? Если так, как вы могли бы сделать setMissileVelocity (missile, 100)?
user3150201
1
@ user3150201 Вы не совсем правы. Большинство не-ООП-языков (и я бы сказал, что любой из них подходит для серьезной разработки игр) поддерживают структуры. Структура похожа на класс, просто она не содержит ничего, кроме открытых переменных. Так что это позволит вам создать тип Missile, который представляет собой структуру с несколькими полями, как x, y, angleи velocity.
Филипп
@ user3150201 Обновленный ответ с разделом о том, как это сделать без структур.
Филипп
Хороший ответ, Филипп, хотя я не понимаю, почему бы не захотеть программировать объектно-ориентированные. Очень трудно читать языки, не связанные с ООП, и это может привести к разочарованию. Код может стать беспорядком в кратчайшие сроки.
Жафур
2
@Zhafur Вы знаете, что ваше заявление - огромная приманка, не так ли?
Филипп
6

Я делаю это следующим образом:

  • Все классы / методы ООП имеют доступ к this. Чтобы использовать thisподход без ОО, просто передайте в thisкачестве первого параметра любой экземпляр (см. Следующий пункт) .
  • Теперь, что касается примеров, вы можете передавать structs в свои функции как this, но я считаю, что лучший способ добиться хорошей производительности кэша для объектов, которые являются плодовитыми, таких как объекты или частицы, - это просто передать один индекс в несколько массивов примитивов. или маленький structс. Таким образом, этот индекс используется для каждого отдельного члена данных исходного класса. Так, например, если у вас было

...

class Entity //let's say you had 100 instances of this
{
   int a;
   char b;
   function foo() 
   {
      .../*can access 'this' herein*/
   }
}

Вы бы заменили это на

int a[100];
char b[100];
function foo(int index);

Так что теперь вы передаете индекс в функцию, чтобы получить то, что обычно будет this.

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

Для получения дополнительной информации о построении сущностей и т. Д. В виде массива структур или примитивов см. Mick West's Evolve your Hierarchy .

инженер
источник
0

В дополнение к существующим ответам вы можете узнать, как сделать полиморфизм на процедурном языке.

Есть два подхода:

Хранение типа

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

Другой способ:

Хранение указателей на функции

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

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

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


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

  • Вложенные переключатели для каждой комбинации танка и ракеты.
  • Двумерные массивы диспетчеризации, которые содержат указатели на функции для каждой комбинации танка и ракеты.
Calmarius
источник