Partage
  • Partager sur Facebook
  • Partager sur Twitter

Violation d'accès en lecture.

    15 juin 2021 à 12:29:22

    Bonjour,

    J'essaye de faire un jeu en SFML 2.5.1 et TGUI 0.9. Dans le menu option, j'ai des boutons qui ont un callback quand l'utilisateur appuie dessus:

    buttonBack->onPress(&callbackMainMainMenu, om);
    buttonLeftResolution->onPress([&] { callbackResolution(om, gui, false); });
    buttonRightResolution->onPress([&] { callbackResolution(om, gui, true); });

    Pour buttonBack, aucun problème, il transmet bien l'objet om (classe OptionsMenu) et aucune erreur de lecture. Par contre, pour les boutons de résolution, une erreur de lecture. Quand je debug, je vois que la variable om est null dans le callback donc j'essaye de faire autrement:

    buttonRightResolution->onPress(&callbackResolution, std::ref(om), std::ref(gui), true);

    Mais la même erreur s'invite.

    main.cpp

    #include <iostream>
    #include <SFML/Graphics.hpp>
    #include <TGUI/TGUI.hpp>
    #include "ScenesIncluded.h"
    
    
    int main()
    {
    	std::vector<SceneManager*> Scenes;
    	int screen = 0;
    
    	sf::RenderWindow app(sf::VideoMode(1024, 768), "Carlita", sf::Style::Fullscreen);
    	app.setFramerateLimit(30);
    	app.setVerticalSyncEnabled(false);
    
    	MainMenu mm;
    	Scenes.push_back(&mm);
    	OptionsMenu om;
    	Scenes.push_back(&om);
    
    	while (screen >= 0)
    	{
    		screen = Scenes[screen]->Run(app);
    	}
    
    	return EXIT_SUCCESS;
    }

    SceneManager.h

    #pragma once
    #ifndef DEF_SCENE_MANAGER
    #define DEF_SCENE_MANAGER
    
    #include <SFML/Graphics.hpp>
    #include <TGUI/TGUI.hpp>
    
    class SceneManager
    {
    public:
    	virtual int Run(sf::RenderWindow& App) = 0;
    };
    
    #endif // !DEF_SCENE_MANAGER
    

    MainMenu.h

    #pragma once
    #ifndef DEF_MAIN_MENU
    #define DEF_MAIN_MENU
    
    #include <iostream>
    #include "SceneManager.h"
    
    class MainMenu : public SceneManager
    {
    private:
    	bool playing;
    	int numScene;
    
    public:
    	MainMenu(void);
    	virtual int Run(sf::RenderWindow& App);
    	void setPlaying(bool state);
    	void setNumScene(int num);
    };
    
    #endif // !DEF_MAIN_MENU
    

    MainMenu.cpp

    #include "MainMenu.h"
    
    void callbackBtPlay()
    {
    	std::cout << "Button play pressed" << std::endl;
    }
    
    void callbackBtOptions(MainMenu* mm)
    {
    	mm->setNumScene(1);
    	mm->setPlaying(false);
    }
    
    void callbackBtGoalGame()
    {
    	std::cout << "Button goal of the game pressed" << std::endl;
    }
    
    void callbackBtBestScores()
    {
    	std::cout << "Button best scores pressed" << std::endl;
    }
    
    void callbackQuit(MainMenu *mm)
    {
    	mm->setPlaying(false);
    }
    
    void updateTextSize(tgui::GuiBase& gui)
    {
    	const float windowHeight = gui.getView().getRect().height;
    	gui.setTextSize(static_cast<unsigned int>(0.035f * windowHeight));
    }
    
    void loadWidgets(tgui::GuiBase& gui, MainMenu *mm)
    {
    	updateTextSize(gui);
    	gui.onViewChange([&gui] {updateTextSize(gui); });
    
    	auto Font = tgui::Font("verdana.ttf");
    
    	auto buttonRenderer = tgui::ButtonRenderer();
    	buttonRenderer.setFont(Font);
    	buttonRenderer.setRoundedBorderRadius(20.f);
    	buttonRenderer.setBorders(5);
    	buttonRenderer.setBorderColor(tgui::Color(168, 33, 219));
    	buttonRenderer.setBackgroundColor(tgui::Color(255, 255, 255));
    	buttonRenderer.setTextColor(tgui::Color(168, 33, 219));
    	buttonRenderer.setBackgroundColorHover(tgui::Color(168, 33, 219));
    	buttonRenderer.setTextColorHover(tgui::Color(255, 255, 255));
    	buttonRenderer.setBackgroundColorDown(tgui::Color(100, 33, 129));
    
    	auto buttonPlay = tgui::Button::create("JOUER");
    	buttonPlay->setSize({ "50%", "10%" });
    	buttonPlay->setPosition({ "25%", "15%" });
    	buttonPlay->setRenderer(buttonRenderer.getData());
    	gui.add(buttonPlay);
    
    	auto buttonOptions = tgui::Button::create("OPTIONS");
    	buttonOptions->setSize({ "50%", "10%" });
    	buttonOptions->setPosition({ "25%", "30%" });
    	buttonOptions->setRenderer(buttonRenderer.getData());
    	gui.add(buttonOptions);
    
    	auto buttonGoalGame = tgui::Button::create("BUT DU JEU");
    	buttonGoalGame->setSize({ "50%", "10%" });
    	buttonGoalGame->setPosition({ "25%", "45%" });
    	buttonGoalGame->setRenderer(buttonRenderer.getData());
    	gui.add(buttonGoalGame);
    
    	auto buttonBestScores = tgui::Button::create("MEILLEURS SCORES");
    	buttonBestScores->setSize({ "50%", "10%" });
    	buttonBestScores->setPosition({ "25%", "60%" });
    	buttonBestScores->setRenderer(buttonRenderer.getData());
    	gui.add(buttonBestScores);
    
    	auto buttonQuit = tgui::Button::create("QUITTER");
    	buttonQuit->setSize({ "50%", "10%" });
    	buttonQuit->setPosition({ "25%", "75%" });
    	buttonQuit->setRenderer(buttonRenderer.getData());
    	gui.add(buttonQuit);
    
    	buttonPlay->onPress(&callbackBtPlay);
    	buttonOptions->onPress(&callbackBtOptions, mm);
    	buttonGoalGame->onPress(&callbackBtGoalGame);
    	buttonBestScores->onPress(&callbackBtBestScores);
    	buttonQuit->onPress(&callbackQuit, mm);
    }
    
    MainMenu::MainMenu(void)
    {
    	playing = true;
    	numScene = 0;
    }
    
    int MainMenu::Run(sf::RenderWindow& App)
    {
    	sf::Event Event;
    	tgui::GuiSFML gui{ App };
    
    	numScene = 0;
    	playing = true;
    	
    	try
    	{
    		loadWidgets(gui, this);
    	}
    	catch (const tgui::Exception& e)
    	{
    		std::cerr << "Failed to load TGUI Widgets: " << e.what() << std::endl;
    		return -1;
    	}
    
    	App.setMouseCursorVisible(false);
    	sf::Image cursor;
    	sf::Sprite cursorSprite;
    	sf::Texture cursorTexture;
    
    	if (cursor.loadFromFile("cursor.png"))
    	{
    		if (cursorTexture.loadFromImage(cursor))
    		{
    			cursorSprite.setTexture(cursorTexture);
    		}
    		else
    			App.setMouseCursorVisible(true);
    	}
    	else
    		App.setMouseCursorVisible(true);
    
    	while (playing)
    	{
    		while (App.pollEvent(Event))
    		{
    			gui.handleEvent(Event);
    
    			if (Event.type == sf::Event::Closed) return -1;
    			if (Event.type == sf::Event::MouseMoved)
    			{
    				cursorSprite.setPosition(Event.mouseMove.x, Event.mouseMove.y);
    			}
    		}
    
    		App.clear(sf::Color(255, 255, 255));
    		gui.draw();
    		App.draw(cursorSprite);
    		App.display();
    
    	}
    
    	gui.removeAllWidgets();
    
    	if (numScene != 0) return numScene;
    
    	return -1;
    }
    
    void MainMenu::setPlaying(bool state)
    {
    	playing = state;
    }
    
    void MainMenu::setNumScene(int num)
    {
    	numScene = num;
    }

    OptionsMenu.h

    #pragma once
    #ifndef DEF_OPTIONS_MENU
    #define DEF_OPTIONS_MENU
    
    #include <iostream>
    #include <map>
    #include "SceneManager.h"
    
    class OptionsMenu : public SceneManager
    {
    private:
    	bool playing;
    	int numScene;
    	std::vector<std::map<char, int>> allResoltions;
    	std::vector<int> allFps;
    	bool isVsync;
    	bool isFullScreen;
    	int indexResolution;
    	int indexFps;
    
    public:
    	OptionsMenu(void);
    	virtual int Run(sf::RenderWindow& App);
    	void setPlaying(bool state);
    	void setNumScene(int num);
    	void setIndexResolution(int num);
    	void setIndexFps(int num);
    	void setVsync(bool state);
    	void setFullScreen(bool state);
    	std::vector<std::map<char, int>> getAllResolution();
    	std::vector<int> getAllFps();
    	bool getVsync();
    	bool getFullScreen();
    	int getIndexResoltion();
    	int getIndexFps();
    };
    
    #endif // !DEF_OPTIONS_MENU
    

    OptionsMenu.cpp

    #include "OptionsMenu.h"
    
    void callbackMainMainMenu(OptionsMenu *om)
    {
    	om->setPlaying(false);
    	om->setNumScene(0);
    }
    
    void callbackResolution(OptionsMenu *om, tgui::GuiBase& gui, bool upIndex = true)
    {
    	int currentIndex = om->getIndexResoltion();
    	if (upIndex) om->setIndexResolution(currentIndex + 1);
    	else om->setIndexResolution(currentIndex - 1);
    
    	tgui::Button::Ptr currentLabelResolution = gui.get<tgui::Button>("resolution");
    	currentLabelResolution->setText("TextChanged");
    	
    }
    
    void updateTextSizes(tgui::GuiBase& gui)
    {
    	const float windowHeight = gui.getView().getRect().height;
    	gui.setTextSize(static_cast<unsigned int>(0.035f * windowHeight));
    }
    
    void loadWidgets(tgui::GuiBase& gui, OptionsMenu* om)
    {
    	updateTextSizes(gui);
    	gui.onViewChange([&gui] {updateTextSizes(gui); });
    
    	auto Font = tgui::Font("verdana.ttf");
    
    	auto buttonRenderer = tgui::ButtonRenderer();
    	buttonRenderer.setFont(Font);
    	buttonRenderer.setRoundedBorderRadius(20.f);
    	buttonRenderer.setBorders(5);
    	buttonRenderer.setBorderColor(tgui::Color(168, 33, 219));
    	buttonRenderer.setBackgroundColor(tgui::Color(255, 255, 255));
    	buttonRenderer.setTextColor(tgui::Color(168, 33, 219));
    	buttonRenderer.setBackgroundColorHover(tgui::Color(168, 33, 219));
    	buttonRenderer.setTextColorHover(tgui::Color(255, 255, 255));
    	buttonRenderer.setBackgroundColorDown(tgui::Color(100, 33, 129));
    
    	auto labelRendererN = tgui::LabelRenderer();
    	labelRendererN.setFont(Font);
    	labelRendererN.setTextStyle(tgui::TextStyle::Bold);
    
    	auto labelRendererE = tgui::LabelRenderer();
    	labelRendererE.setFont(Font);
    	labelRendererE.setBackgroundColor(tgui::Color(255, 255, 255));
    	labelRendererE.setBorderColor(tgui::Color(168, 33, 219));
    	labelRendererE.setPadding(tgui::Padding({ "50%", "10%", "100%", "10%" }));
    	labelRendererE.setBorders(5);
    
    
    	auto buttonBack = tgui::Button::create("RETOUR");
    	buttonBack->setSize({ "25%", "10%" });
    	buttonBack->setPosition({ "50%", "75%" });
    	buttonBack->setRenderer(buttonRenderer.getData());
    	gui.add(buttonBack);
    
    	auto labelResolution = tgui::Label::create(L"Résolution:");
    	labelResolution->setPosition({ "10%", "5%" });
    	labelResolution->setRenderer(labelRendererN.getData());
    	gui.add(labelResolution);
    
    	std::vector<std::map<char, int>> allResolutions = om->getAllResolution();
    	std::map<char, int> currentResolution = allResolutions[om->getIndexResoltion()];
    	std::string currentResolutionStr = std::to_string(currentResolution['x']) + "x" + std::to_string(currentResolution['y']);
    	auto labelResolutionChoice = tgui::Button::create(currentResolutionStr);
    	labelResolutionChoice->setSize({ "40%", "5%" });
    	labelResolutionChoice->setPosition({ "30%", "5%" });
    	labelResolutionChoice->setRenderer(buttonRenderer.getData());
    	labelResolutionChoice->setEnabled(false);
    	gui.add(labelResolutionChoice, "resolution");
    
    	auto buttonLeftResolution = tgui::Button::create("<");
    	buttonLeftResolution->setSize({ "3%", "5%" });
    	buttonLeftResolution->setPosition({ "26.5%", "5%" });
    	buttonLeftResolution->setRenderer(buttonRenderer.getData());
    	gui.add(buttonLeftResolution);
    
    	auto buttonRightResolution = tgui::Button::create(">");
    	buttonRightResolution->setSize({ "3%", "5%" });
    	buttonRightResolution->setPosition({ "70.5%", "5%" });
    	buttonRightResolution->setRenderer(buttonRenderer.getData());
    	gui.add(buttonRightResolution);
    
    	buttonBack->onPress(&callbackMainMainMenu, om);
    	buttonLeftResolution->onPress([&] { callbackResolution(om, gui, false); });
    	buttonRightResolution->onPress([&] { callbackResolution(om, gui, true); });
    	//buttonRightResolution->onPress(&callbackResolution, std::ref(om), std::ref(gui), true);
    }
    
    OptionsMenu::OptionsMenu(void)
    {
    	playing = false;
    	numScene = 1;
    	allFps = {
    		30,
    		60,
    		90,
    		120,
    		144,
    		240,
    		360,
    		0
    	};
    	allResoltions = {
    		{
    			{ 'x' , 1024 },
    			{ 'y' , 768 }
    		},
    		{
    			{ 'x' , 1280 },
    			{ 'y' , 1024 }
    		},
    		{
    			{ 'x' , 1366 },
    			{ 'y' , 768 }
    		},
    		{
    			{ 'x' , 1440 },
    			{ 'y' , 900 }
    		},
    		{
    			{ 'x' , 1600 },
    			{ 'y' , 900 }
    		},
    		{
    			{ 'x' , 1680 },
    			{ 'y' , 1050 }
    		},
    		{
    			{ 'x' , 1920 },
    			{ 'y' , 1080 }
    		},
    		{
    			{ 'x' , 1920 },
    			{ 'y' , 1200 }
    		},
    		{
    			{ 'x' , 2560 },
    			{ 'y' , 1080 }
    		},
    		{
    			{ 'x' , 2560 },
    			{ 'y' , 1440 }
    		},
    		{
    			{ 'x' , 3440 },
    			{ 'y' , 1440 }
    		},
    		{
    			{ 'x' , 3840 },
    			{ 'y' , 1080 }
    		},
    		{
    			{ 'x' , 3840 },
    			{ 'y' , 2160 }
    		},
    	};
    	isVsync = true;
    	isFullScreen = true;
    	indexResolution = 0;
    	indexFps = 0;
    }
    
    void OptionsMenu::setPlaying(bool state)
    {
    	playing = state;
    }
    
    void OptionsMenu::setNumScene(int num)
    {
    	numScene = num;
    }
    
    void OptionsMenu::setIndexResolution(int num)
    {
    	indexResolution = num;
    	if (indexResolution > allResoltions.size() - 1) indexResolution = 0;
    	if (indexResolution < 0) indexResolution = allResoltions.size() - 1;
    }
    
    void OptionsMenu::setIndexFps(int num)
    {
    	indexFps = num;
    }
    
    void OptionsMenu::setVsync(bool state)
    {
    	isVsync = state;
    }
    
    void OptionsMenu::setFullScreen(bool state)
    {
    	isFullScreen = state;
    }
    
    std::vector<std::map<char, int>> OptionsMenu::getAllResolution()
    {
    	return allResoltions;
    }
    
    std::vector<int> OptionsMenu::getAllFps()
    {
    	return allFps;
    }
    
    bool OptionsMenu::getVsync()
    {
    	return isVsync;
    }
    
    bool OptionsMenu::getFullScreen()
    {
    	return isFullScreen;
    }
    
    int OptionsMenu::getIndexResoltion()
    {
    	return indexResolution;
    }
    
    int OptionsMenu::getIndexFps()
    {
    	return indexFps;
    }
    
    int OptionsMenu::Run(sf::RenderWindow& App)
    {
    	sf::Event Event;
    	tgui::GuiSFML gui{ App };
    
    	numScene = 1;
    	playing = true;
    
    	try
    	{
    		loadWidgets(gui, this);
    	}
    	catch (const tgui::Exception& e)
    	{
    		std::cerr << "Failed to load TGUI Widgets: " << e.what() << std::endl;
    		return -1;
    	}
    
    	App.setMouseCursorVisible(false);
    	sf::Image cursor;
    	sf::Sprite cursorSprite;
    	sf::Texture cursorTexture;
    
    	if (cursor.loadFromFile("cursor.png"))
    	{
    		if (cursorTexture.loadFromImage(cursor))
    		{
    			cursorSprite.setTexture(cursorTexture);
    		}
    		else
    			App.setMouseCursorVisible(true);
    	}
    	else
    		App.setMouseCursorVisible(true);
    
    	while (playing)
    	{
    		while (App.pollEvent(Event))
    		{
    			gui.handleEvent(Event);
    
    			if (Event.type == sf::Event::Closed) return -1;
    			if (Event.type == sf::Event::MouseMoved)
    			{
    				cursorSprite.setPosition(Event.mouseMove.x, Event.mouseMove.y);
    			}
    		}
    
    		App.clear(sf::Color(255, 255, 255));
    		gui.draw();
    		App.draw(cursorSprite);
    		App.display();
    	}
    
    	gui.removeAllWidgets();
    
    	if (numScene != 1) return numScene;
    
    	return 0;
    }

    Merci pour toute aide apporté.

    • Partager sur Facebook
    • Partager sur Twitter
      19 juin 2021 à 16:55:29

      Bonjour,

      Quand tu fais:

      buttonBack->onPress(&callbackMainMainMenu, om);

       tu transmets la valeur de ton pointeur om à onPress(), il utilise plus tard cette valeur pour appeler la callback.

      Quand tu fais:

      buttonLeftResolution->onPress( [&]{ callbackResolution(om, gui, false); } );

       tu transmets par référence (à cause du [&]) la variable om de ta fonction à la lambda. Mais ta variable om disparaît dès que tu quittes loadWidgets(). Donc plus tard la callback sera appelées en lisant la valeur d'une om qui n'existe plus.

      Il faut transmettre la valeur de om, surtout pas en prendre la référence. Un code qui devrait mieux marcher (gui est par référence, om est par valeur):

      buttonLeftResolution->onPress( [&gui,om]{ callbackResolution(om, gui, false); } );
      • Partager sur Facebook
      • Partager sur Twitter

      En recherche d'emploi.

      Violation d'accès en lecture.

      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
      • Editeur
      • Markdown