Рисование текста, возвращенного из класса, приводит к остановке программы без ошибок

#c #crash #sfml

#c #сбой #sfml

Вопрос:

Он просто вылетает всякий раз, когда я пытаюсь нарисовать текстовый объект, возвращенный из FPS_Counter класса.

Я сделал перекрестные ссылки на документацию SFML, и, насколько я мог судить, я ничего не пропустил, и Visual также не дает мне никаких замечаний по поводу плохого кода.

 #include <SFML/Graphics.hpp>
#include <Windows.h>
#include <string>
#include <iostream>

using namespace std;

//takes frame render time and counts how many of those fits in a second
//then assigns that to a text object and returns it.
class FPS_Counter 
{
private:
    sf::Text text;
    unsigned int count = 0;
public:
    FPS_Counter() //setting up my fps counting object here
    {
        sf::Font font;
        if (!font.loadFromFile("pixel font 1.ttf")) { throw "Cannot find font 'pixel font 1.ttf'."; }
        text.setFont(font);
        text.setCharacterSize(24);
        text.setColor(sf::Color(255, 255, 0, 255));
    }
    sf::Text Count(sf::Time difference)
    {
        cout << "count called" << endl;
        if (difference.asSeconds() != 0) //dodging a divide by zero
        {
            count = 1 / (float)difference.asSeconds();
            text.setString("FPS: "   count);
            cout << "count returned number" << endl;
            return text;
        }
        text.setString("FPS: 0");
        cout << "count returned default" << endl;
        return text;
    }
};

int main()
{
    int mon_res_x = GetSystemMetrics(SM_CXSCREEN);
    int mon_res_y = GetSystemMetrics(SM_CYSCREEN);

    sf::RenderWindow window(sf::VideoMode(mon_res_x, mon_res_y), "SFML     works!");
    window.setPosition(sf::Vector2i(0,0));

    FPS_Counter fps;
    sf::Clock clock;
    sf::Time time;

    while (window.isOpen())
    {
        window.clear();

        time = clock.getElapsedTime(); //get time since last frame
        clock.restart();

        window.draw(fps.Count(time)); //draw fps count with given frame-time

        window.display();

        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
    }

    return 0;
}
  

Комментарии:

1. Базовый пример, приведенный в конце руководства по установке, сработал?

2. И вы не используете здесь исключение catching, как вы можете быть уверены, что ваш шрифт исправлен?

3. Ну, это не выбрасывается в консоль, поэтому я предполагаю, что загружается нормально, потому что, когда я пытался загрузить шрифт, отличный от юникода, ранее он зависал, прежде чем перейти к Count () и написать ‘count called’ в консоли. Код работает нормально до тех пор, пока он не вернет текстовый объект SFML функции draw обратно в основной цикл. Вот где происходит сбой.

4. Я думаю, что я только что решил свою собственную проблему. Я добавлял unsigned int в строку без ее преобразования, поэтому, когда я переместил содержимое класса в основной цикл, он выдавал на экран тарабарщину из случайных мест в памяти, таких как пути к включениям, случайные буквы и т.д. Я предполагаю, что причиной сбоев могло быть копирование этого и возврат его в вызов draw из класса.

5. Также кажется, что SFML не предназначен для копирования всего текста или графических классов, поэтому я должен создать текст перед классом и передать текст в качестве указателя на него.

Ответ №1:

Поскольку для отображения каждого кадра может потребоваться всего несколько миллисекунд, отсчет прошедших секунд всегда будет равен 0.
Вам нужно создать таймер в вашем классе fps counter и печатать текст FPS каждый раз, когда этот счетчик достигает 0, изменение вашего FPS в каждом кадре бесполезно, поскольку оно будет пересчитываться только каждую секунду:

 #include <SFML/Graphics.hpp>
#include <Windows.h>
#include <string>
#include <iostream>

using namespace std;

//takes frame render time and counts how many of those fits in a second
//then assigns that to a text object and returns it.
class FPS_Counter
{
private:
    sf::Text text;
    unsigned int count = 0;
    sf::Int32 countdown = 1000;
public:
    FPS_Counter() //setting up my fps counting object here
    {
        sf::Font font;
        if (!font.loadFromFile("pixel font 1.ttf")) { throw "Cannot find font 'pixel font 1.ttf'."; }
        text.setFont(font);
        text.setCharacterSize(24);
        text.setColor(sf::Color(255, 255, 0, 255));
    }
    sf::Text Count(sf::Int32 difference)
    {
        countdown -= difference; //Counts the time elapsed
        count  ; //Increment FPS
        cout << "count called" << endl;
        if (countdown < 0)
        {
            countdown  = 1000;
            text.setString("FPS: "   count);
            cout << "count returned number" << endl;
        }
        return text;
    }
};

int main()
{
    int mon_res_x = GetSystemMetrics(SM_CXSCREEN);
    int mon_res_y = GetSystemMetrics(SM_CYSCREEN);

    sf::RenderWindow window(sf::VideoMode(mon_res_x, mon_res_y), "SFML     works!");
    window.setPosition(sf::Vector2i(0, 0));

    FPS_Counter fps;
    sf::Clock clock;
    sf::Time time;

    while (window.isOpen())
    {
        window.clear();

        time = clock.restart(); //get time since last frame

        window.draw(fps.Count(time.asMilliseconds())); //draw fps count with given frame-time

        window.display();

        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
    }
    return 0;
}
  

Кроме того, (IMO) я бы рекомендовал отправить указатель текста вашему основному классу один раз с помощью функции «init», было бы проще обработать сбой при загрузке шрифта и увеличить частоту кадров в секунду, это также отделило бы ваш таймер от вашего рендеринга.

Комментарии:

1. Функционально это решает мою проблему намного лучше, чем я даже пытался это сделать. Но я намеренно пытался выполнить упражнение, в котором я хотел, чтобы FPS вычислялся и рисовался каждый кадр. Я решил проблему, которую я поставил здесь, полностью избегая ее. Вместо копирования текстового объекта, который нужно отрисовывать в цикле визуализации, я связал целевое окно с классом FPS_Counter, чтобы избежать проблем с копированием класса в SFML и позволить ему самому отрисовываться в целевом окне. Отличный ответ, и, вероятно, то, что я буду делать с этого момента вместо этого!