If you want a thread running fully for the game loop, can it not be the main thread?
That said, if you want a separate thread that does all the work, you should be able to do that by sending information to it whenever the main thread gets events.
It's worth noting but probably obvious that you shouldn't really be doing stuff to the window if the other thread is doing that.
Multi-threading is complicated so this may be wrong but I'm imagining something (slightly pseudo) like:
std::atomic<std::size_t> command{ 0u };
std::mutex windowMutex;
void game(sf::RenderWindow& window)
{
window.setActive(true);
bool isRunning{ true };
bool isPaused{ false };
while (isRunning)
{
if (command > 0u)
{
switch (command)
{
case 1u: // quit
isRunning = false;
break;
case 2u: // pause
isPaused = true;
command = 0u;
break
case 3u: // unpause
isPaused = false;
command = 0u;
break
}
}
if (!isPaused)
updateStuff();
while (windowMutex.isLocked()) { }
windowMutex.lock();
window.clear();
window.draw(things);
window.display();
windowMutex.unlock();
}
while (windowMutex.isLocked()) { }
windowMutex.lock();
window.close();
windowMutex.unlock();
}
int main()
{
std::thread game;
sf::RenderWindow window(sf::VideoMode(1920u, 1080u), "");
window.setFramerateLimit(300u);
window.setActive(false);
bool quit{ false };
bool isPaused{ false };
while (!quit)
{
sf::Event event;
if (window.waitEvent(event))
{
switch (event.type)
{
case sf::Event::Type::Closed:
quit = true;
command = 1u;
break;
case sf::Event::Type::KeyPressed:
switch (event.key.code)
{
case sf::Keyboard::Escape:
isPaused = !isPaused;
command = isPaused ? 2u : 3u;
break;
}
break;
}
}
}
game.join();
}
,which, it turns out, is very similar to your example code. One difference is that I haven't locked the mutex during waitEvent otherwise it stays locked while asleep and your other thread is halted.
I'm not sure how thread-safe sf::Window is in itself. Maybe at least waitEvent is thread-safe; the documentation suggests this approach anyway.
This function is typically used when you have a thread that is dedicated to events handling: you want to make this thread sleep as long as no new event is received.
sf::Event event;
if (window.waitEvent(event))
{
// process event...
}
Also, the thread should already be sleeping itself with setFramerateLimit; there should be no need to sleep it manually as well.
Setting a window as active is only for the targetting of rendering. Since nothing is being rendered in the main thread, it shouldn't need to be activated.