ゲームアクションを実行するためのパターン


11

ゲーム内でさまざまなアクションを実行するための一般的に受け入れられているパターンはありますか?プレーヤーがアクションを実行する方法、およびAIが移動、攻撃、自己破壊などのアクションを実行する方法。

現在、.NETジェネリックを使用してさまざまなアクションによって返されるさまざまなオブジェクトを指定する抽象BaseActionがあります。これはすべて、コマンドと同様のパターンで実装され、各アクションはそれ自体に責任を持ち、必要なすべてのことを行います。

私が抽象的である理由は、単一のActionHandlerを使用できるようにするためであり、AIはbaseActionを実装するさまざまなアクションをキューに入れることができます。そしてそれが一般的である理由は、いくつかの一般的なbeforeActionとafterActionの実装とともに、さまざまなアクションがアクションに関連する結果情報を返すことができるようにするためです(さまざまなアクションはゲーム内でまったく異なる結果をもたらす可能性があります)。

それで...これを行うためのより受け入れられた方法はありますか、またはこの音は大丈夫ですか?


それはいいですね、質問はキューとはどういう意味ですか?ほとんどのゲームは非常に迅速に応答しますか?「AIはさまざまなアクションをキューに入れることができる」
AturSams 2012

いい視点ね。キューはありません。ビジーかどうかを確認し、ビジーでない場合はアクションを実行するだけです。
Arkiliknam 2012

回答:


18

この概念を実装するための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);

私は以前このシステムを使用してグラフィックアドベンチャーのすべてのゲームプレイを推進しましたが、おそらくほとんど何でも機能するはずです。また、実行ループと条件を作成するために使用される他のタイプの複合アクションを追加するのにも十分簡単でした。


それは非常に素晴らしい解決策のように見えます。好奇心から、UIに何を描くかをどのように知らせますか ゲームオブジェクト(キャラクターなど)には、レンダリングの目的で何が起こったかを識別するために使用される状態が含まれていますか、それともそれ自体がアクションそのものですか?
Arkiliknam 2012

1
通常、私のアクションはエンティティの状態のみを変更し、レンダリングされた出力への変更は、アクション自体ではなく、その状態変更の結果として発生します。たとえば、イミディエイトモードレンダラーでDrawは、メソッドは既にエンティティの状態の上に構築されており、変更は自動的に行われるため、追加の手順は必要ありません。Flashのような保持モードレンダラーでは、観察可能なパターンを使用して、エンティティに変更を加えて表示オブジェクトに伝達したり、エンティティ自体の内部で手動で接続を作成したりできます。
David Gouveia 2012

1
最初の状況でCharacterは、クラスにPositionプロパティがありDraw、現在の値を読み取っPositionて正しい画像をそこに描画するメソッドがあるとします。この状況でPositionは、結果が画面に自動的に表示される値のみを更新する必要があります。
David Gouveia 2012

1
第2の状況は、あなたがたときに、あるCharacter持っているPosition財産を、それ代表団は、ある種のにレンダリングSprite自動的にシーングラフか何かでレンダリングされているオブジェクト。この状況では、キャラクターの位置とスプライトの位置の両方が常に同期していることを確認する必要があります。これにはもう少し作業が伴います。それでも、どちらの場合でも、アクションマネージャーがそれと何か関係がある必要がある理由はわかりません。:)
David Gouveia 2012

1
どちらの方法にも長所と短所があります。2Dゲームの2番目の方法を使用しましたが、すべてを同期させることは非常に複雑になるため、時々後悔しました。しかし、たとえば、どのエンティティがクリックされたのか、何を描画するべきか、または描画しないのかを検出しようとする場合など、利点もあります。レンダリングされるすべてのものが、N個のエンティティタイプに分散するのではなく、同じデータ構造内に含まれるためです。
David Gouveia 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.