Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Trying to adapt to SFML3  (Read 485 times)

0 Members and 1 Guest are viewing this topic.

Deedolith

  • Newbie
  • *
  • Posts: 5
    • View Profile
    • Email
Trying to adapt to SFML3
« on: December 23, 2024, 03:00:39 pm »
Hello,

I am following to the book SFML Game Development, by Artur Moreira and Artur Vogelius Jan Haller,
who's sources can be found on GitHub: https://github.com/SFML/SFML-Game-Development-Book/tree/master/05_States

I am at chapter 5, and trying to achieve the loading screen (classes LoadingState and ParallelTask).
From what I understood in the migration guide, I need to replace old sf::thread by std thread and old sf::mutex by std::mutex.

When the thread terminate, I am experiencing a crash without much informations beside "Abord has been called".

With my average C++ skills, I am not used to using threads, I might have done something wrong in the ParallelTask class or the LoadingState class.
Here are the versions I wrote:

ParallelTask class:
#include <thread>
#include <mutex>

#include <SFML/System/Clock.hpp>

class ParallelTask
{
private:
        std::thread mThread;
        bool mFinished;
        sf::Clock mElapsedTime;
        std::mutex mMutex;
private:
        void runTask();
public:
        ParallelTask();
        void execute();
        bool isFinished();
        float getCompletion();
};
#include <SFML/System/Time.hpp>

#include "ParallelTask.h"

void ParallelTask::runTask()
{
        // Dummy task - stall 10 seconds
        bool ended = false;
        while (!ended)
        {
                mMutex.lock(); // Protect the clock
                if (mElapsedTime.getElapsedTime().asSeconds() >= 10.f)
                        ended = true;
                mMutex.unlock();
        }

        { // mFinished may be accessed from multiple threads, protect it
                mMutex.lock();
                mFinished = true;
                mMutex.unlock();
        }
}

ParallelTask::ParallelTask() :
        mElapsedTime{},
        mFinished{ false },
        mMutex{},
        mThread{}
{
}

void ParallelTask::execute()
{
        mFinished = false;
        mElapsedTime.restart();
        mThread = std::thread(&ParallelTask::runTask, this);
}

bool ParallelTask::isFinished()
{
        mMutex.lock();
        bool isFinished{ mFinished };
        mMutex.unlock();
        return isFinished;
}

float ParallelTask::getCompletion()
{
        mMutex.lock();
        float elapsedTime{ mElapsedTime.getElapsedTime().asSeconds() / 10.f };
        mMutex.unlock();
        return elapsedTime;
}

LoadingState class:
#pragma once

#include <optional>

#include <SFML/System/Time.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/RectangleShape.hpp>

#include "StateStack.h"
#include "State.h"
#include "ParallelTask.h"

class LoadingState :
    public State
{
private:
        sf::Text mLoadingText;
        sf::RectangleShape mProgressBarBackground;
        sf::RectangleShape mProgressBar;
        ParallelTask mLoadingTask;
private:
        void setCompletion(float percent);
public:
        LoadingState(StateStack& stack, Context context);
        void draw() override;
        bool update(sf::Time dt) override;
        bool handleEvent(std::optional<sf::Event> const& event) override;
};
#include <SFML/Graphics/RenderWindow.hpp>

#include "LoadingState.h"
#include "Fonts.h"
#include "Utilities.h"

void LoadingState::setCompletion(float percent)
{
        if (percent > 1.f) // clamp
                percent = 1.f;
        mProgressBar.setSize(sf::Vector2f(mProgressBarBackground.getSize().x * percent, mProgressBar.getSize().y));
}

LoadingState::LoadingState(StateStack& stack, Context context) :
        State{ stack, context },
        mLoadingText{ context.fonts->get(Fonts::ID::Sansation), "Loading ressources"},
        mProgressBarBackground{},
        mProgressBar{},
        mLoadingTask{}
{
        sf::RenderWindow& window{ *getContext().window };
        sf::Vector2f viewSize{ window.getView().getSize() };

        mLoadingText.setCharacterSize(20);
        centerOrigin(mLoadingText);
        mLoadingText.setPosition(sf::Vector2f{ viewSize.x / 2.f, viewSize.y / 2.f + 50.f });

        mProgressBarBackground.setFillColor(sf::Color::White);
        mProgressBarBackground.setSize(sf::Vector2f{ viewSize.x - 20.f, 10.f });
        mProgressBarBackground.setPosition(sf::Vector2f{ 10.f, mLoadingText.getPosition().y + 40.f });

        mProgressBar.setFillColor(sf::Color(100, 100, 100));
        mProgressBar.setSize(sf::Vector2f{ 200.f, 10.f });
        mProgressBar.setPosition(sf::Vector2f{ 10.f, mLoadingText.getPosition().y + 40.f });

        setCompletion(0.f);
        mLoadingTask.execute();
}

void LoadingState::draw()
{
        sf::RenderWindow& window{ *getContext().window };
        window.setView(window.getDefaultView());

        window.draw(mProgressBarBackground);
        window.draw(mProgressBar);
        window.draw(mLoadingText);
}

bool LoadingState::update(sf::Time dt)
{
        if (mLoadingTask.isFinished())
        {
                requestStackPop();
                requestStackPush(States::ID::Title);
        }
        else
                setCompletion(mLoadingTask.getCompletion());
        return true;
}

bool LoadingState::handleEvent(std::optional<sf::Event> const& event)
{
        return true;
}
 

Any tought ?

Thanks for reply.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11071
    • View Profile
    • development blog
    • Email
Re: Trying to adapt to SFML3
« Reply #1 on: December 23, 2024, 04:59:16 pm »
With std::thread you have to call join() at the end to make sure that the thread is terminated correctly before your main thread exits.
Official FAQ: https://www.sfml-dev.org/faq/
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Deedolith

  • Newbie
  • *
  • Posts: 5
    • View Profile
    • Email
Re: Trying to adapt to SFML3
« Reply #2 on: December 23, 2024, 10:40:10 pm »
So, I just needed to call join() in the destructor.

Thank you.

 

anything