5.1.3 Écriture de sdl_application.h

On va mettre en pratique à peu près tout ce que l'on a vu depuis le début de ce cour.

Vous vous en rappelez sûrement, dans sdl_application.h :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef SDL_APPLICATION_H
#define SDL_APPLICATION_H

#include <iostream>
#include <string>

#include <string.h>
#include <time.h> //pour l'initialisation des aléatoires (on verra ça plus bas)

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

class SDL_Application{
	
};

#endif

Jusque là rien de bien surprenant, maintenant nous allons définir deux types pour les deux std::map que l'on va devoir utiliser, mettez ces lignes entre #include et class SDL_Application { :

1
2
3
4
#include <map> //on va utiliser des map

typedef std::map<SDLKey,bool> KeyStates; /*tableau de bool pour les événements clavier */
typedef std::map<std::string,SDLKey> KeyConf; /*tableau d'action pour savoir ce que l'utilisateur veut faire*/

Intéressons nous à la partie publique de la classe.

Je vous propose de faire plusieurs constructeurs :

  • un avec que la taille de la fenêtre en option (SDL_Application(int width = 640, int height = 480);)
  • un constructeur avec la taille, le titre et l’icon de a fenêtre (de dernier étant en option)
  • un constructeur avec les quatre précédents et une SDL_Surface* backGround (pour le fond), le nom d'une police, sa taille, ces deux derniers paramètres étant en option
  • un constructeur avec tout les paramètres précédents mais en replaçant SDL_Surface* backGround par Uint32 backGroungColor (la couleur de font de l'application)
  • un constructeur avec tout les paramètres précédents en remplaçant Uint32 backGroungColor par const std::string & backgroundFile

Ce qui donne :

1
2
3
4
5
SDL_Application(unsigned int width = 640, unsigned int height = 480);
SDL_Application(unsigned int width, unsigned int height, const std::string & titre, SDL_Surface* icon = NULL);
SDL_Application(unsigned int width, unsigned int height, const std::string & titre, SDL_Surface* icon, const std::string & backGroundFile, const std::string & police = "", int taille = 0);
SDL_Application(unsigned int width, unsigned int height, const std::string & titre, SDL_Surface* icon, SDL_Surface* backGround, const std::string & police = "", int taille = 0);
SDL_Application(unsigned int width, unsigned int height, const std::string & titre, SDL_Surface* icon, Uint32 backGroundColor, const std::string & police = "", int taille = 0);

N'oublions pas le destructeur :

1
virtual ~SDL_Application();

Nous pouvons également ajouter des fonctions d'initialisations (setteurs) :

1
2
3
4
5
6
7
8
9
void setTitle(const std::string & titre);
void setIcon(SDL_Surface* icon);
void setIcon(const std::string & iconFile);
void setBackGroundColor(Uint32 color);
void setBackGroundColor(Uint8 r, Uint8 g, Uint8 b);
void setBackground(SDL_Surface* background);
void setBackground(const std::string & backgrounsFile);
void setFont(const std::string & police, int taille);
void setFont(TTF_Font* font);

Il nous faut aussi une fonction int executer() pour lancer l'application (qui retournera 0 si tout fonctionne et 1 si un truc à foiré (comme main) :

1
int executer();

On à dit tout à l'heure que la classe ne devait pas pouvoir être copiée, pour cela il suffit de définir un constructeur de copie et l'opérateur =, pour empêcher la copie de la classe.

Les fonctions protégées (protected).

Le schéma d'un programme est assez simple :

  • initialisation
  • exécution (en boucle jusqu'à l'arrêt de l'application)
    • affichage
    • mise à jour (calculs)
  • fin du programme (nettoyage de la mémoire, sauvegarde de données)

Et s'est tout.

Nous avons déjà la fonction exécution, il nous manque l'affichage (draw) et la mise à jour (update).

Elles seront virtuelles pures car c'est l'utilisateur qui en aura besoin, et pas nous.

Pourquoi on les déclare alors ?

Tout simplement pour pouvoir les appeler. Nous devons appeler des fonctions qui n'existent pas, donc on les créés sans les implémentés.

Pour dessiner nous devons donner l'écran en paramètre, donc la déclaration ressemblera à cela :

1
virtual void draw(SDL_Surface* ecran) =0;

Quant à la fonction update on pourrait fournir l'intervalle de temps entre deux calcul (le dt en physique) :

1
virtual void update(float dt) =0;

De la même manière nous pouvons rajouter une fonction virtuelle pour permettre une initialisation, par exemple :

1
virtual void initVar();

Pour que l'utilisateur puisse mettre des valeurs par défaut dans son application.

Nous en avons parler tout à l'heure il faut une fonction pour ajouter une touche à gérer :

1
void addKeyEvent(const std::string action, SDLKey key, bool initValue);

On passe donc à cette fonction :

  • action : le nom de l’événement appuis de touche
  • key : la touche associée
  • initValue : sons état initial (true pressée, false relâchée)

La fonction qui va nous dire si un événement s'est réalisé :

1
bool keyEventMade(const std::string action);

Pensons aussi à la fonction d'arrêt de l'application :

1
void stop();

Et aux différentes fonctions pour écrire du texte à l'écran :

1
2
3
void drawText_Solid(int x, int y, const std::string & str, SDL_Color color);
void drawText_Shaded(int x, int y, const std::string & str, SDL_Color color, SDL_Color fond);
void drawText_Blended(int x, int y, const std::string & str, SDL_Color color);

Les fonctions et variables privées.

Une fonction pour initialiser SDL :

1
void initialisation_SDL(unsigned int width, unsigned int height);

Une fonction d'initialisation pour chaque constructeur complet (7 paramètres).

Une fonction pour récupérer les événements :

1
void getEvent(SDL_Event* event);

Une fonction pour mettre à jour l'intervalle de temps entre deux calculs.

1
float updateTicks();

Une fonction qui met l'icon à l'application :

1
void openIcon(SDL_Surface* icon);

Une fonction pour initialiser SDL :

1
void initialisation_SDL(unsigned int width, unsigned int height);

Côté variable :

La dernière mesure de temps :

1
Uint32 last_time;

Le temps courant :

1
Uint32 current_time;

Le dernier ticks :

1
Uint32 lastTick;

L'intervalle de temps entre deux calculs :

1
Uint32 ellapsed_time;

L'instant où l'application a été déclenchée :

1
Uint32 start_time;

Le tableau de booléens pour les événements du clavier :

1
KeyStates keystates;

Le tableau qui associe les touches aux événements :

1
KeyConf keyconf;

Un booléen pour dire si l'application s'exécute :

1
bool run;

L'écran (si on veut faire de l'affichage ça peut servir) :

1
SDL_Surface* ecran;

Le fond d'écran de l'application :

1
SDL_Surface* background;

La couleur de fond de l’application :

1
Uint32 backgroundColor;

L'icon de l'application :

1
SDL_Surface* icon;

La police de l'application :

1
TTF_Font* font;

Un booléen qui dit si l'image de fond a été ouverte par l'application :

1
bool isMyIcon;

Un booléen qui dit si la police a été ouverte par l'application :

1
bool isMyFont;

En effet il faut s'assurer que l'application ne va pas détruire une SDL_Surface* qui n'est pas à elle ou fermer une fonte qu'elle n'a pas ouverte.

Voilà un petit résumé de la situation :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#ifndef SDL_APPLICATION_H
#define SDL_APPLICATION_H

#include <string>
#include <string.h>

#include "time.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>

#include <iostream>

#include <map>
typedef std::map< SDLKey,bool> KeyStates;   //tableau de bool pour les événements clavier
typedef std::map<std::string,SDLKey> KeyConf; //tableau d'action pour savoir ce que l'utilisateur veut faire

/**
	@brief Classe qui a pour but de créer une application SDL sans avoir besoin de se trimbaler toute l'initialisation à chaque fois
*/

class SDL_Application
{
	public:
		//ensemble des constructeurs
		SDL_Application(unsigned int width = 640, unsigned int height = 480);
		SDL_Application(unsigned int width, unsigned int height, const std::string & titre, const std::string & icon = "");
		SDL_Application(unsigned int width, unsigned int height, const std::string & titre, const std::string & icon, const std::string & backgroundFile, const std::string & police = "", int taille = 0);
		SDL_Application(unsigned int width, unsigned int height, const std::string & titre, const std::string & icon, SDL_Surface* background, const std::string & police = "", int taille = 0);
		SDL_Application(unsigned int width, unsigned int height, const std::string & titre, const std::string & icon, Uint32 backgroundColor, const std::string & police = "", int taille = 0);
		//constructeur de copie
		SDL_Application(const SDL_Application & app);
		//destructeur
		virtual ~SDL_Application();
		
		int executer();
		
		void setTitle(const std::string & titre);                                 //donne un titre à la fenêtre
		void setIcon(SDL_Surface* icon);                                 //icone passé à l'application
		void setIcon(const std::string & iconFile);                             //icone à initialiser (puis détruire)
		void setBackground(SDL_Surface* background);                   //donne une image de fond de l'application
		void setBackground(const std::string & backgrounsFile);               //donne une image de fond de l'application
		void setBackgroundColor(Uint32 color);                       //couleur de fond de l'application
		void setBackgroundColor(Uint8 r, Uint8 g, Uint8 b);         //couleur de fond de l'application (rouge, vert, bleu)
		void setFont(const std::string & police, int taille);              //initialisation de la police
		void setFont(TTF_Font* font);                             //passe une police
		
		//définition de l'opérateur =
		SDL_Application & operator = (const SDL_Application & app);
		
	protected:
		//affichage
		virtual void draw(SDL_Surface* ecran) =0;
		//mise à jour, calcul
		virtual void update(float dt) =0;
		//permet une initialisation de l'utilisateur
		virtual void initVar();
		//arrête l’application
		void stop();
		
		//ajout d'une touche à gérer
		void addKeyEvent(const std::string action, SDLKey key, bool initValue);
		//dit si un événement est réalisé
		bool keyEventMade(const std::string action);
		
		//écrit du texte Solid
		void drawText_Solid(int x, int y, const std::string & str, SDL_Color color);
		//écrit du texte Shared
		void drawText_Shaded(int x, int y, const std::string & str, SDL_Color color, SDL_Color fond);
		//écrit du texte Blended
		void drawText_Blended(int x, int y, const std::string & str, SDL_Color color);
		
	private:
		//fonction d'initialisation 
		void initialisation(const std::string & titre, const std::string & icon, const std::string & backgroundFile, const std::string & police, int taille);
		//fonction d'initialisation 
		void initialisation(const std::string & titre, const std::string & icon, SDL_Surface* background, const std::string & police, int taille);
		//fonction d'initialisation 
		void initialisation(const std::string & titre, const std::string & icon, Uint32 backgroundColor, const std::string & police, int taille);
		
		void initialisation_SDL(unsigned int width, unsigned int height);
		//fonction de copie de l'application
		void copySDL_Application(const SDL_Application & app);
		
		//récupère les événements
		void getEvent(SDL_Event* event);
		//met à jour les ticks
		float updateTicks();
		
		
		///dernière mesure de temps de l'application (SDL_Ticks)
		Uint32 last_time; //dernière mesure de temps de l'application (SDL_Ticks)
		///temps courrant
		Uint32 current_time; //temps courrant
		///dernier ticks
		Uint32 lastTick;    //dernier ticks
		///intervalle de temps entre le temps courrant et la dernière mesure de temps de l'application
		Uint32 ellapsed_time; //intervalle de temps entre le temps courrant et la dernière mesure de temps de l'application
		///instant ou l’application a été déclenchée
		Uint32 start_time;   //instant ou l’application a été déclenchée
		///tableau de bool pour les entrées clavier
		KeyStates keystates; //tableau de bool pour les entrées clavier
		///association actions touches
		KeyConf keyconf;    //association actions touches
		
		///dit si il y a exécution
		bool run; //exécution
		///écran de l'application
		SDL_Surface* ecran;//écran de l'application
		///dit si l'icon à été ouvert par la classe
		bool isMyIcon; //dit si l’icône à été ouvert par la classe
		///icone de l'application
		SDL_Surface* icon;    //icone de l'application
		///dit si le l'image de fond a été ouverte par l’application
		bool isMyBackground; //dit si le l'image de fond a été ouverte par l’application
		///image de fond
		SDL_Surface* background;  //image de fond
		///couleur de fond
		Uint32 backgroundColor; //couleur de fond
		///dit si la fonte a été ouverte par l'application
		bool isMyFont;    //dit si la fonte a été ouverte par l'application
		///fonte de l'application
		TTF_Font *font;//fonte de l'application
};


#endif

Maintenant nous pouvons écrire le fichier sdl_application.cpp.