0

オブジェクトに「親」を適用できるメニュー システムに取り組んでいます。CLabelフォントをレンダリングするクラスがあります。それらがすべて含まれCEditBoxている基本クラスへのポインターを持つクラスがあります。次に、オブジェクトCControlへのポインターを宣言し、aのコンストラクター内のa をポイントします。 CControlCLabelCEditBox

私が知る限り、これはすべて正しく設定されています。なぜ私はそれを言うのですか?この機能:

void CControl::RenderChildren() {
    for( int i = 0; i < Children.size(); i++ ) {


        //Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        //Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();
    }
}

編集ボックスをレンダリングし、ラベル オフセット (_X、_Y のメンバーであるCControl) を使用してラベルをレンダリングします。それらは 0,0 にあるため、テキストは左上隅にレンダリングされます。

ここで、2 行のコメントを外して次の関数を使用すると、テキストがレンダリングされません。

void CControl::RenderChildren() {
    for( int i = 0; i < Children.size(); i++ ) {


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();
    }
}

値を具体的にテストするために呼び出しを使用exit(variable)しましたが、いくつかのことがわかります。_X と _Y は、子に対して正しく設定されています。親は目的の場所にレンダリングされるため、親の _X、_Y 値には影響しません。

次に、私が呼び出す関数を見てみましょう。

void CControl::X(int x) {                                           
    //      Set Component's X coordinate
    _X = x;
    //if(Pappy != NULL) { 
    //  _X = _X + Pappy->X(); 
    //}
}

void CControl::Y(int y) {                                           
    //      Set Component's Y coordinate
    _Y = y;
    //if(Pappy != NULL) {
    //  _Y = _Y + Pappy->Y();
    //}
}

コメントアウトされた行は気にしないでください。これは、それが何かの子であるかどうかを確認し、_X 関数と _Y 関数のオフセットを変更するつもりだったからです。子をレンダリングするときにのみオフセットを適用します(したがって、上記の元の関数)。簡単に言えば、これらの関数は渡された整数を現在のオフセットに設定するだけです。

次に、関数の読み取りバージョン:

int CControl::X() {                                             
    //      Get Component's X coordinate
    //if(Pappy != NULL) return _X - Pappy->X();
    return _X;
}

int CControl::Y() {                                             
    //      Get Component's Y coordinate
    //if(Pappy != NULL) return _Y - Pappy->Y();
    return _Y;
}

また、値を返すだけで、2行がどのようになっているのかわかりません

    Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
    Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

レンダリングが失敗する原因となっています。

私のCLabel::OnRender()機能を調べても、問題を検出できません。

void CLabel::OnRender() {

    if(Visible) {
        SDL_Surface* Surf_Text; 
        Surf_Text = Font.BlendedUTF8Surface();
        Text_Font.OnLoad(Surf_Text);
        Text_Font.RenderQuad(_X,_Y);
        SDL_FreeSurface(Surf_Text);
    }
}

ここにコードが入っていることはわかっています。ステートメントexit(variable)内で使用しました。オフセット ラインの有無にかかわらず SDL_Surface 値に違いはなく、ある場合にはレンダリングされますが、別の場合にはレンダリングされないため、テキストがレンダリングされることifをテストSurf_Text->wしました。Surf_Text->hさらに、この関数で _X と _Y をテストして、実際に適切な場所にレンダリングされていることを確認しました。彼らです。

これは、レンダリング順序に問題がある可能性があることを意味しますが、この関数で dX と dY を親オフセットを適用した後の整数値に置き換えるText_Font.RenderQuad(_X,_Y);Text_Font.RenderQuad(_X+dX,_Y+dY);、テキストは問題なくレンダリングされます。だから私が考えることができるすべて、私はテストしました。これらの 2 つのオフセット ラインがレンダリングを無効にする理由がわかりません。

    Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
    Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

[解決済み]

うん。行って、ちょっと考えてみました。

フレーム 1)

Children[i]->X(Children[i]->X()+_X) // will be 100 and exit correctly.

フレーム 2)

Children[i]->X(Children[i]->X()+_X) // will be 200 if I don't add the exit

等...

私の機能を作りました:

void CControl::RenderChildren() {
    for( int i = 0; i < Children.size(); i++ ) {


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();

        Children[i]->X(Children[i]->X()-_X);
        Children[i]->Y(Children[i]->Y()-_Y);
    }
}

完璧にレンダリングします。私が誰の時間を無駄にしなかったことを願っています。

【解決策2】

選択した回答を読んで、レンダリング中にオフセットを適用する関数を書き直すことにしました。以下に示すように、子をレンダリングする前にオフセットを計算するだけです。

void CControl::RenderChildren() {
    for( int i = 0; i < Children.size(); i++ ) {

        int xOff, yOff;
        xOff = yOff = 0;                                //Initialize offsets

        CControl * Kin = this;                          //Pointer to current parent
        while( Kin != NULL ) {                          //Until there is no more parent container repeat
            xOff = Kin->X() + xOff;                     //Add X of Parent to the current X offset total.
            yOff = Kin->Y() + yOff;                     //Add Y of Parent to the current Y offset total.
            Kin = Kin->GetParent();                     //Get next parent.  
        }

        Children[i]->OnRender(xOff,yOff);               //Render based on parental induced offset location

    }
}
4

1 に答える 1

1

私はあなたの間違いを1秒以内に見ました。だからあなたは誰の時間を無駄にしませんでした(あなた自身を除いて;))。とにかく次のようにします:

void CControl::RenderChildren() {
    for( int i = 0; i < Children.size(); i++ ) {


        Children[i]->X(Children[i]->X()+_X); //offset child _X with parent's _X
        Children[i]->Y(Children[i]->Y()+_Y); //offset child _Y with parent's _Y

        Children[i]->OnRender();

        Children[i]->X(Children[i]->X()-_X);
        Children[i]->Y(Children[i]->Y()-_Y);
    }
}

最適ではありません。あなたの場合、問題が発生している整数を使用しています。しかし、ある時点で float を使用することにしたとします

問題は、浮動小数点数で発生するすべての操作で丸め誤差が発生することです。(あなたの場合のように)反復的に行うと、数値が安定した点に収束するか、わずかに発散する可能性があります。原則として、単一の浮動小数点数が「流れる」操作を最小限に抑える必要があります。数学的には、プリアンブルとポストアンブルは互いに正反対のように見えるかもしれません。実際には、精度が制限されたコンピューターではそうではありません。

長い話を短くします:

オフセットをパラメーターとして受け取るように少し変更CControl::OnRenderして、レンダリング時にその場でオフセットの追加を適用する必要があります。余分な作業は気にしないでください。本当に問題がある場合は、プロファイラーを使用して真のボトルネックを特定します。パフォーマンスに関する特定の「アイデア」を念頭に置いてインターフェイスを設計しないでください。時期尚早の最適化はそれであり、それは良くありません。


ところで: StackOverflow では、自己解決した問題をマークする標準的な方法は、独自の解決策を自分の質問に対する回答に書き込んでから、それを承認済みとしてマークすることです。

于 2013-06-23T10:37:48.487 に答える