6

そこで私は C# XNA 4.0 で 2D ゲームを作成していますが、またしても些細な問題に出くわしました。長方形。_ 基本的なコリジョンを使用する場合、これはほぼ必須です。作成されたほとんどすべてのゲーム オブジェクトには、長方形が必要です。次に、X を変更したり、衝突をチェックしたり、その他のことを行います。そして、終わりなき戦いが始まるobjectName.Rectangle.Whatever。これを回避するために、もちろん、これらにアクセスする objectName プロパティ/メソッドのクラスを提供します。

それから私はあえて夢を見ました。すべてのドローアブルが継承される基本的なゲーム オブジェクト クラスを作成し、ペアレント化、正確なローカル座標 (フロート)、およびテクスチャ/スプライト バッチの保持を可能にする壮大な設計がありました。これを完成させるために、Rectangle から継承し、Rectangle が保持するすべてのメソッドと属性を使用する準備ができました。何かが Rectangle を必要とするときはいつでも、objectName.Rectangle ではなく、objectName と言うほど怠惰になることがあります。

それから私は気づいた、チャンスではありません。私の非常に賢いアイデアが粉々に砕かれたので、私は最初は落ち込んでいました。それ以来、私の完璧な小さなクラスは四角形を保持し、必要に応じてそれにアクセスするさまざまなメソッドとプロパティを備えています。また、XNA DrawableGameComponent から継承する機会もありました。長い目で見れば、これはより実用的でしたが、draw メソッドや update メソッドを表示し、rectangle の呼び出しを見るたびに、自分が望んでいたことを実行する希望はあったのだろうかと疑問に思うことがよくあります。私ができたはずの巧妙な回避策はありましたか?それとも、Rectangle から継承して、私の手から本当に封印されていたのでしょうか?

XNA で提供される DrawableGameComponent クラスを使用すると、ほとんどのゲーム オブジェクト関連のアクションをクラスの Update() メソッド内で発生させることができますが、クラスの外では毎回、Rectangle のプロパティではなく Rectangle 自体を参照する必要があります実際、私のオブジェクトはあらゆる点で、実際には、強化された Rectangle であることを考えると腹が立ちます。そして、もう一度、私は自分自身に尋ねることができます:

事前定義された構造体から継承する方法、またはプロジェクトにあなたの印象を与える方法はありますか (回避策)?

4

3 に答える 3

16

いいえ、継承しませんが、拡張メソッドを使用して Rectangle オブジェクトに多くの「デフォルト」機能を追加できます。例えば

  //(inside a static class)
  public static int GetSurface(this Rectangle rect){return rect.Width * rect.Height;}

  //calling
  Rectangle rect;
  var s = rect.GetSurface();

そうは言っても、私が通常行うことは、上記の構造体をカプセル化することです。そのクラスをベース オブジェクトとして使用し、演算子を追加して、暗黙的に Rectangle にキャストできるようにします。そうすれば、キャストせずに長方形を必要とするメソッドに渡すことができます。

    public class MyRect //class so you can inherit from it, but you could make your own struct as well
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public int Right { get { return X + Width; } }
        public int Bottom{ get { return Y + Height; } }

        public static implicit operator Rectangle(MyRect rect)
        {
            return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
        }

        public static implicit operator MyRect(Rectangle rect)
        {
            return new MyRect { X = rect.X, Y = rect.Y, Width = rect.Width, Height = rect.Height };
        }

    }       
 }

これで、手動で、または既存のものから独自の rect を作成できます。

  MyRect rect = ARectangleVar

また、キャストせずに Rectangle を期待する従来のメソッドで使用できます

于 2012-06-16T17:56:41.420 に答える
4

考えられる回避策は次のとおりです(これをMyClass、 Rectangle プロパティを持つあなたが話しているクラスに入れます):

public static implicit operator Rectangle(MyClass obj)
{
    return obj.Rectangle;
}

これにより、たとえば、 を期待するメソッドにオブジェクトを渡すことができ、機能しRectangleます。真の継承とは異なり、存在する Rectangle は、MyClass渡したものと同じインスタンスではなく、値から作成された単なる構造体であることに注意してください。

于 2012-06-16T17:55:01.870 に答える
0

値型は、クラス型に適用される継承のスタイルとは基本的に互換性がありませんが、コンパイラが派生間の双方向の同一性保持変換を認識するような方法で「派生構造体」を宣言できると便利です。タイプとオリジナル。派生した構造体には、"Base" と呼ばれるフィールドが 1 つだけ必要です (ただし、C# コンパイラはこのキーワードbaseを代用として受け入れることができます)。その型は、派生する構造体の型です。名前が周囲の型の名前と一致しない「Base」のすべてのメンバーは、囲んでいる構造のメンバーと見なされます。

「派生構造体」が提供する主なものですが、現在欠けているものは次のとおりです。

  1. 構文間接化のレイヤーを追加することなく、ラップされた構造体のメンバーにアクセスする機能。たとえば、「Point」から派生したタイプのインスタンス「MyFancyPoint」がある場合、「MyFancyPoint.Base.X += 5」ではなく、「MyFancyPoint.X += 5」と言うことができます。
  2. 一度に複数の暗黙的または明示的な型変換を行う機能。一般に C# では、直接変換が存在する場合を除いて、「X」から「Y」への変換のみが許可されます。これは、可能なすべての変換シーケンスを検索するのが困難であり、そうすると変換のシーケンスが曖昧になることが多いためです。採用すべきです。特定の構造体をラップするすべての型が相互同一性保存変換を伴う「クラウド」を表すと想定される場合、2 つの派生構造体 `XX:X` と `YY:Y` の間の変換は、明確に `X` への変換と見なすことができます。 、次に `Y`、次に `YY` (これは、`X` から `Y` への変換が存在する場合に有効です)。
  3. ある型のインスタンスへの ByRef を別の型のインスタンスへの ByRef と見なし、一方のフィールドへの ByRef を他方の対応するフィールドの ByRef と見なす機能。

ボックス化された派生型のアイテムが同じ派生型としてのみボックス化されていない可能性があることを受け入れる場合、これらの機能のいずれかをサポートするためにランタイムへの変更が必要になるかどうかはわかりません。ボックス化されたバージョンの構造体を恒等変換可能な派生構造体のインスタンスに直接キャストできるようにすると便利ですが、複雑さが増す可能性があります。ジェネリックを機能させるためにそのような動作が必要かどうかはわかりません。残念ながら、この種の決定を下す責任者の多くは、値型が本当に好きではないように感じます。.net の歴史の早い段階でいくつかの設計上の決定が行われたため (特に、「const ref」パラメーターの欠如と、ref)、構造体を意味的に正しい方法で動作させることは困難な場合があり、一部の実装者は、問題を修正する機能を追加するよりも、.net の処理を​​改善しない言い訳として構造体の問題を使用する方がよいと思います。

于 2012-06-17T17:11:59.533 に答える