2

Component という基本クラスがあります。I2DComponent と I3DComponent の 2 つのインターフェイスもあります。現在、I2DComponent に取り組んでいます。

実装:

/// <summary>
/// Represtions a 2D object. These objects will be drawn after 3D objects,
/// and will have modifiers automatically provided in the editor.
/// </summary>
public interface I2DComponent
{
    /// <summary>
    /// Gets or sets the rectangle.
    /// </summary>
    /// <value>The rectangle.</value>
    Rectangle Rectangle { get; set; }

    /// <summary>
    /// Gets the local position on the game screen.
    /// </summary>
    /// <value>The local position on the game screen.</value>
    /// <remarks>The rectangle position minus the parent screen position.</remarks>
    Rectangle LocalPosition { get; }

    /// <summary>
    /// Gets or sets the scale.
    /// </summary>
    /// <value>The scale.</value>
    float Scale { get; set; }
}

問題は、マウスがその上にあるかどうかを確認するために、グローバル位置または Rectangle にアクセスする必要があることです。

if (component.Rectangle.Contains(mouse.Rectangle))
{
    do somthing.
}

しかし、それを移動するためにアクセスしているときは、ローカル位置にアクセスしたいだけなので、位置 50、50 にゲーム画面がある場合、ローカル位置を 0、0 に設定でき、それが一番上になります親ゲーム画面の左隅。本当の問題は、誤ってRectangleを設定したくないということだと思います

component.Rectangle = new Rectangle(component.Rectangle.X + 5, component.Rectangle.Y + 5, component.Rectangle.Width, component.Rectangle.Height);

これは多かれ少なかれアクセサの設計上の問題であり、見た目を正しくしたいのですが、そうするのに苦労しています。

アップデート:

I2D コンポーネントが境界とスケールのみを持つように変更し、GameScreen にコンポーネントの現在の「グローバル」位置を取得する機能を持たせた場合はどうでしょうか。

アップデート:

これらの 2D オブジェクトはすべて、3D 空間にない hud または GUI オブジェクトとして描画されるオブジェクトです。ただの説明。

アップデート:

私は今、再帰的にそれを行うことを考えていますが、どうすればこれを行うことができるかわかりません。

4

3 に答える 3

3

ゲームオブジェクトのローカル位置を変更することだけを心配します。画面の位置ではありません。カメラの位置とビューポートに依存するためです。

画面上の何かの位置を見つけるには、2 つの方法があります。1 つ目はカメラを取得するアクセサ メソッドを使用する方法で、もう 1 つはカメラを最初の変換方法として使用する方法です。私は後者を好むので、次のように書き直します。

public interface I2DComponent
{
    /// <summary>
    /// Gets or sets the local (world) bounds of the object.
    /// </summary>
    /// <value>The rectangle.</value>
    Rectangle Bounds{ get; }

    /// <summary>
    /// Gets or sets the scale.
    /// </summary>
    /// <value>The scale.</value>
    float Scale { get; set; }
}

次に、カメラには2つの方法があります

public class Camera
{
    public Rectangle WorldToScreen(Rectangle rect);
    public Rectangle ScreenToWorld(Rectangle point);
}

このようにして、画面をまったく気にしないカプセル化されたオブジェクトと、すべての変換を処理するカメラを保持します。

于 2009-06-25T17:44:39.867 に答える
1

これらの Rectangles がどのように使用されるかについて懸念している場合、なぜそれらを公開するのでしょうか? コンポーネントには独自の がGetGlobalX, GetGlobalY, GetLocalX, GetLocalYあり、さらにIsInside(X, Y)マウスオーバーをチェックするための があるかもしれません。次に、内部で Rectangles を使用するかどうかを好みに応じて使用できます。

カプセル化、よ。もはや朝食だけではありません。

于 2009-06-25T17:39:28.170 に答える
1

あなたの最初の質問は、これらの 2D オブジェクトが何であるかについて少し曖昧であり、最良の答えはより厳密な定義に依存します。

これらがゲーム ワールド内のオブジェクト (例: 頭の上の名前、ビルボード) である場合、ワールド ポジションが必要であり、別の回答で説明されているように、通常はカメラ クラスを介してそれを画面の位置に変換します。

ただし、これらがメニュー、フォーム、ヘッドアップ ディスプレイなどの GUI オブジェクトである場合は、まったく異なります。その場合、親要素に対する相対的な位置 (つまり、ローカル位置) を保存するだけでよく、描画は再帰的に行うことができます。各要素の位置は基本的に、その親のグローバル位置に独自のローカル位置を加えたものであり、ローカル位置がグローバル位置でもあるトップレベルの親までツリーを上ります。

編集:明確にするために与えられた例。Python スタイルのテストされていない疑似コード (C# がわからないため、申し訳ありません)

def draw(element, parentScreenX, parentScreenY):
    # Draw this element relative to its parent
    screenX = parentScreenX + element.localX
    screenY = parentScreenY + element.localY    
    render(element, screenX, screenY)
    # Draw each child relative to this one
    for childElement in element.children:
        draw(childElement, screenX, screenY)

# Normal usage (root element should be at 0,0, 
# and typically just an invisible container.)
draw(rootElement, 0, 0)


# Slightly different mathematics for the mouseover test,
# but that's just personal preference
def elementAtPos(element, posX, posY):
    # Translate that space to element local space
    posX -= element.localX
    posY -= element.localY
    # Compare against this element's dimensions
    if (posX, posY) is within (0, 0, element.width, element.height):
        # it's within this element - now check children
        for childElement in element.children:
            # Do this same check on the child element (and its children, etc)
            targetedChildElement = elementAtPos(childElement, posX, posY) 
            if targetedChildElement is not None:
                return targetedChildElement
        # it wasn't within any of our descendants so return this one
        return element 
    # It wasn't within our bounds at all, so return None
    return None

#Normal usage
targetedElement = elementAtPos(rootElement, mouseScreenX, mouseScreenY)

2 つの別個の関数が必要な場合があります。1 つはターゲット要素を正確に取得するもの (上記のように) で、もう 1 つはマウスが要素の上にある場合に単に返すもので、複数の要素に対して同時に true を返す場合があります。ボタン、ボタンが配置されているパネル、パネルが配置されているフォームなど。これを実装する方法はいくつかありますが、おそらく最も簡単なのは、再帰呼び出しを実装して、任意の要素が画面位置を取得できるようにすることです。

def screen_position(element):
    if element.parent is not None:
        (parentLocalX, parentLocalY) = screen_position(element.parent)
    else:
        (parentLocalX, parentLocalY) = (0,0)
    return (element.localX + parentLocalX, element.localY + parentLocalY)

親と子の間の循環参照に注意してください。

これらはすべて 0,0 のルート要素を必要とします。これにより、ルート要素のスクリーン スペースとローカル スペースの間の変換が容易になります。これらは事実上同じだからです。その後、残りのアルゴリズムはローカル空間で機能します。

于 2009-06-25T19:54:03.533 に答える