Ce cinquième chapitre du tutorial ne va pas vous faire afficher de jolis trucs à l'écran (et oui encore !), en effet, nous allons programmer une classe qui permet de gérer les événements. Autrement dit, une classe qui va dans un premier temps, attendre que le joueur appuie sur une ou plusieurs touches de son clavier et par conséquent déclencher une action. C'est plus ou moins comme ça qu'on va concevoir les commandes de notre jeu.
Il existe une classe dans Irrlicht qui “écoute” et qui est capable de dire quel événement vient de se produire. Alors nous, dans ce chapitre nous allons nous concentrer sur l'événement clavier. Mais sachez qu'il existe d'autres types d'événements : souris, joystick etc... Ce que nous allons faire, c'est plus où moins ce qui est expliqué dans le tutorial officiel d'Irrlicht sur les événements. Car il faut avouer que le tutorial donne une méthode qui convient parfaitement à la structure de notre jeu.
Il s'agit de dériver la classe IEventReceiver. Comme son nom l'indique, cette classe reçoit les événements pour qu'on puisse les traiter. Comme on ne peut pas modifier la classe directement, on va la dériver. Nous allons appeler notre classe fille EventManager, pour “Gestionnaire d'événements”. Nous allons donc créer un fichier EventManager.h et commencer l'écriture du code :
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#endifPuis le fichier source EventManager.cpp :
#include "EventManager.h"Nous allons ensuite créer un lien entre le jeu et le gestionnaire d'événements car c'est dans le jeu qu'on fera des tests pour savoir si il se passe quelque chose. Ce lien, on le créer par la présence du gestionnaire dans la classe Game. On va donc déclarer un objet directement dans Game.h, comme pour driver et device, en static et on n'oublie pas non plus l'instruction include de EventManager.h :
#ifndef GAME_H#define GAME_H#include <irr/irrlicht.h>#include "Scene.h"#include "EventManager.h"#endifSi on compile le projet, on se rendra compte qu'une erreur survient à la ligne 17. En fait, la classe IEventReceiver contient une méthode OnEvent qui est abstraite. Cela signifie qu'elle est comme incomplète. Pour remédier à cela, on doit redéfinir la méthode en la réecrivant. Dans EventManager.h :
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#endifVous voyez l'ajout de la méthode OnEvent, désormais si on compile, mis à part quelques warnings (qu'on corrigera), l'exécutable est créé sans problème. Il faut savoir que quand l'utilisateur appuie sur une touche du clavier, bouge sa souris ou incline son joystick, la méthode OnEvent est appelée automatiquement. Notre objectif maintenant est d'écrire le contenu de OnEvent de manière à ce qu'on traite différents types d'événements.
Un nom barbare mais c'est bien avec cette constante qu'on va tester le type d'événement. Vous apercevez dans la signature de la méthode OnEvent un objet de type SEvent et qui est constant, il s'agit même d'une référence à cet objet comme en témoigne la présence du &. L'objet event dispose de quelques propriétés dont EventType qui contient la valeur correspondant au type d'événement déclenché. Je peux donc comparer cette valeur à EET_KEY_INPUT_EVENT et être en mesure de détecter un événement clavier.
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#endifOn vient de voir que event contenait une propriété appelée EventType. Mais cette structure SEvent contient des sous-structures, une pour chaque type d'événement. Pour notre cas, nous allons nous servir de KeyInput qui est de type SKeyInput. Avec KeyInput, on a accès à des propriétés intéressantes : Key tout d'abord qui contient le code de la touche qui a été enfoncée ou relâchée, PressedDown qui dit que la touche est pressée ou non, on a aussi Control et Shift qui nous disent si ces deux touches spéciales sont enfoncées au moment de l'événement.
La technique préconisée par les créateurs d'Irrlicht est de créer une méthode qui va dire si une touche particulière est enfoncée ou non. Regardez le schéma suivant, si dans une scène on a besoin de tester qu'une touche est enfoncée (par exemple pour déplacer le personnage principal), la fonction isKeyDown sera appelée 60 fois par seconde tant que la touche est appuyée. Cette fonction prendra un paramètre : la touche qu'on souhaite tester (ici KEY_LEFT) et ira interroger un tableau nommé keyDown. En fonction de la touche testée, la fonction ira chercher la valeur correspondant à la touche et la renverra, d'où le true qu'on reçoit à la sortie de la méthode.

Nous allons donc d'abord créer le tableau keyDown dans la partie privée de la classe, il aura pour taille le nombre de codes de touches disponibles, on l'obtient par la constante KEY_KEY_CODES_COUNT :
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#include <iostream>#endifNous allons initialiser les cellules du tableau keyDown, c'est-à-dire, le remplir de valeurs par défaut. Pour cela, on effectue une boucle dans le constructeur de EventManager pour remplir le tableau avec des valeurs false :
#include "EventManager.h"Pour la méthode isKeyDown, elle retournera juste la valeur d'une cellule précise qu'on demandera via son paramètre code (type EKEY_CODE).
#include "EventManager.h"On a plus qu'à terminer la méthode OnEvent pour qu'en cas d'événement clavier, la valeur de la cellule, dont le code de la touche est le même que event.KeyInput.Key, prenne la valeur true et toutes les autres false. On va se servir de event.KeyInput.Key qui contient le code de la touche qui agit et de event.KeyInput.PressedDown qui va renvoyer true ou false selon que c'est appuyé ou relâché.
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#include <iostream>#endifSeul soucis : lors de la compilation, on a encore plein de warnings, ils sont dûs au fait que la méthode OnEvent dans sa définition dans la classe IEventReceiver doit renvoyer une valeur. D'ailleurs quand on l'a redéfinit, on a spécifié son type de retour : bool. On placera donc la ligne return false; à la fin de la méthode
Voyons comment on utilise la méthode qu'on a fraîchement créé. Tout d'abord, sachez que la classe EventManager ne fonctionnera pas tant que vous n'aurez pas dit à Irrlicht qu'il faut l'utiliser ! Pour ce faire, rappelez vous de l'appel à createDevice qu'on a vu au chapitre précédent, dans la classe Game.
Regardez le dernier paramètre de la méthode : 0. On avait dit à l'époque qu'il s'agissait d'une référence à un objet de type IEventReceiver. Le soucis c'est qu'on a uniquement défini l'objet en question, en static dans la classe Game. On a besoin de le déclarer comme les objets driver et device, juste avant le code du constructeur :
#include "Game.h"#include "EventManager.h"#include <iostream>#include <irr/irrlicht.h>"In Game constructor"<< endl;
On n'oublie pas l'include de EventManager.h, on a déclaré l'objet (qui n'est pas un pointeur, attention) et on peut donc le mettre en paramètre de createDevice (avec le & pour passer son adresse).
Il est maintenant possible de programmer une action selon un événement simple, on affichera dans la console "Event OK" tant qu'on appuiera sur la touche gauche. On peut placer par exemple cette partie du code dans la boucle principale de la scène, dans la fonction updateAll() :
"Event OK"<< endl;

Un cas plus difficile mais qui va beaucoup servir : comment faire pour que l'action ne s'exécute qu'une seule fois quand l'événement se produit ? Nous allons voir une méthode basée sur ce qu'on vient de faire : l'utilisation d'un deuxième tableau dans EventManager, nommé KeyOnce. Nous l'ajoutons à la classe EventManager et nous créons une nouvelle méthode nommée isKeyDownOnce :
#ifndef EVENTMANAGER_H#define EVENTMANAGER_H#include <irr/irrlicht.h>#include <iostream>#endifLe code de la fonction isKeyDownOnce est un peu difficile à expliquer de manière claire (si vous avez des questions, n'hésitez pas à me contacter ou poser la question sur le forum). Cette fonction va renvoyer true une seule fois, quand keyOnce[code] sera true. On va fixer cette valeur à true si elle est à false et si on est en train de presser la touche (isKeyDown). Et on fixera à false la valeur de cette cellule quand elle vaudra true et que la touche n'est pas pressée, ainsi ça réinitialise l'action quand on relâche la touche et on pourra donc reprovoquer l'action si on rappuie sur la touche.
En C++, voila ce que donne cette fonction :
Testons maintenant les deux fonctions, isKeyDownOnce seule et ensuite combinée avec isKeyDown :
"Left Forever"<< endl;
"Right Once"<< endl;
"Ctrl+Up Once"<< endl;
Testez par vous-même les combinaisons en appuyant sur Droite, Gauche et Control + Haut, vous verrez alors les utilisations possibles de ces deux fonctions bien pratiques pour programmer les commandes du jeu.