2017-11-02 7 views
0

私はUnityのゲームで作業しています。複数のオブジェクト(ネット、ボックス、フープ)に衝突する複数のオブジェクト(リンゴ、オレンジ、バナナなど) 、など)。それぞれのマッチには特定の機能があります。 10個のオブジェクトと10個のコライダーオブジェクトがあるとすると、それは100個のメソッドです。 可能ならばswitch/if-elseステートメントを避けたいと思います。2つのパラメータを持つイベントを特定のメソッドにマップするためのエレガントな方法

現在、衝突が衝突型加速器のオブジェクトでトリガされ、その後、私は派遣に送信:

CollisionDispatchで
public class NetCollision : BaseCollider { 
CollisionDispatch dispatch; 

void OnCollisionEnter (Collision coll) 
{ 
    Fruit obj = coll.gameObject.GetComponent<Fruit>(); 
    dispatch.RegisterCollision (obj, this, coll); 
}} 

、私はそうのようなswitch文を持っている:

public void RegisterCollision(Fruit obj, BaseCollider collider, Collision collision) { 
    if (obj is Banana) { 
     BananaDispatch (obj as Banana, collider, collision) 
    } else if (obj is Apple) { 
     AppleDispatch (obj as Banana, collider, collision) 
    } ... 
} 

public void BananaDispatch (Banana obj, BaseCollider coll, Collision collision) { 
    if (coll is NetCollider) { 
    // Banana-NetCollider method 
    } else if (coll is BoxCollider) { 
    // Banana-BoxCollider method 
    } ... 
} 

は、このAですジェネリック医薬品を使用する状況?ジェネリック向けのリファクタリングを試しましたが、コードをクリーンアップしていないようです。

+0

簡単な方法は、 'Dictionary >'を保ち、オブジェクト型に基づいてパラメータを渡すことです。 –

+0

@ManfredRadlwimmerありがとう、私はこれを考慮した。しかし、2つの重要な辞書が必要です。果物とコライダーの両方がコールする関数を決定するので、私は辞書を2つ必要とします。関数はどこかで定義しなければならないので、私はそれに反対すると思うし、辞書は余計に見えた。 –

答えて

0

多型性と戦略または状態パターンを使用できます。たとえば :あなたはちょうどBaseColliderからすべてのinheritesためFruit、そしてHandleCollisionからすべてのinheritesためDispatchメソッドをオーバーライドします

public class CollisionDispatch : MonoBehaviour 
{ 
    public void RegisterCollision(Fruit obj, BaseCollider collider, Collision collision) 
    { 
     obj.Dispatch(collider, collision); 
    } 
} 

public interface ICollisionableFruit 
{ 
    //add method for each collision type 
    void HandleNetCollision(Collision collision); 
    void HandleElseCollision(Collision collision); 
} 

public abstract class Fruit : ICollisionableFruit 
{ 
    public virtual void Dispatch(BaseCollider collider, Collision collision) 
    { 
     collider.HandleCollision(this, collision); 
    } 

    //declare all of interface's methods as abstract 
    public abstract void HandleNetCollision(Collision collision); 
    public abstract void HandleElseCollision(Collision collision); 
} 


public class Banana : Fruit 
{ 
    //override all methods 
    public override void HandleNetCollision(Collision collision) 
    { 
     Debug.LogFormat("HandleNetCollision for {0}", this.GetType()); 
    } 

    public override void HandleElseCollision(Collision collision) 
    { 
     Debug.LogFormat("HandleElseCollision for {0}", this.GetType()); 
    } 
} 

public abstract class BaseCollider 
{ 
    CollisionDispatch dispatch; 

    void OnCollisionEnter(Collision coll) 
    { 
     var obj = coll.gameObject.GetComponent<Fruit>(); 
     dispatch.RegisterCollision(obj, this, coll); 
    } 

    public abstract void HandleCollision(ICollisionableFruit fruit, Collision collision); 
} 

public class NetCollision : BaseCollider 
{ 
    public override void HandleCollision(ICollisionableFruit fruit, Collision collision) 
    { 
     Debug.LogFormat("NetCollision HandleCollision"); 
     fruit.HandleNetCollision(collision); 
    } 
} 

public class ElseCollision : BaseCollider 
{ 
    public override void HandleCollision(ICollisionableFruit fruit, Collision collision) 
    { 
     Debug.LogFormat("NetCollision HandleCollision"); 
     fruit.HandleElseCollision(collision); 
    } 
} 

。また、BaseColliderの継承者ごとにFruitに抽象的な特定のメソッドを追加し、それが異なるコリジョン処理の依存する果物タイプを意味する場合はHandleCollisionから呼び出すことができます。

さらに多くのコライダーを使用する必要がある場合は、ICollisionableFruitFruitに新しいメソッドを追加するだけで、各メソッドは継承されます。

明らかに柔軟な解決策ではありませんが、ifよりも優れています。

+0

何か間違っていない限り、私はHandleCollision に対して1つの関数オーバーライドしか実装できませんが、果物ごとに1つずつ、10個の関数が必要です。 –

+0

私は投稿とコードを編集しています。それを確認してください。 –

1

私はあなたがタイプFruitObstacleの特定のオブジェクトがそれらと衝突するときにすべて異なって反応しなければならないFruitの束を持っていることを理解しています。

  • OnCollisionEnterメソッドを持つことになり、基本クラスFruitを作成します。私は、継承使用します。このため

  • CollideWithNet,CollideWithBox ...をすべてabstractの方法で作成します。
  • OnCollisionEnterの方法でメソッドを実行して、衝突するオブジェクトの種類を検出します(これを検出する方法はたくさんあります)。tagsFruitObstacleなどに使用して対応するメソッドを呼び出します。
  • Fruitクラス(Banana : FruitApple : Fruit ...)を継承するフルーツの子をすべて作成します。
  • 各フルーツのCollideWithBoxCollideWithNet ...メソッドのカスタムロジックを実装します。

あなたはいつもあなたがvirtualメソッドの代わりabstractメソッドを使用してFruitクラスにロジックを追加することができ、すべての果物のために同じであるいくつかのロジックを持っている場合は(あなたの継承クラスで基本クラスを呼び出すことを忘れないでくださいbase.MethodName)。

+0

入力いただきありがとうございます。それが最善の方法かもしれませんが、私はswitch文を避け、すべてを動的に実行させようとしていました。残念なことに、GetComponent は基本クラスを返し、適切な派生クラスでオーバーロードされたメソッドに渡すと、ベースとして登録されます。だから最後に、これが唯一の方法かもしれない –

+0

私はあなたがスイッチを避けることができるとは思わない、すべての組み合わせフルーツ障害がスイッチを必要とする別の結果を持っている場合。私はあなたが残りの部分について何を意味するのか分かりません。GetComponentは要求するクラスを返します.Fruitを返すとFruitを返すでしょう。もしあなたがバナナを返すなら、それはバナナを返すでしょう(オブジェクトにはバナナまたはフルーツスクリプト)。 – Quentin

+0

OnCollisionEnter関数では、フルーツがどれかわからないので、GetComponent で果物オブジェクトを取得します。これは私の問題の要点です。スイッチのステートメントにチェックを入れなければなりません。完璧な世界では、GetComponent の結果を、派生したフルーツクラスを取る関数オーバーライドの束に渡すことができ、ランタイムはどちらが適切な関数であるかを決定します。私は、すべての果物が機能のオーバーライドとして説明されるという保証はないので、これを行うことはできないと思いますか? –