用SFML将文本居中显示在屏幕上

21

我正在Ubuntu 12.10上使用SFML 2.0库。

sudo apt-get install libsfml-dev

现在我正在尝试让一个sf::Text居中显示。为了做到这一点,我将文本的原点(用于进行位置设置、旋转等变换的地方)设置为sf::Text的边界框的中心,然后将其位置设置为屏幕中心,如下所示:

//declare text
sf::Font font;
sf::Text text;
font.loadFromFile("helvetica.ttf");
text.setFont(font);
text.setString("RANDOMTEXT");
text.setCharacterSize(100);
text.setColor(sf::Color::White);
text.setStyle(sf::Text::Regular);

//center text
sf::FloatRect textRect = text.getLocalBounds();
text.setOrigin(textRect.width/2,textRect.height/2);
text.setPosition(sf::Vector2f(SCRWIDTH/2.0f,SCRHEIGHT/2.0f));

这段代码无法正常运行,文本的位置与预期偏差较大,例如在x轴上偏3,在y轴上偏25。奇怪的是,如果你创建一个 sf::RectangleShape 来表示文本的包围盒,那个矩形会被正确地居中并调整大小以适应文本,但文本仍然会在该包围盒外面绘制,并出现前面提到的偏移。

在这张图片中,我标记了屏幕中心,用一个 sf::RectangleShape 代替了文本的包围盒,并绘制了 sf::Text。

http://i.imgur.com/4jzMouj.png

这段代码生成了上述图像:

const int SCRWIDTH = 800; 
const int SCRHEIGHT = 600;

int main() {
sf::RenderWindow window;
window.create(sf::VideoMode(SCRWIDTH,SCRHEIGHT), "MYGAME" ,sf::Style::Default);
window.setMouseCursorVisible(false);
window.setVerticalSyncEnabled(true);

sf::Font font;
sf::Text text;
font.loadFromFile("helvetica.ttf");
text.setFont(font);
text.setString("RANDOMTEXT");
text.setCharacterSize(100);
text.setColor(sf::Color::White);
text.setStyle(sf::Text::Regular);

sf::FloatRect textRect = text.getLocalBounds();

text.setOrigin(textRect.width/2,textRect.height/2);
text.setPosition(sf::Vector2f(SCRWIDTH/2.0f,SCRHEIGHT/2.0f));

sf::RectangleShape rect(sf::Vector2f(textRect.width,textRect.height));
rect.setFillColor(sf::Color::Blue);
rect.setOrigin(rect.getSize().x/2,rect.getSize().y/2);
rect.setPosition(text.getPosition());

sf::RectangleShape RectW;
RectW.setSize(sf::Vector2f(SCRWIDTH, 0.0));
RectW.setOutlineColor(sf::Color::Red);
RectW.setOutlineThickness(1);
RectW.setPosition(0, SCRHEIGHT / 2);
sf::RectangleShape RectH;
RectH.setSize(sf::Vector2f(0.0, SCRHEIGHT));
RectH.setOutlineColor(sf::Color::Red);
RectH.setOutlineThickness(1);
RectH.setPosition(SCRWIDTH / 2, 0);

while(window.isOpen()) {
    window.clear();
    window.draw(rect);
    window.draw(text);
    window.draw(RectW);
    window.draw(RectH);
    window.display();
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
        window.close();
    }
}
return 1;
}

如何使其居中并位于其边界框内,正如它应该在那里一样?

3个回答

40

sf::Text::getLocalBounds() 返回的 topleft 字段值不为零,因此在居中原点时不能忽略它们。

请尝试使用以下方法代替:

//center text
sf::FloatRect textRect = text.getLocalBounds();
text.setOrigin(textRect.left + textRect.width/2.0f,
               textRect.top  + textRect.height/2.0f);
text.setPosition(sf::Vector2f(SCRWIDTH/2.0f,SCRHEIGHT/2.0f));

1
请查看我的答案,其中包含一些重要细节。 - Andrew
2
window.getView().getCenter(); should be used instead of sf::Vector2f(SCRWIDTH/2.0f,SCRHEIGHT/2.0f) - Robert Russell

6

我认为这是SFML文本渲染中已知的问题。请前往他们的问题跟踪器并查看此问题

另外,您可以在他们的开发论坛上提问。那里的开发人员总是非常友好和乐于助人。


2
除了Emile's answer之外,您应该使用以下代码中的maxHeight,而不是使用textRect.height
for (size_t characterIndex = 0; characterIndex < text.size(); ++characterIndex)
{
  currentHeight = font->getGlyph(text[characterIndex], 12, false).bounds.height;
  if (currentHeight > maxHeight)
  {
    maxHeight = currentHeight;
  }
}

解释 在这里:

这是因为第一行的对齐高度基于最高字符的高度 -- 即使它不在你的字符串中。这是为了保持第一行的顶部稳定,即使你在第一行添加更高的字符。

确切的计算并不简单:你需要遍历第一行的所有字符,计算最高字符的大小,将其从 sf::Text 的 CharacterSize 中减去,并将结果从边界矩形的高度中减去。


另一个非常重要的注意事项:如果您在非整数位置绘制文本,可能会破坏文本的外观。这似乎也包括原点...(因此,请将您的原点+位置四舍五入到最近的整数!)


1
很好,你也提到了浮点数转整数的问题。知道它会影响其他所有东西,而不仅仅是文本,这是很好的。(最明显的是,在像素完美纹理映射的小细节部分,特别是旋转时...它们可能由于缺失/不受控制的四舍五入而变得非常错误。) - Sz.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接