この概念を実装するための1つの受け入れられた方法はないと思いますが、ゲームでこれを通常どのように処理するかを共有したいと思います。コマンドデザインパターンとコンポジットデザインパターンを少し組み合わせたものです。
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;
}
次に、複合アクションの2つの実装があります。1つは並列実行用、もう1つは順次実行用です。ただし、並列処理とシーケンス処理自体がアクションであるため、これらを組み合わせてより複雑な実行フローを作成できるのが優れています。
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);
私は以前このシステムを使用してグラフィックアドベンチャーのすべてのゲームプレイを推進しましたが、おそらくほとんど何でも機能するはずです。また、実行ループと条件を作成するために使用される他のタイプの複合アクションを追加するのにも十分簡単でした。