Recently, I've started to learn SFML. The first thing I wanted to do was a simple menu - so I've created an interface for all menus, containing everything necessary for other menus in protected field. However, my code throws an exception at some point, and I have no idea, why.
#include <SFML/Graphics.hpp>
#include <iostream>
class Menu
{
protected:
sf::Color red;
sf::Color white;
std::vector<sf::Text> displayedText;
int currentOption{ 0 };
public:
virtual void draww(sf::RenderWindow& window) = 0;
virtual void clickButton() = 0;
virtual void moveUp() = 0;
virtual void moveDown() = 0;
};
class FirstMenu : public Menu
{
public:
FirstMenu(sf::RenderWindow& window)
{
sf::Text text;
sf::Font font;
if (!font.loadFromFile("arial.ttf"))
{
std::cout << "Font error. \n";
}
text.setFont(font);
text.setString("Play");
displayedText.push_back(text);
text.setString("Options");
displayedText.push_back(text);
displayedText[0].setFillColor(red);
displayedText[0].setPosition(20, 30);
displayedText[1].setPosition(30, 30);
}
virtual void clickButton()
{
switch (currentOption)
{
case 0:
std::cout << "Playing. \n";
break;
case 1:
std::cout << "Options. \n";
break;
}
}
virtual void moveUp()
{
currentOption++;
displayedText[currentOption].setFillColor(white);
for (int i = 0; i < displayedText.size(); i++)
{
if (i == currentOption)
{
displayedText[i].setFillColor(red);
}
}
}
virtual void moveDown()
{
currentOption--;
displayedText[currentOption].setFillColor(white);
for (int i = 0; i < displayedText.size(); i++)
{
if (i == currentOption)
{
displayedText[i].setFillColor(red);
}
}
}
virtual void draww(sf::RenderWindow& window)
{
if (!displayedText.empty())
{
for (int i = 0; i < displayedText.size(); i++)
{
window.draw(displayedText[i]); //Exception thrown here
}
}
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(500, 500), "SFML works!");
FirstMenu menu(window);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
menu.draww(window);
window.display();
}
return 0;
}
Text displayed while throwing exception is: "Unhandled exception in location 0x799B35BB (sfml-graphics-2.dll) 0xC0000005: Access violation while reading location 0x00000004"
The main issue I can see is that in the constructor of FirstMenu
you are
sf::Font font;
if (!font.loadFromFile("arial.ttf"))
{
std::cout << "Font error. \n";
}
text.setFont(font)
Essentially setting the text's font to a local font object. This is problematic because text in SFML doesn't copy the passed in font resource.
SFML's documentation on the text class states this about setFont
The font argument refers to a font that must exist as long as the text uses it. Indeed, the text doesn't store its own copy of the font, but rather keeps a pointer to the one that you passed to this function. If the font is destroyed and the text tries to use it, the behavior is undefined.
It is also worth noting that the setTexture
function for Shapes and Sprites behaves similarly as it doesn't store a copy of the texture resource.
The fix is to ensure that the font object is never destroyed while it is being used by a text object.
The simplest fixes include:
User contributions licensed under CC BY-SA 3.0