Partage

Erreur classe héritée de sf::RenderWindow SFML2

9 août 2018 à 8:10:36

Bonjour,

J'ai écrit une classe qui hérite de sf::RenderWindow pour mes besoins.

Pour la fenêtre, à sa construction, j'utilise bien sf::Style::Default. Pourtant, parfois quand je la lance j'ai bien les contours de la fenêtre avec les boutons fermer, réduire, agrandir mais parfois j'ai juste un carré noir sans contour...

Auriez-vous une idée d'où pourrait provenir l'erreur ?

Cordialement

Vous êtes demandeur d'emploi ?
Sans diplôme post-bac ?

Devenez Développeur web junior

Je postule
Formation
en ligne
Financée
à 100%
14 août 2018 à 13:51:33

Hello,

Je dirai ligne 37. Plus sérieusement, si tu pouvais poster le code de ta classe ce serait plus pratique et limite la manière dont tu l'utilises aussi :).

-
Edité par Guit0Xx 14 août 2018 à 13:52:35

...
14 août 2018 à 14:07:04

Si je ne l'ai pas posté, c'est pour une raison simple, il est très long :)

#include "functions.hpp"

int main(){
	const int WIDTH = 640;
	const int HEIGHT = 480;

	SfmlWindow app(sf::VideoMode(WIDTH, HEIGHT), "Sfml Window");

	app.center();

	return app.start();
}



#ifndef HEADER_SFML_WINDOW
#define HEADER_SFML_WINDOW

#include "SFML/SfmlWindowAbstraction.hpp"

/*!
* \class	SfmlWindow
* \brief	A class to manage an SFML Window
*/
class SfmlWindow : public SfmlWindowAbstraction, public Threadable<SfmlWindow> {
	THREADABLE

	/* Members of SfmlWindow */
	public:
		/* Constructors & Destructor of SfmlWindow */
			/*!
			* \brief	The class constructor
			*	\param[in]		mode		The video mode, so, the window size for example
			*	\param[in]		title		The window title
			*	\param[in]		style		The window style, default is \b sf::Style::Default
			*	\param[in]		settings	The OpenGL's context's settings, default is \b sf::ContextSettings()
			*/
			SfmlWindow(sf::VideoMode mode, const sf::String& title, sf::Uint32 style = sf::Style::Default, const sf::ContextSettings& settings = sf::ContextSettings());
			virtual ~SfmlWindow();
		/* Getters of SfmlWindow */
			
		/* Setters of SfmlWindow */
			
		/* Statics of SfmlWindow */
			
		/* Operators of SfmlWindow */
			
		/* Friends of SfmlWindow */
			
		/* Others members of SfmlWindow */
			/*!
			* \brief	Start the window
			*	\return		Return the value returned by onStop, default is \b 0
			*/
			int start();

	protected:
		/* Getters of SfmlWindow */
			
		/* Setters of SfmlWindow */
			
		/* Statics of SfmlWindow */
			
		/* Friends of SfmlWindow */
			
		/* Others members of SfmlWindow */
			#ifndef DOXYGEN_SHOULD_SKIP_THIS
				virtual void update();
			#endif //DOXYGEN_SHOULD_SKIP_THIS

	private:

	/* Atttributes of SfmlWindow */
	public:
		/* Global */
			
		/* Local */
			

	protected:
		/* Global */
			
		/* Local */
			

	private:
		/* Global */
			
		/* Local */
			
};

#endif //HEADER_SFML_WINDOW
#ifndef HEADER_SFML_WINDOW_ABSTRACTION
#define HEADER_SFML_WINDOW_ABSTRACTION

#include "SFML/SfmlDefines.hpp"

#ifndef DOXYGEN_SHOULD_SKIP_THIS
	#define START_FUNCTION\
	size_t fpsCounter{0};\
\
	sf::Clock gameClock;\
	sf::Clock fpsClock;\
\
	this->show();\
	/*KeyState::init();*/\
	this->onStart();\
\
	/* Starting treatments */\
		if(this->centered){ this->Center(); }\
	/***********************/\
\
	gameClock.restart();\
	fpsClock.restart();\
\
	while(_mainLoop){\
		_mutex.lock();\
			while(this->pollEvent(event)){\
				if(event.type == sf::Event::Closed){\
					this->close();\
				}\
				this->events(event);\
\
				this->listeners();\
			}\
		_mutex.unlock();\
\
		/*KeyState::update();*/\
		if(!this->launched()){ this->launch(); }\
\
		_mutex.lock();\
			if(this->isOpen()){\
				this->clear();\
				this->drawer();\
				this->display();\
			}\
		_mutex.unlock();\
\
		_mutex.lock();\
			/* FPS */\
				fpsCounter++;\
\
				if(fpsClock.getElapsedTime().asMilliseconds() >= 1000){\
					this->fps = fpsCounter;\
					fpsCounter = 0;\
					fpsClock.restart();\
				}\
			/*******/\
		_mutex.unlock();\
\
		microSleep(1);\
\
		_mutex.lock();\
			this->onEnd();\
		_mutex.unlock();\
\
		_mutex.lock();\
			/* Compute the remaining time for the image */\
				auto gameElapsed = gameClock.getElapsedTime();\
\
				if(gameElapsed.asMilliseconds() < this->remainingTime){\
					milliSleep(this->remainingTime - gameElapsed.asMilliseconds());\
				}\
\
				gameClock.restart();\
			/********************************************/\
		_mutex.unlock();\
	}\
\
	this->stop();\
	auto out = this->onStop();\
	/*KeyState::reset();*/\
\
	sf::RenderWindow::close();\
\
	return out;
#endif //DOXYGEN_SHOULD_SKIP_THIS

/*!
* \class	SfmlWindowAbstraction
* \brief	A class to manage an SFML Window
*/
class SfmlWindowAbstraction : public sf::RenderWindow {
	/* Members of SfmlWindowAbstraction */
	public:
		/* Constructors & Destructor of SfmlWindowAbstraction */
			/*!
			* \brief	The class constructor
			*	\param[in]		mode		The video mode, so, the window size for example
			*	\param[in]		title		The window title
			*	\param[in]		style		The window style, default is \b sf::Style::Default
			*	\param[in]		settings	The OpenGL's context's settings, default is \b sf::ContextSettings()
			*/
			SfmlWindowAbstraction(sf::VideoMode mode, const sf::String& title, sf::Uint32 style = sf::Style::Default, const sf::ContextSettings& settings = sf::ContextSettings());
			virtual ~SfmlWindowAbstraction();
		/* Getters of SfmlWindowAbstraction */
			size_t getFps()const { return this->fps; }
		/* Setters of SfmlWindowAbstraction */
			void setFps(size_t fps);
		/* Statics of SfmlWindowAbstraction */
			
		/* Operators of SfmlWindowAbstraction */
			
		/* Friends of SfmlWindowAbstraction */
			
		/* Others members of SfmlWindowAbstraction */
			/*!
			* \brief	Center the window after it has been started
			*	\param[in]		center		\b true or \b false, default is \b true
			*	\return		void
			*/
			void center(bool center = true){ this->centered = center; }

			/*! \brief	Show the window */
			void show();
			/*! \brief	Hide the window */
			void hide();
			/*! \brief	Stop the main loop of the window */
			void close();

	protected:
		/* Getters of SfmlWindowAbstraction */
			
		/* Setters of SfmlWindowAbstraction */
			
		/* Statics of SfmlWindowAbstraction */
			
		/* Friends of SfmlWindowAbstraction */
			
		/* Others members of SfmlWindowAbstraction */
			/*! \brief	Called just before the loop start */
			virtual void onStart(){}
			/*! \brief	Called just before the loop restart or end */
			virtual void onEnd(){}
			/*! \brief	Called just after the loop end */
			virtual int onStop(){ return 0; }

			/*! \brief	Called in a loop to treat each event */
			virtual void events(sf::Event&){}
			/*! \brief	Called in the same loop as events() but just after it */
			virtual void listeners(){}
			/*! \brief	Called in an other thread to not slow down the window */
			virtual void treater(){}
			/*! \brief	Called between a clear() and a display() */
			virtual void drawer(){}

			/*! \brief	Center the window on the desktop */
			void Center();

			#ifndef DOXYGEN_SHOULD_SKIP_THIS
				virtual void update();
			#endif //DOXYGEN_SHOULD_SKIP_THIS

	private:

	/* Atttributes of SfmlWindowAbstraction */
	public:
		/* Global */
			
		/* Local */
			

	protected:
		/* Global */
			
		/* Local */
			sf::Event event;

			size_t fps;
			sf::Int32 remainingTime;
			bool hidden;

			bool centered;

			/*! \brief	The time that the threadable class has to sleep after each update */
			long int sleeping;

			bool _mainLoop;

	private:
		/* Global */
			
		/* Local */
			
};

#endif //HEADER_SFML_WINDOW_ABSTRACTION




14 août 2018 à 15:13:20

mcabiocdel a écrit:

Si je ne l'ai pas posté, c'est pour une raison simple, il est très long :)

Au moins ça donne un aperçu. Et puis si le code est vraiment long, il y a toujours git ^^.

Bon sinon étant donné qu'il y a du multithreading la-dedans et que c'est un peu le bordel à mes yeux, ça dépasse clairement mes compétences. Là tout de suite le seul tuc qui me vient en tête c'est qu'à un moment ou un autre sf::Style se retrouve avec la valeur 0 (qui correspond à une fenêtre sans bordure ni élément, juste un carré noir).

Désolé de ne pouvoir t'aider :/.

...
14 août 2018 à 15:35:54

Malheureusement, je passe style à chaque constructeur, les uns à la suite des autres, et vu que ça marche mais pas à tous les coups, je ne sais pas quand la variable passerait à 0.

Pour ce qui est de Git, quand j'aurais "fini" les bases de mon projet je l'y mettrai ;)

15 août 2018 à 17:58:55

Salut,

Déjà, C'EST QUOI CETTE HORREUR DE MACRO ????

Le simple fait que ta macro START_FUNCTION soit définie dans une logique de compilation conditionnelle basée sur l'inexistence du symbole DOXYGEN_SHOULD_SKIP_THIS pose déjà un sérieux problème, car cela implique que, si ce symbole est défini, on risque de ne rien avoir en remplacement de START_FUNCTION :waw::waw:

Cela peut ne pas poser de problème, en fonction des situations dans lesquelles DOXYGEN_SHOULD_SKIP_THIS sera défini, mais, avec le code que tu nous donnes, on ne peut avoir aucune garantie à ce sujet !

Et puis, il y a toutes les inconguités de ta macro:

1- START_FUNCTION représente de toute évidence l'intégralité (ou très peu s'en faut) d'une fonction particulièrement complexe.  Mais, du coup, la question est : pourquoi n'en as tu pas fais tout bêtement une fonction ?

Dans le pire des cas, si c'est une fonction qui doit pouvoir être appelée (en tant que sous ensemble d'une fonction plus complexe encore) par n'importe quelle classe dérivée, pourquoi ne pas en faire une fonction protégée de ta classe SfmlWindowAbstraction ? cela reviendrait au même, mais, ca t'éviterait le recours à une macro.

Car les macros, c'est l'enfer! Voici quatre raisons (n'hésite pas à suivre les liens connexes représentés par #evil2 #evil3 et #evil4 ;) ) pour justifier ce jugement

2- Il faut comprendre que jouer à verrouiller / déverrouiller vingt fois (bon, d'accord, tu ne le fait pas vingt fois, mais quand meme :D ) ton mutex au fil de l'exécution de cette partie de code, c'est très clairement pas la meilleure manière de fonctionner!

Non seulement l'utilisation de mutexes, de manière générale, occasionne de très sérieuses contraintes au niveau des threads, au point que l'on peut très facilement en arriver à perdre tout l'intérêt de travailler avec des threads, mais, en plus, le verrouillage et le déverrouillage d'un mutex, ce n'est pas gratuit (très loin s'en faut)!

Si tu n'as pas d'autre choix que de travailler avec un mutex, arrange toi au moins pour limiter au maximum aussi bien le nombre de lock et de unlock (donc, dans l'idéal, pour n'avoir qu'un verrouillage et un déverrouillage) -- si possible -- pour limiter également au grand maximum le temps de verrouillage.

3- this ne sert absolument à rien dans le code :il fait clairement partie du code d'une fonction membre qui fait partie de la classe SfmlWindowAbstraction (ou d'une classe qui en dérive) il fait donc forcément référence à l'objet en cours de traitement, et il est donc implicite pour tout ce qui est accessible à partir de cet objet!

Y compris aux fonctions membre publiques et protégées des classes parentes!

Ensuite, tu devrais prendre la peine de réfléchir à la responsabilité que tu veux donner à ta classe SfmlWindowAbstraction, et, partant de là, à ta classe

4- Laisses moi être sur de ce que tu souhaites faire au travers de la ligne

if(this->centered){ this->Center(); }

En gros, tu dis "si l'objet courent est centrer, je dois appeler le comportement qui permettra de ... centrer mon objet".

Ouaip, mais bon... Ca me semble plutôt bizarre, pas toi???

Il est plus que vraisemblable que ce ne soit pas ce que tu voulais exprimer car je subodore que tu voulais exprimer quelque chose comme "si la vue doit être centrée, assure toi que le centre de la  fenêtre corresponde au centre de la vue".  Mais, dans ce cas, centered et center() devrait refléter d'avantage ce que tu veux qu'ils indiquent ;)

5- Lorsque tu sors de la boucle principale, tu déclare une variable out que tu définis comme prenant la valeur de la fonction virtuelle onStop (qui est -- à ce jour -- une fonciton qui se contente de renvoyer 0) et que tu vas renvoyer comme résultat de la foncton start.

Pourquoi passer par cette variable out, et non "tout simplement" renvoyer le résultat de onStop() ?

De plus, la valeur renvoyée par ta fonction start() sera directement renvoyée par ta fonction main().

Oui, mais la fonction main a ceci de particulier que la valeur qu'elle va renvoyer sera directement utilisée par le système d'exploitation pour savoir comment l'application s'est comportée.

Pour faire simple : une valeur renvoyée égale à 0 indiquera que "tout s'est bien passé" et une valeur différente indiquera qu'il "y a eu un problème".

Seulement, tu fais appel à onStop en dehors de la boucle principale, c'est à dire, uniquement si mainLoop_ est passé à false, et donc, a priori, si close() a été invoqué.

Or, l'invocation de close() est a priori volontaire, et ne surviendra donc -- a priori toujours -- que dans le cadre de "l'exécution logique" de l'application : tôt ou tard, le joueur voudra arrêter pour une raison qui lui est propre.

Tu peux donc considérer que tout ce qui se passe en dehors de la boucle ne pourra survenir que si tout s'est bien déroulé, et que la seule réponse possible à la question que le système d'exploitation va poser à partir du moment où l'on sort de cette boucle principale ("est ce que tout s'est bien déroulé ?" ) sera forcément "oui, tout s'est bien déroulé".

Il n'y a donc -- a priori -- aucune raison de permettre au développeur de redéfinir le comportement de onStop(), vu que la seule valeur qu'elle puisse renvoyer à partir de l'endroit où elle est invoquée est ... 0.

Et l'un dans l'autre, il n'y a même pas vraiment de quoi en faire une fonction vu que la seule valeur que ta fonction start puisse renvoyer à partir de ce point est une "constante obligatoire" destinée au système d'exploitation.

Eventuellement, au lieu de renvoyer la valeur magique 0, tu pourrais renvoyer la valeur clairement définie EXIT_SUCCESS, mais tu n'as a priori aucune raison de passer par une fonction (et encore moins par une fonction virtuelle) pour obtenir ces valeurs ;)

6- Je crois comprendre ce à quoi correspond microSleep(1); mais je t'avouerai que je ne vois absolument pas l'intérêt qu'il peut y avoir à l'invoquer ici.

Au contraire, j'aurais tendance à estimer que, selon le temps nécessaire à "exécuter le reste", cette micro pose pourrait très (trop) facilement t'empêcher d'atteindre un  taux de rafraîchissement correct :p

Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
16 août 2018 à 7:05:47

Bonjour koala01,
Tout d'abord, merci pour ta réponse même si elle ne correspond pas à ma question d'origine. Alors, pour te répondre dans l'ordre ;

0 - Pour la DOXYGEN_SHOULD_SKIP_THIS : j'utilise doxugen pour la documentation de mon code, cette macro est définie lorsque doxygen créer la doc, c'était seulement pour cacher cette macro.

Pour pouvoir répondre à la suite je dois préciser une chose, dans la macro, la fonction launch() et le booléen launched appartiennent à ma classe Threadable.
De plus la fonction launch lance un nouveau thread qui appelle une fonction membre de la classe dans laquelle elle est appelée. Pour mes windows cette fonction permet de faire les traitements en dehors du thread de la fenêtre.

1 - Pour la MACRO, la classe SfmlWindowAbstraction ne dérive pas de Threadable seules les classes filles en dérivent, hors, suite à un problème d'héritage en diamant dans une des classes filles, SfmlWindowAbstraction ne peut pas hériter de Threadable. Cepndant toutes les classes filles ont le même code principal d'où la mise an macro.
En écrivant ma réponse, je viens de penser à une chose, je pourrais peut-être écrire une méthode launch vide dans SfmlWindowAbstraction. Il memanqueraitquand même le booléen launched...

2 - Pour le mutex, il est partagé avec la fonction lancée par launch(). C'est pour cela que je le lock/unlock aussi souvent, je ne voyais pas comment faire autrement.

3 - Pour this, je sais qu'il est ici implicite mais je préfère l'appeler pour la lecture du code, il n'y a pas d'impact sur la performance, si ?

4 - Pour centrer la fenêtre à l'écran au bon moment, l'utilisateur, avant de lancer la fenêtre, peut appeler center(), cette fonction met centered à true. Center() en revanche, centre la fenêtre à l'écran.

5 - Pour onStop, j'ai besoin qu'il soit appeler avant KeyState::reset(); et sf::RenderWindow::close(); pour que les traitements faits puissent potentiellement utilisés la fenêtre ouverte.
En cas d'erreur(s) dans les traitements avant fermeture de la fenêtre, la valeur de retour doit pouvoir être différente de EXIt_SUCCESS.

6 - microSleep(1) fait une pause du thread de la fenêtre de 1 microseconde. Il me permettait un meilleur partage des ressources entre la fenêtre et l'autre thread. Avec cette fonction j'ai des FPS d'environ 400.
17 août 2018 à 15:23:41

mcabiocdel a écrit:

Pour pouvoir répondre à la suite je dois préciser une chose, dans la macro, la fonction launch() et le booléen launched appartiennent à ma classe Threadable.
De plus la fonction launch lance un nouveau thread qui appelle une fonction membre de la classe dans laquelle elle est appelée. Pour mes windows cette fonction permet de faire les traitements en dehors du thread de la fenêtre.

1 -  (b)Pour la MACRO, la classe SfmlWindowAbstraction ne dérive pas de Threadable seules les classes filles en dérivent, hors, suite à un problème d'héritage en diamant dans une des classes filles,(a) SfmlWindowAbstraction ne peut pas hériter de Threadable. Cepndant toutes les classes filles ont le même code principal d'où la mise an macro.
En écrivant ma réponse, je viens de penser à une chose, je pourrais peut-être écrire une méthode launch vide dans SfmlWindowAbstraction. Il memanqueraitquand même le booléen launched...

Houla!!!

(a) Si SfmlWindowAbstraction ne peut pas hériter de threadable, cette interdiction représente un invariant fort de cette classe. Les héritages suivants doivent donc respecter cet invariant! :

Lorsque tu fais hériter SfmlWindow de SfmlWindowAbstraction, tu dis "SfmlWindow EST-UNE SfmlWindowAbstraction" et, si SfmlWindowAbstraction ne peut pas hériter de threadable, SfmlWindow ne peut donc pas non hériter de threadable, vu que c'est ... une SfmlWindowAbstraction.

SfmlWindow peut éventuellement utiliser un système de thread (en utilisant l'agrégation "classique") , voire être implémentée en termes de Threadable (en ayant recours à l'héritage privé), mais elle ne peut pas hériter de threadable!!!!  C'est interdit par le contrat de SfmlWindowAbstraction!!!

(b)Il n'y a absolument aucun besoin d'utiliser une macro ici!!!

Si c'est un comportement qui ne doit apparaître que lorsqu'un système de thread est mis en place, définit ce comportement sous la forme d'une fonction (doStart() ??? ) membre de ta classe Threadable.

Et comme ce comportement va manipuler une instance de SfmlWindow, s'il a besoin de manipuler des données qui sont issue de SfmlWindowAbstraction, le mieux est encore:

  1. de créer dans SfmlWindowAbstraction des fonctions protégées qui permettent d'interroger et de modifier les données (privées) de SfmlWindowAbstraction, de manière à ce que SfmlWindow puisse y accéder et
  2. de déclarer ta classe Threadable<SfmlWindow> amie de ta classe SfmlWindow, de manière à ce qu'elle puisse accéder à ces fonctions protégées.
La classe Threadable pourrait donc ressembler à quelque chose comme
template <typneame T>
class Threadable{
public:
    void start(T & context){
        /* le contenu de ta macro, en remplacant this-> par
         * context.
         */
    }
};

Quant à la classe SfmlWindow, elle pourrait utiliser threadable sous la forme d'une agrégation "classique" et ressembler à

class SfmlWindow : public SfmlWindowAbstracion{
public:
    void start() override{
       threadHolder_.start(*this);
    }
private:
    friend class Threadable<SfmlWindow>;// pour permettre à threadable d'accéder au fonctions
                                        // protégées de SfmlWindow (et, du fait de l'héritage,
                                        // à celle de SfmlWindowAbstraction)
    Threadable<SfmlWindow> threadHolder_;
};

Ou utiliser l'héritage privé et prendre alors une forme proche de

class SfmlWindow : public SfmlWindowAbstracion,
                   private Threadable<SfmlWindow>{
public:
    void start() override{
       Threadable<SfmlWindow>::start(*this);
    }
private:
    friend class Threadable<SfmlWindow>;// pour permettre à threadable d'accéder au fonctions
                                        // protégées de SfmlWindow (et, du fait de l'héritage,
                                        // à celle de SfmlWindowAbstraction)
};

mcabiocdel a écrit:

3 - Pour this, je sais qu'il est ici implicite mais je préfère l'appeler pour la lecture du code, il n'y a pas d'impact sur la performance, si ?

Cela n'a -- a priori -- aucun impact sur les performances, mais cela rend le code plus complexe, et moins facile à suivre, en "le surchargeant" d'informations inutiles ;)

mcabiocdel a écrit:

4 - Pour centrer la fenêtre à l'écran au bon moment, l'utilisateur, avant de lancer la fenêtre, peut appeler center(), cette fonction met centered à true. Center() en revanche, centre la fenêtre à l'écran.

Tu devrais alors choisir des noms qui expliquent clairement les différents objectifs.  C'est d'autant plus vrai si l'on prend en compte ce que je viens d'expliquer quant à l'accès à certaines données privées de SfmlWindowAbstraction:

Pour savoir si la fenêtre doit être centrée sur l'écran, la fonction protégée pourrait prendre un nom proche de isWindowCentered() et la fonction qui obligerait la fenêtre à être centrée à l'écran prendrait le un nom proche de centerWindowOnScreen().

La logique resterait strictement identique: si la fenêtre doit être centrée à l'écran, il faut appeler la fonction adéquate pour s'assurer qu'elle le soit. mais

Eragon (2006):

Blissingr signifie le feu.  C'est le feu.  Le mot, c'est la chose.  Connais le mot et tu maîtrise la chose

ou, si tu préfères: "nommer, c'est créer" : en nommant précisément les différentes choses, tu t'assures que celui qui lira ton code comprendra exactement ce que tu voulais faire lorsque tu l'as écrit ;)

mcabiocdel a écrit:

5 - Pour onStop, j'ai besoin qu'il soit appeler avant KeyState::reset(); et sf::RenderWindow::close(); pour que les traitements faits puissent potentiellement utilisés la fenêtre ouverte.
En cas d'erreur(s) dans les traitements avant fermeture de la fenêtre, la valeur de retour doit pouvoir être différente de EXIt_SUCCESS.

Les même causes présentent les même effets... En nommant une fonction onStop(), tu transmet au lecteur de ton code que "cette fonction sera appelée uniquement au moment où l'on décide d'arrêter"

Si cette fonction est destinée à être appelée à d'autre moment, la réalité de ton code contredit l'information que tu transmet au lecteur, et ce n'est "pas bon"...

Si je lis bien entre les lignes de tes explications, cette fonction renverra 0 s'il faut mettre fin à l'exécution et "autre chose" si l'exécution doit continuer.  Mais, du coup, elle n'a de toutes manières aucune raison d'être appelée en dehors de la boucle, vu que, à ce moment là, la décision d'arrêter a déjà été prise :p

Ce dont tu as sans doute besoin avant d'appeler KeyState::reset() et sf::RenderWindow::close(), c'est de savoir si l'exécution doit continuer, et donc une fonction proche de bool willContinue() renvoyant true s'il faut continuer et false ans le cas contraire et qui serait sans doute bien plus adaptée à la situation ;)

-
Edité par koala01 17 août 2018 à 15:24:34

Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

Erreur classe héritée de sf::RenderWindow SFML2

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown