Suivez l'évolution du framework !
Suivez moi sur Github pour vous tenir informé des dernières nouveautés du framework : https://github.com/Asthegor/Dina_SDL
2022-01-05
Gestionnaire d'événements - 3ème jour
Après de multiples recherches sur le sujet, j'ai eu l'impression d'arriver face à un gigantesque mur.
Je n'ai pas réussi à percevoir la façon dont tout s'enchaîne.
Je peux le dire : je suis arrivé au bout de mes connaissances et de ma compréhension sur ce sujet précis.
J'ai donc décidé de conserver ce qui fonctionne déjà, à savoir une fonction "générique" et c'est au code client (le code du jeu, pas celui du moteur) de traiter les actions à réaliser.
Toutefois !
En utilisant cette façon de faire dans le MenuManager, j'ai pu faire que les items soient sélectionnés (changent de couleur) en appuyant sur la touche Up ou Down et également lorsque la souris passe par-dessus l'item.
Il ne reste plus qu'à rajouter le clic de la souris et j'ai un menu fonctionnel.
Je m'arrête pour aujourd'hui après ces belles victoires.
2022-01-04
Gestionnaire d'événements - 2ème jour
La 2ème journée vient de se terminer sur plusieurs échecs (je m'en doutais) et une profonde envie de refaire la totalité du processus.
J'ai l'impression d'avoir en main un meuble en kit (sans notice bien sûr) et de l'avoir monté à l'envers.
Plus je lis sur le sujet et plus je me décompose en voyant que ce que j'ai fait ne va pas du tout.
Je vais essayer d'exprimer ce que je souhaite vraiment faire (avec le contexte si possible).
- Je voudrais que chaque scène puisse avoir ses propres fonctions qui sont appelées lorsqu'un événement se déclenche.
Par exemple, lorsqu'on appuye sur un touche, je voudrais que dans la classeLogo
, la fonctionOnKeyPressed
soit exécutée et quand on bouge la souris, que la fonctionOnMouseMove
soit lancée. - Je voudrais pouvoir m'abonner à un événement spécifique pour qu'une fonction fournie en paramètre puisse être appelée.
C'est surtout le cas pour les items du menu où la validation permettra de lancer une fonction créée par le programmeur.
J'ai bien un système d'abonnement mais je n'arrive pas à emboîter les morceaux pour qu'il fonctionne pour une seule scène précise.
Actuellement, lorsque je crée les états (GameState::AddState
), je construis un objet.
Si cet objet dérive de la classe KeyboardEvent
, alors il doit implémenter les fonction OnKeyPressed
et OnKeyReleased
.
Jusque là, ça répond à ce que je veux. Mais là où se trouve le hic, c'est que je ne veux pas impliquer le changement d'état dans les événements.
Parce que maintenant, l'abonnement se fait à la création de la classe.
De plus, je ne veux pas que ce soit au code client de s'abonner mais qu'il y ait un processus automatique qui le fasse.
Est-ce que c'est au Component
de porter cette "charge" ? Je ne sais pas...
Au moment d'écrire ces lignes, j'ai fait hérité Component
de Event
qui contiendra la totalité des fonctions "génériques" (OnKeyPressed
, OnKeyReleased
, OnMouseMove
, OnMousePressed
, etc.).
Ces fonctions devront être redéfinies dans le code client et ce sera de la responsabilité du code client de faire les bonne affaire avec.
Pour le moment, cela semble fonctionner. Hourra !
Mais il reste le 2ème point à faire : l'abonnement à un événement précis.
Vous me direz, on peut toujours faire avec les fonctions "génériques". Oui, c'est bien vrai mais je voudrais faire mieux que ce que j'ai actuellement.
J'ai envie de sortir de ma zone de confort.
2022-01-03
Gestion des événements - Fin de la 1ère journée
Après plusieurs tentatives, j'ai réussi à obtenir quelque chose qui fonctionne...mais pas comme il faut 😆
Mise en place
Tout d'abord, j'ai créé une classe EventDispatcher
. Cette classe contient le code qui permet de traiter les événements en provenance de la SDL.
Après avoir créé la fonction statique Execute
, j'y ai implémenté le code provenant de Game
.
Pour des raisons évidentes, cette classe est un singleton. On ne veut pas avoir à gérer plusieurs gestionnaires d'événements !
J'ai ensuite créé la classe Event
qui ne sert, pour l'instant, que pour avoir la fonction QuitGame
.
Puis, viennent les classes KeyboardEvent
et MouseEvent
qui dérivent de la classe Event
.
Pour le moment, je n'ai implémenté que les fonctions OnKeyPressed
et OnKeyReleased
de la classe KeyboardEvent
.
Pour mes tests, j'ai directement ajouté la classe KeyboardEvent
en tant que parent de la classe MainMenu
du projet SandBox
. En faisant cela, j'ai dû implémenter les fonctions OnKeyPressed
(qui quitte le programme quand on appuye sur la touche Echap) et OnKeyReleased
(qui ne fait rien).
En passant, j'ai créé mes propres codes pour les touches. Bon, c'est plus pour ne pas être complètement coupler avec la SDL que pour faire mieux. En fait, on peut dire que c'est une simplification de la liste...pour le moment. 😣
Après avoir fait tout ça, il a fallu que j'implémente un système d'abonnement.
Donc, dans la classe EventDispatcher
, j'ai rajouté un vector
qui contiendra l'ensemble des objets dérivant de la classe Event
(sous forme de pointeur).
J'ai également rajouté une fonction qui permet de s'abonner à un événement. Pour le moment, c'est un abonnement à vie 🤣
Comme j'ai implémenté cet abonnement à la création d'un KeyboardEvent
, lorsque je crée ma classe de départ (ici, MainMenu
), c'est directement ajouté.
Cependant, comme j'ai plusieurs scènes qui sont chargées, l'événement est récupéré par tous les abonnés et pas seulement par celui qui m'intéresse....
Donc, quand je suis sur le logo et que j'appuie sur Echap, le jeu se termine.... 😫
Post-mortem
J'ai découplé la gestion des événements du jeu (une bonne chose) et créé un système d'abonnement (ok, il est à vie pour l'instant mais il fonctionne 😜)
J'ai appris que dynamic_cast
permet de tester si l'objet dérive bien de la classe indiquée sinon on reçoit nullptr
.
J'ai réussi à faire un gestionnaire d'événement ! OK, il est à améliorer mais il fonctionne !
Une bonne nuit de sommeil pourra me donner des idées pour corriger tous ces irritants.
2022-01-03
Gestion des événements
Ce matin, je me suis attaqué à la gestion des événements.
Tout d'abord, j'ai imaginé un système qui se chargerait de réceptionner tous les événements et les affecter au bon gestionnaire : un EventDispatcher
(ça, c'est la partie la plus facile).
J'ai plusieurs idées pour essayer de gérer les événements :
- soit une sorte d'abonnement à un événement précis.
Par exemple, on pourrait s'inscrire à l'événementKeyPressed
et, si une touche est appuyée, l'action (fonction) associée lors de l'inscription serait exécutée. - soit en associant une interface à la classe.
Par exemple, notre classeMenu
pourrait héritée de l'interfaceKeyboardEvent
et c'est au code client d'implémenter la fonctionOnKeyPressed
et de dire ce qu'il se passe.
Pour la première approche, le code client est plus léger mais demande d'avoir une fonction pour chaque action à réaliser si une touche est appuyée (gestion plus fine côté client avec plusieurs abonnements à un même événement).
Pour la deuxième approche, c'est au code client de gérer la totalité du traitement et des conditions d'activation.
Bref, je suis un peu tiraillé entre les deux. D'un côté, je veux que le code client soit simple à rédiger mais je veux également que les programmeurs aient le plus de liberté possible dans leur code.
Dans un premier développement, je vais partir sur l'interface. C'est l'idée qui semble plus simple à implémenter.
Je viens de penser qu'il me faudra aussi un système d'abonnement au EventDispatcher.
Dans tous les cas, je vais avoir de nombreux échecs avant d'obtenir un résultat convenable (mais pas forcément optimisé).
2022-01-02
Ajout d'un MenuManager
Bonne Année 2022 à toutes et tous !
Pour commencer cette nouvelle année, j'ai souhaité créer un gestionnaire de menu.
Je sais qu'il y a des choses beaucoup plus importantes à faire, comme la gestion des événements, mais je voulais commencer par un petit travail pas trop compliqué.
MenuManager
Ce gestionnaire de menu contient 7 fonctions publiques :
SetBackground
qui permet d'indiquer une seule image de fond (positionnée en haut à gauche de l'écran)SetTitle
qui permet de définir le titre du menu, sa police, sa taille, sa couleur et une ombre avec sa propre couleur et l'offset à appliquerAddItem
qui permet d'ajouter un item au menuSetItemsStartHeight
qui permet de définir la hauteur de départ de l'affichage du menu (les items sont toujours afficher au milieu de l'écran)SetItemsPadding
qui permet de définir l'espacement en pixels entre les items du menuDraw
qui permet d'afficher tous les éléments du menu (fond, titre, items)Update
(qui ne fait rien pour le moment)
Optimisations
Durant la mise en place du MenuManager, j'ai opéré également quelques modifications sur l'affichage des éléments.
Avant cette optimisation, je passais systématiquement le renderer
à chaque élément. Or, ce renderer
est unique !
Je l'ai donc créé dans la classe Graphic
et par la même occasion, j'ai dû transformer cette classe statique en un Singleton
.
Cela a découplé un grand nombre d'éléments et m'a permis également de simplifier l'affichage des textures et des surfaces.
L'affichage d'une surface se fait désormais à travers l'affichage d'une texture (donc moins de risque d'erreurs).
Avec le code ci-dessous :
J'obtiens ceci :
Couplage SDL encore très présent
Si vous regardez le code plus haut, vous constaterez qu'il y a beaucoup de couplage avec la SDL.
Pour le moment, ce n'est pas vraiment grave mais quand le framework sera beaucoup plus avancé, cela pourra va poser problème si je décide d'utiliser une autre librairie graphique.
Pour éviter de passer par les commandes de la SDL, je vais :
- Soit refaire mes propres structures
- Soit renommer les structures dont j'ai besoin à l'aide de
define
Je n'ai pas vraiment décidé de la manière de procéder.
Ensuite...
Il reste (encore et toujours) à gérer les événements.
C'est l'étape la plus dure et la plus longue à faire...