Я только что прочитал ответ на вопрос о структурировании игрового кода . Это заставило меня задуматься о вездесущем GameManager
классе и о том, как часто он становится проблемой в производственной среде. Позвольте мне описать это.
Во-первых, есть прототипирование. Никто не заботится о написании отличного кода, мы просто пытаемся запустить что-то, чтобы увидеть, улучшается ли игровой процесс.
Тогда есть зеленый свет, и, чтобы очистить вещи, кто-то пишет GameManager
. Вероятно, чтобы держать кучу GameStates
, может быть, хранить несколько GameObjects
, ничего большого, правда. Милый, маленький, менеджер.
В мирной сфере подготовки производства игра складывается хорошо. У программистов есть достаточное количество ночей сна и множество идей для создания архитектуры с использованием Great Design Patterns.
Затем начинается производство, и вскоре, конечно, наступает время кризиса. Сбалансированная диета давно исчезла, трекер ошибок сталкивается с проблемами, люди испытывают стресс, и игра должна быть выпущена вчера.
В этот момент, как правило, GameManager
это действительно большой беспорядок (чтобы оставаться вежливым).
Причина этого проста. В конце концов, при написании игры, а ... весь исходный код на самом деле здесь , чтобы управлять в игре . Легко просто добавить эту небольшую дополнительную функцию или исправление в GameManager
, где все остальное в любом случае уже сохранено. Когда время становится проблемой, нет способа написать отдельный класс или разделить этого гигантского менеджера на суб-менеджеров.
Конечно, это классический анти-паттерн: объект бога . Это плохо, боль слияния, боль поддержания, боль понимания, боль преобразования.
Что бы вы предложили, чтобы этого не случилось?
РЕДАКТИРОВАТЬ
Я знаю, что заманчиво обвинять в названии. Конечно, создание GameManager
класса не такая уж хорошая идея. Но то же самое может случиться с чистым GameApplication
или, GameStateMachine
или GameSystem
это будет фаворитом клейкой ленты к концу проекта. Независимо от названия, у вас есть этот класс где-то в вашем игровом коде, это пока только зародыш: вы просто еще не знаете, каким монстром он станет. Так что я не жду ответов «обвиняю в названии». Я хочу, чтобы это не происходило, архитектура кодирования и / или процесс, которым команда может следовать, зная, что это произойдет в какой-то момент производства. Просто очень плохо отбрасывать, скажем, один месяц исправлений и последних функций, просто потому, что все они теперь в одном огромном неуправляемом менеджере.
источник
GameManager
воздействию, которое я описал выше?Ответы:
Знаете, когда я читал это, у меня в голове возникали маленькие тревоги. Объект с именем «GameManager» никогда не будет милым или маленьким. И кто-то сделал это, чтобы очистить код? Как это выглядело раньше? Хорошо, оставим в стороне шутки: имя класса должно быть четким указанием на то, что делает класс, и это должно быть одно (иначе: принцип единой ответственности ).
Кроме того, вы все равно можете получить такой объект, как GameManager, но, очевидно, он существует на очень высоком уровне, и он должен заниматься задачами высокого уровня. Ведение каталога игровых объектов? Может быть. Облегчение общения между игровыми объектами? Конечно. Вычисление столкновений между объектами? Нет! Именно поэтому имя менеджера не одобряется - оно слишком широкое и допускает много злоупотреблений под этим баннером.
Быстрое правило о размерах классов: если вы используете несколько сотен строк кода на класс, что-то начинает идти не так. Не переусердствовав, скажем, что-нибудь свыше 300 LOC - это кодовый запах для меня, и если вы наберете более 1000, должны прозвучать предупреждающие сигналы. Полагая, что каким-то образом 1000 строк кода проще для понимания, чем 4 хорошо структурированных класса по 250 в каждом, вы вводите себя в заблуждение.
Я думаю, что это так только потому, что проблема может распространяться до такой степени, что все в полном беспорядке. Практика рефакторинга - это действительно то, что вы ищете - вам нужно постоянно улучшать дизайн кода небольшими шагами .
Проблема не технологическая, поэтому вам не нужно искать технологические решения для нее. Проблема заключается в следующем: в вашей команде есть тенденция создавать монолитные фрагменты кода, и есть убеждение, что в среднесрочной / долгосрочной перспективе так или иначе работать так. Также кажется, что команде не хватает сильного архитектурного лидера, который бы руководил архитектурой игры (или, по крайней мере, этот человек слишком занят, чтобы выполнить эту задачу). По сути, единственный выход состоит в том, чтобы члены команды поняли, что это неправильное мышление. Это никто не одобряет. Качество продукта ухудшится, и команда будет проводить еще больше ночей, исправляя вещи.
Хорошей новостью является то, что непосредственные ощутимые преимущества написания чистого кода настолько велики, что почти все разработчики очень быстро осознают свои преимущества. Убедите команду работать так некоторое время, результаты сделают все остальное.
Сложность заключается в том, что развитие чувства плохого кода (и способности быстро придумывать лучший дизайн) является одним из наиболее сложных навыков, которые необходимо освоить при разработке. Мое предложение основано на надежде, что в команде есть кто-то достаточно высокопоставленный, кто сможет это сделать - гораздо проще убедить людей таким образом.
Редактировать - немного больше информации:
В общем, я не думаю, что ваша проблема ограничена разработкой игр. По сути, это проблема разработки программного обеспечения, поэтому мои комментарии в этом направлении. Я не уверен, может ли отличаться природа индустрии разработки игр, более ли она ориентирована на результаты и сроки выполнения, чем другие виды разработки.
Тем не менее, специально для разработки игр принятый ответ на этот вопрос в StackOverflow, касающийся советов «особенно игровой архитектуры», гласит:
По сути, это именно то, что я говорю. Когда я нахожусь под давлением, я также нахожу себя пишущим большие куски кода, но я просверлил это в моей голове, что это технический долг. Что хорошо работает для меня, так это потратить первую половину (или три четверти) дня на создание большого количества кода среднего качества, а затем расслабиться и немного подумать; В своей голове или на бумаге / доске делаю немного о том, как немного улучшить код. Часто я замечаю повторяющийся код и могу фактически сократить общее количество строк кода, разбивая их на части, одновременно улучшая читабельность. Инвестированное время окупается так быстро, что называть его «инвестицией» звучит глупо - довольно часто я выявляю ошибки, которые могли бы потратить впустую половину моего дня (неделю спустя), если бы я позволил этому продолжаться.
Достичь веры в вышесказанное сложно; Мне удалось сделать это для моей собственной работы только потому, что я снова и снова испытывал эффекты. Несмотря на это, мне все еще трудно оправдать исправление кода, когда я мог бы производить больше ... Так что я определенно понимаю, откуда вы пришли. К сожалению, этот совет, возможно, слишком общий, и его нелегко выполнить. Я твердо верю в это, однако! :)
Чтобы ответить на ваш конкретный пример:
Чистый код дяди Боба делает потрясающую работу по обобщению кода хорошего качества. Я согласен почти со всем его содержанием. Поэтому, когда я вспоминаю ваш пример с менеджером класса 30 000 LOC, я не могу действительно согласиться с частью «веских оснований». Я не хочу звучать оскорбительно, но такое мышление приведет к проблеме. Нет веской причины иметь столько кода в одном файле - это почти 1000 страниц текста! Любая выгода от локальности (скорость выполнения или «простота» дизайна) будет немедленно аннулирована разработчиками, которые полностью увязнут в попытках ориентироваться в этом чудовище, и это даже до того, как мы обсудим слияние и т. Д.
Если вы не уверены, мое лучшее предложение - взять копию вышеприведенной книги и просмотреть ее. Применение такого типа мышления приводит к тому, что люди добровольно создают чистый, не требующий пояснений код, который хорошо структурирован.
источник
GameManager
который я видел до сих пор, составлял около 30 000 строк кода, и я почти уверен, что большая его часть была здесь по очень веской причине. Это, конечно, крайность, но такие вещи случаются в реальном мире. Я прошу способ ограничить этотGameManager
эффект.Это не проблема программирования игр, а вообще программирования.
Вот почему вы должны хмуриться на любом объектно-ориентированном кодере, который будет предлагать классы с «Менеджером» в названии. Честно говоря, я думаю, что практически невозможно избежать «полугодовых» объектов в игре, но мы просто называем их «системными».
Любое программное обеспечение имеет тенденцию пачкаться, когда приближается крайний срок. Это часть работы. И нет ничего плохого в « программировании типа воздуховода », особенно когда вы должны отгружать свой продукт в течение нескольких часов. Вы не можете полностью избавиться от этой проблемы, вы можете просто уменьшить ее.
Хотя очевидно, что если вы соблазнитесь положить что-то в GameManager, это означает, что у вас нет очень здоровой кодовой базы. Там может быть две проблемы:
Ваш код слишком сложен. Слишком много шаблонов, преждевременная оптимизация, никто больше не понимает поток. Попробуйте использовать больше TDD при разработке, если это возможно, потому что это очень хорошее решение для борьбы со сложностью.
Ваш код плохо структурирован. Вы (ab) используете переменную globals, классы не связаны слабо, нет никакого интерфейса, никакой системы событий и так далее.
Если код кажется нормальным, вы должны будете помнить для каждого проекта «что пошло не так» и избегать этого в следующий раз.
Наконец, это также может быть проблемой управления командой: было ли достаточно времени? Все ли знали об архитектуре, на которую вы шли? Кто, черт возьми, разрешил коммит с классом со словом «Менеджер»?
источник
SceneManager
или aNetworkManager
? Я не понимаю, почему мы должны их предотвращать или как помогает замена -Manager на -System. Я ищу предложения для замены архитектуры для того, что обычно входит вGameManager
что-то, менее склонное к раздутию кода.GameStatesCollection
. В начале у вас будет только несколько игровых состояний и способов переключения между ними. Затем появляются загрузочные экраны, которые усложняют все это. Затем некоторым программистам приходится иметь дело с ошибкой, когда пользователь извлекает диск, пока вы переключаетесь с Level_A на Level_B, и единственный способ исправить это, не тратя полдня, - это рефакторингGameStatesCollection
. Бум, объект бога.Итак, привнося одно возможное решение из более корпоративного мира: вы проверяли инверсию управления / внедрения зависимостей?
По сути, вы получаете эту среду, которая является контейнером для всего остального в вашей игре. Он и только он знает, как связать все воедино и каковы отношения между вашими объектами. Ни один из ваших объектов ничего не создает в своих собственных конструкторах. Вместо того, чтобы создавать то, что им нужно, они спрашивают, что им нужно, в рамках IoC; после создания платформа IoC «знает», какой объект необходим для удовлетворения зависимости, и заполняет ее. Слабая муфта FTW.
Когда ваш класс EnemyTreasure запрашивает у контейнера объект GameLevel, фреймворк знает, какой экземпляр ему предоставить. Как это узнать? Может быть, он создал его раньше, может быть, он спрашивает какой-то соседний GameLevelFactory. Дело в том, что EnemyTreasure не знает, откуда появился экземпляр GameLevel. Он только знает, что его зависимость теперь удовлетворена, и он может продолжать жить.
О, я вижу, ваш класс PlayerSprite реализует IUpdateable. Что ж, это здорово, потому что фреймворк автоматически подписывает каждый объект IUpdateable на Timer, где находится основной игровой цикл. Каждый Timer :: tick () автоматически вызывает все методы IUpdatedable :: update (). Легко, правда?
Реально, вам не нужен этот bighugeohmygod фреймворк, чтобы сделать это за вас: вы можете сделать важные кусочки самостоятельно. Дело в том, что если вы создаете объекты типа -Manager, то, скорее всего, вы неправильно распределяете свои обязанности между классами или пропускаете некоторые классы где-то.
источник
В прошлом я обычно получал класс бога, если я делаю следующее:
Это может быть спорным, что я буду смеяться, если это так, но я не могу вспомнить ни единого момента, даже в прототипировании, что вы не должны писать очень простую диаграмму классов перед написанием воспроизводимого прототипа. Я склонен проверять технические идеи перед планированием, но это все. Поэтому, если бы я хотел создать портал, я бы написал очень простой код для работы порталов, а затем сказал: «Хорошо, отличное время для небольшого планирования, тогда я могу работать над воспроизводимым прототипом».
источник
Я знаю, что этот вопрос уже устарел, но я решил добавить свои 2 цента.
При разработке игр у меня почти всегда есть объект Game. Тем не менее, это очень высокий уровень и сам по себе ничего не «делает».
Например, он сообщает классу Graphics объекту Render, но не имеет ничего общего с процессом рендеринга. Он может попросить LevelManager загрузить новый уровень, но не имеет никакого отношения к процессу загрузки.
Короче говоря, я использую полубогоподобный объект, чтобы организовать использование других классов.
источник