Гарантия сохранения последовательности действий.Пользователь Reddit под ником distinctdan опубликовал небольшой пример использования конечных автоматов для создания логики поведения игровых объектов. Мы выбрали из его рассказал главное.Если вы не знакомы с конечными автоматами, но хотите получить начальные знания по этой теме, советуем прочитать этот текст.Изображение главного примера этого текста: шар стреляет лазером в игрока, когда тот попадает в поле видимости. У шара есть конечное количество состояний в игре — бездействие, прицеливание и атакаПо словам пользователя, недавно он закончил свою мобильную игру Orbus и решил поделиться техниками, которые применял в разработке. Использование конечных автоматов в игре даёт несколько преимуществ.Если организовать весь код в виде чётко прописанных состояний, то это может предотвратить множество ошибок.Это помогает спланировать все состояния, в которых может находиться игровой объект.Прописанные переходы между состояниями гарантируют, что объекты не попадут в странные или незапланированные состояния.Также это позволяет легко сериализовать игровые объекты.Поведение шара можно определить как последовательность из трёх состояний: бездействие, прицеливание, атака. Чтобы следить за тем, как долго продолжается то или иное состояние, используются таймеры: cooldownTimer и stateTimer. Вот список правил:шар стреляет, если видит игрока, и если он перезарядился;во время прицеливания шар испускает слабый луч, который показывает, что скоро будет атака и игроку пора уворачиваться;атака наносит урон игроку.tick(delta) { switch(this.state) { case State.Normal: if (this.cooldownTimer > 0) this.cooldownTimer -= delta; if (this.canSeePlayer() && this.cooldownTimer <= 0) { this.transitionToState(State.Targeting); } break; case State.Targeting: this.stateTimer -= delta; if (this.stateTimer <= 0) { this.transitionToState(State.Firing); } break; case State.Firing: this.stateTimer -= delta; if (this.intersectLaserPlayer(this.targetLocation, this.player)) { this.doDamageToPlayer(); } if (this.stateTimer <= 0) { this.transitionToState(State.Normal); } break; } }Теперь нужно прописать переходы между состояниями. Когда шар входит в новое состояние, он определяет все свойства, необходимые для этого состояния. Можно использовать таймер, чтобы объект оставался в определённом состоянии в течение какого-то времени.transitionToState(newState) { switch(newState) { case State.Targeting: this.stateTimer = this.TIME_TARGETING; // Set our firing target to the player's current location. this.targetLocation = this.player.location; break; case State.Firing: // Do validation if (this.state !== State.Targeting) { this.log("Invalid state!!! Can't fire without targeting first"); return; } this.stateTimer = this.TIME_FIRING; break; case State.Normal: // Only do a cooldown if we're currently firing. if (this.state === States.Firing) { this.cooldownTimer = this.TIME_COOLDOWN; } else { this.cooldownTimer = 0; } break; } this.state = newState; }Все таймеры хранятся в виде чисел — это упрощает сохранение и восстановление текущего состояния лазера.serialize() { return { cooldownTimer: this.cooldownTimer, state: this.state, stateTimer: this.stateTimer, targetLocation: this.targetLocation, } }Если представить состояние в виде конечного автомата, то это гарантирует, что состояния всегда будут адекватно и последовательно переходить от одного к другому: бездействие — прицеливание — атака. Поэтому шар никогда не выстрелит, пока не прицелится. #код #опыт #основы
Разраб VVVVVV одобряет.
Тут написано через switch для наглядности. Можно было бы конечно написать через какой-нибудь словарь делегатов, типа
IDictionary<State, Func<State, State>>
Но так было бы не иллюстративно.
кошмар! сразу видно, сильный и независимый инди, работает один
Для ++ есть классная либа, для быстрого описания конечных автоматов.
мне понравился формат статьи - коротко и понятно, о чем-то полезном на практике. побольше бы такого - типо, каждый день по небольшой фиче.
Комментарий недоступен
Так это оно и есть, только упрощённое максимально