#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 и позволить ему самому отрисовываться в целевом окне. Отличный ответ, и, вероятно, то, что я буду делать с этого момента вместо этого!