6

私が言いたいことの例として、コード内の何かのケーススタディを使用すると思います。

現在、コンポーネント ベースのゲーム システムのビヘイビア/アクション システムに取り組んでいます。ゲームオブジェクトには IBehaviorComponent と IActionComponent をアタッチすることができ、関連する詳細のみを表示し、以下を公開します。

public interface IBehaviorComponent : IBaseComponent
{
   IBehavior Behavior { get; }
}

public interface IActionComponent : IBaseComponent
{
   IAction Action { get; }
   void ExecuteAction(IGameObject target = null);
}

今のところ、これで問題ありません (少なくとも私にとっては!)。しかし、IActionComponent の実装を見ると、問題が発生し始めます。

たとえば、単純な IActionComponent の実装は次のとおりです。

public class SimpleActionComponent : IActionComponent
{
   public IAction Action { get; protected set; }

   public void ExecuteAction(IGameObject target = null)
   {
      Action.Execute(target);
   }

   public void Update(float deltaTime) { } //from IBaseComponent
}

しかし、時間指定されたスケジュールでアクションを実行できるようにする、より複雑な IActionComponent 実装を導入したいとしましょう。

public class TimedActionComponent : IActionComponent
{
   public IAction Action { get; protected set; }

   public float IdleTime { get; set; }

   public float IdleTimeRemaining { get; protected set; }

   public void ExecuteAction(IGameObject target = null)
   {
      IdleTimeRemaining = IdleTime;
   }

   public void Update(float deltaTime)
   {
      if (IdleTimeRemaining > 0f)
      {
         IdleTimeRemaining -= deltaTime;
      }
      else
      {
         Action.Execute(target);
      }
   }
}

そして今、IdleTime を公開して、外部の影響によって変更できるようにしたいとしましょう。最初の私の考えは、新しいインターフェースを作成することでした:

public interface ITimedActionComponent : IActionComponent
{
   float IdleTime { get; set; }

   float IdleTimeRemaining { get; set; }
}

ただし、ここでの問題は、コンポーネント システムがすべてを IBaseComponent の 1 レベル上に格納することです。したがって、GameObject のアクション コンポーネントは、ITimedActionComponent、IRandomizedActionComponent、さらには ICrashTheProgramActionComponent などではなく、IActionComponent として取得されます。コンポーネントの基本的なタイプ (IActionComponent、IRenderableComponent、IPhysicsComponent など) を超えて何が必要かを正確に知る必要なく、ゲームオブジェクトのコンポーネントの 1 つを照会できるようにしたいので、この理由が明らかであることを願っています。

取得した IActionComponent を対象の型にキャストしなくても、子クラスで定義されたこれらのプロパティを公開できる、これを処理するよりクリーンな方法はありますか? それとも、これを達成するための唯一の/最良の方法ですか?何かのようなもの:

public void IWantYouToAttackSuperSlow(IGameObject target)
{
   //Let's get the action component for the gameobject and test if it's an ITimedActionComponent...
   ITimedActionComponent actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;

   if (actionComponent != null) //We're okay!
   {
      actionComponent.IdleTime = int.MaxValue; //Mwhaha
   }
}

今、私はそれが唯一の方法だと考えていますが、私が知らない木工品にパターンが隠れているかどうか、または誰かがこれを達成するためのより良い方法を最初から提案できるかどうかを確認すると思いました.

ありがとう!

4

2 に答える 2

1

IActionComponentanを an にキャストダウンすることを示したコードITimedActionComponentは (私が見る限り) 避けられませんIdleTime。それらを使用するには、プロパティを認識している必要がありますよね?

ここでの秘訣は、あなたを使用するクラスがそれを処理する必要のない、見栄えの悪いコードを隠すことだと思いますIActionComponent
これを行う方法についての私の最初の考えは、を使用することFactoryです:

  public void IWantYouToAttackSuperSlow(IGameObject target)
{
   //Let's get the action component for the gameobject 
   IActionComponent actionComponent = ActionComponentsFactory.GetTimedActionComponentIfAvailable(int.MaxValue); 
}

そしてあなたの工場の方法:

public IActionComponent GetTimedActionComponentIfAvailable(IGameObject target, int idleTime)
{
var actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent;

   if (actionComponent != null) //We're okay!
   {
      actionComponent.IdleTime = int.MaxValue; //Mwhaha
   }
return (actionComponent != null)? actionComponent : target.GetComponent<IActionComponent>();
}
于 2012-09-11T22:24:55.313 に答える
0

そうです、サブタイプにキャストして特定の実装をテストするのは良い考えではありません。IGameObject提供した例から、何らかのアクションを実行したいものがあるように見えます。を引数としてIActionComponent取るメソッドを公開するのではなく、逆の方法でそれを行うことができます。つまり、実行できるアクションを1つ、または必要に応じて多く取ることができます。IGameObjectIGameObject

interface IActionComponent
{
    ExecuteAction();
}

interface IGameObject
{
    IActionComponent ActionComponent { get; }
}

次に、実行メソッドで

public void IWantYouToAttackSuperSlow(IGameObject target)
{
    target.ActionComponent.ExecuteAction();
}

IActionComponentの実装方法に応じて、ポリモーフィズムは正しいコードが実行されることを確認します。

ニーズに合っていると思われるコマンドパターンと呼ばれるパターンがあります。

于 2012-09-11T22:22:57.527 に答える