我正在开发一个菜单系统,该系统允许我将"父"应用于对象。我有一个CLabel
类,用于呈现字体。我有一个CEditBox
类,它有一个指向它们都属于的基本CControl
类的指针。然后,我声明一个指向CControl
对象的指针,并将其指向CEditBox
的构造函数中的CLabel
。
据我所知,这一切都安排得很好。我为什么这么说?此功能:
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,因此会在左上角渲染文本。
现在,如果我取消对这两行的注释并使用下面的函数,文本就不会呈现。
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;
}
同样只是返回值,我无法弄清楚两行
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);
}
}
我知道代码在这里输入。我在if
语句中使用了exit(variable)
。我测试了Surf_Text->w
和Surf_Text->h
,知道文本正在渲染,因为带有或不带有偏移线的SDL_Surface值没有差异,并且它在一种情况下渲染,但在另一种情况中不会。此外,我在这个函数中测试了_X和_Y,只是为了验证它们确实在正确的位置进行了渲染。确实如此。
这意味着渲染顺序可能有问题,但在这个函数中,如果我用Text_Font.RenderQuad(_X+dX,_Y+dY);
替换Text_Font.RenderQuad(_X,_Y);
,其中dX和dY只是应用父偏移量后的整数值,那么文本渲染就很好。所以我能想到的一切,我都测试过了。我不明白为什么这两条偏移线会破坏渲染。
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
}
}
我确实在一秒钟内看到了你的错误。所以你没有浪费任何人的时间(除了你自己的时间)。无论如何,这样做:
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); } }
不是最优的。在您的案例中,如果遇到任何问题,则使用整数但是说有一次你决定使用浮动:
问题是,对浮点数字进行的每一次运算都会产生舍入误差。迭代地进行(就像在您的情况下一样)可能会将数字收敛在一个稳定点,也可能会稍微发散。一般来说,您应该尽量减少单个浮点数"流动"的操作。从数学上讲,你的前序和后序可能看起来像是彼此的精确逆。实际上,在精度有限的计算机上,它们不是。
长话短说:
您应该稍微更改CControl::OnRender
以将偏移量作为参数,以便在渲染时原位应用偏移量添加。不要介意额外的工作。如果这真的是一个问题,请使用探查器来识别真正的瓶颈。不要在设计界面时考虑到某些关于性能的"想法"。过早的优化就是这样,这是没有好处的。
BTW:在StackOverflow上,标记自行解决问题的规范方法是将自己的解决方案写入自己问题的答案中,然后标记为已接受