Паттерны программирования игр
— Другой взгляд на паттерны проектирования
129
на таблицу внутренних виртуальных методов, с помо-
щью которой эти методы могут быть вызваны. В таком
случае нет смысла создавать более одного экземпляра.
Они все равно все будут одинаковые.
В этом случае вы сможете создать один
статический
экземпляр. Даже если у вас есть набор конечных автома-
тов, которые находятся одновременно в одном и том же
состоянии, они могут указывать на один и тот же экзем-
пляр, так как в нем не содержится никакой специфич-
ной информации о конкретной машине состояний.
Где
вы разместите получившийся статический класс,
остается на ваше усмотрение. Найдите место, в котором
будет какой-то смысл. Наш мы разместим в классе базо-
вого состояния, просто так, без причины:
{
public:
static StandingState standing;
static DuckingState ducking;
static JumpingState jumping;
static DivingState diving;
// 6 …
};
Каждое из указанных статических полей представля-
ет собой один экземпляр состояния, которое использу-
ется в игре. Чтобы заставить героиню прыгать, состоя-
ние «Стоять» должно выполнить примерно следующее:
if (input == PRESS_B)
{
heroine.state_ = &HeroineState::jumping;
heroine.setGraphics(IMAGE_JUMP);
}
Инстанцированные состояния
Хотя иногда такой способ не годится. Например, он
не сработает с состоянием «Пригнуться». Там есть поле
chargeTime_
, специфичное для героини в конкретном
Получился паттерн
Приспособленец
(Flyweight) (с. 47)
130
Состояние (State) —
Паттерны программирования игр
состоянии. Ненароком это может сработать в нашей игре,
если мы так и оставим только одну героиню. Но если мы
захотим добавить режим для двух игроков и у нас будут
на экране одновременно две героини, то мы столкнем-
ся с проблемами.
Нам придется создавать объект для каждого состоя-
ния при переходе в него. Это позволит каждому конеч-
ному автомату иметь собственный экземпляр состояния.
Конечно, если мы выделяем память под
новое
состояние,
нам надо освободить память из-под
текущего
. И здесь
следует быть осторожными, так как код, вызывающий
изменение, находится в методе текущего состояния. Мы
не хотим удалить
this
прямо из-под собственных ног.
А мы позволим
handleInput()
и
HeroineState
выбирать, когда возвращать новое состояние. Когда это
произойдет,
Heroine
удалит старое состояние и перей-
дет в новое, примерно так:
void Heroine::handleInput(Input input)
{
HeroineState* state = state_->handleInput(
*this, input);
if (state != NULL)
{
delete state_;
state_ = state;
}
}
Видите? Мы не удаляем предыдущее состояние, пока
его метод не вернет значение. Сейчас состояние «Сто-
ять» может перейти в состояние «Пригнуться» путем со-
здания нового экземпляра:
HeroineState* StandingState::handleInput(
Heroine& heroine, Input input)
{
if (input == PRESS_DOWN)
{
// 6 …
return new DuckingState();
}
Когда вы динамически
выделяете память для
состояний, вас, скорее
всего, беспокоит фраг-
ментация. Паттерн Пул
объектов (Object Pool)
(с. 388) способен здесь
помочь.
Do'stlaringiz bilan baham: |