Я не думаю, что есть один приемлемый способ реализации этой концепции, но я действительно хотел бы поделиться тем, как я обычно справляюсь с этим в своих играх. Это что-то вроде комбинации шаблона проектирования Command и шаблона Composite .
У меня есть абстрактный базовый класс для действий, который представляет собой не что иное, как обертку вокруг Update
метода, который вызывается в каждом кадре, и Finished
флаг, указывающий, когда действие закончилось.
abstract class Action
{
abstract void Update(float elapsed);
bool Finished;
}
Я также использую шаблон составного дизайна, чтобы создать тип действий, который может содержать и выполнять другие действия. Это тоже абстрактный класс. Сводится к:
abstract class CompositeAction : Action
{
void Add(Action action) { Actions.Add(action); }
List<Action> Actions;
}
Затем у меня есть две реализации составных действий, одна для параллельного выполнения и одна для последовательного выполнения . Но прелесть в том, что, поскольку параллель и последовательность сами являются действиями, их можно объединять для создания более сложных потоков выполнения.
class Parallel : CompositeAction
{
override void Update(float elapsed)
{
Actions.ForEach(a=> a.Update(elapsed));
Actions.RemoveAll(a => a.Finished);
Finished = Actions.Count == 0;
}
}
И тот, который управляет последовательными действиями.
class Sequence : CompositeAction
{
override void Update(float elapsed)
{
if (Actions.Count > 0)
{
Actions[0].Update(elapsed);
if (Actions[0].Finished)
Actions.RemoveAt(0);
}
Finished = Actions.Count == 0;
}
}
При этом в месте , это просто вопрос создания реализации конкретных действий, а также с использованием Parallel
и Sequence
действий для управления потоком выполнения. Я закончу примером:
// Create a parallel action to work as an action manager
Parallel actionManager = new Parallel();
// Send character1 to destination
Sequence actionGroup1 = new Sequence();
actionGroup1.Add(new MoveAction(character1, destination));
actionGroup1.Add(new TalkAction(character1, "Arrived at destination!"));
actionManager.Add(actionGroup1);
// Make character2 use a potion on himself
Sequence actionGroup2 = new Sequence();
actionGroup2.Add(new RemoveItemAction(character2, ItemType.Potion));
actionGroup2.Add(new SetHealthAction(character2, character2.MaxHealth));
actionGroup2.Add(new TalkAction(character2, "I feel better now!"));
actionManager.Add(actionGroup2);
// Every frame update the action manager
actionManager.Update(elapsed);
Я успешно использовал эту систему для управления всем игровым процессом в графическом приключении и раньше, но, вероятно, она должна работать практически для чего угодно. Также было достаточно просто добавить другие типы составных действий, которые использовались для создания циклов выполнения и условных выражений.