Например, у меня есть класс Game, и он хранит данные, int
которые отслеживают жизнь игрока. У меня условно
if ( mLives < 1 ) {
// Do some work.
}
Однако это условие продолжает работать, и работа выполняется повторно. Например, я хочу установить таймер для выхода из игры через 5 секунд. В настоящее время он будет устанавливать 5 секунд на каждый кадр, и игра никогда не заканчивается.
Это всего лишь один пример, и у меня одна и та же проблема в нескольких областях моей игры. Я хочу проверить какое-то условие и затем сделать что-то один раз и только один раз, а затем не проверять или делать код снова в операторе if. Некоторые возможные решения, которые приходят на ум, имеют bool
для каждого условия и устанавливают, bool
когда условие срабатывает. Однако на практике это приводит к большим ошибкам bools
, поскольку они должны храниться как поля класса или статически в самом методе.
Каково правильное решение этого (не для моего примера, но для проблемной области)? Как бы вы сделали это в игре?
Ответы:
Я думаю, что вы можете решить эту проблему, просто проявив более тщательный контроль над возможными путями кода. Например, если вы проверяете, упало ли количество жизней игрока ниже единицы, почему бы не проверить только, когда игрок теряет жизнь, а не каждый кадр?
Это, в свою очередь, предполагает, что он
subtractPlayerLife
будет вызываться только в определенных случаях, что, возможно, будет результатом условий, которые вы должны проверять каждый кадр (возможно, столкновения).Тщательно контролируя, как выполняется ваш код, вы можете избежать грязных решений, таких как статические логические значения, а также понемногу сокращать объем кода, выполняемого в одном кадре.
Если есть что-то, что кажется просто невозможным для рефакторинга, и вам действительно нужно проверить только один раз, тогда можно использовать
enum
статические или логические значения (например, a ). Чтобы избежать объявления статики самостоятельно, вы можете использовать следующий прием:который сделал бы следующий код:
распечатать
something
иsomething else
только один раз. Он не дает лучший код, но работает. Я также почти уверен, что есть способы улучшить его, возможно, за счет лучшего обеспечения уникальных имен переменных. Это#define
будет работать только один раз во время выполнения. Нет способа сбросить его, и нет способа его сохранить.Несмотря на хитрость, я настоятельно рекомендую сначала лучше контролировать поток кода и использовать его
#define
в качестве крайней меры или только для целей отладки.источник
Это звучит как классический случай использования шаблона состояния. В одном состоянии вы проверяете свое состояние на жизнь <1. Если это условие становится истинным, вы переходите в состояние задержки. Это состояние задержки ожидает указанную продолжительность, а затем переходит в состояние выхода.
В самом тривиальном подходе:
Вы могли бы рассмотреть использование класса State вместе с StateManager / StateMachine для обработки изменения / нажатия / перехода между состояниями, а не оператора switch.
Вы можете сделать свое решение для управления состояниями настолько сложным, насколько вам нужно, включая несколько активных состояний, одно активное родительское состояние со многими активными дочерними состояниями, использующими некоторую иерархию и т. Д. Конечно, используйте то, что имеет смысл для вас сейчас, но я действительно считаю, что Решение шаблонов состояний сделает ваш код более пригодным для повторного использования, его будет проще поддерживать и отслеживать.
источник
Если вы беспокоитесь о производительности, производительность проверки несколько раз не является значительной; То же самое для того, чтобы иметь условия bool.
Если вас интересует что-то еще, вы можете использовать что-то похожее на шаблон нулевого дизайна для решения этой проблемы.
В этом случае предположим, что вы хотите вызвать метод,
foo
если у игрока не осталось жизней. Вы бы реализовали это как два класса, один из которых вызываетfoo
, а другой ничего не делает. Позвоним имDoNothing
иCallFoo
вот так:Это немного «сырой» пример; ключевые моменты:
FooClass
который может бытьDoNothing
илиCallFoo
. Это может быть базовый класс, абстрактный класс или интерфейс.execute
метод этого класса.DoNothing
экземпляр).CallFoo
экземпляр).Это по сути как сочетание стратегии и нулевых паттернов.
источник
if
чека в самFooClass
экземпляр, чтобы он выполнялся только один раз, и то же самое для создания экземпляраCallFoo
.