Aller au menu - Aller au contenu

Icône Gestion des périphériques

Avatar
Mise à jour : 23/03/2011
Difficulté : Facile Facile Creative Commons BY-SA
1 621 visites depuis 7 jours, dont 41 sur ce chapitre classé 80/786
Pour ce premier chapitre des techniques intermédiaires, on attaque fort avec les événements !
Vous allez enfin pouvoir interagir avec vos applications Irrlicht en temps réel. :)

Il s'agit donc d'un chapitre fondamental, et s'il n'est pas placé plus tôt dans ce tutoriel, c'est parce que la gestion des événements sous Irrlicht est loin d'être aisée. Mais pas de panique, on a tout notre temps alors on va y aller par étapes en expliquant bien à chaque fois de quoi il retourne.
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Les événements à la source

Pour commencer, il convient de savoir exactement de quoi on parle. On appelle "événement" tout appui/relâchement sur une touche, mouvement de la souris, clic sur un bouton, etc... La liste complète des types d'événements (events en anglais) pouvant être captés par Irrlicht est disponible dans la documentation. Notez au passage le mot "captés", voilà une notion importante en ce qui concerne les événements.

Le schéma de la gestion des événements sera le suivant :


Phase 1 Un événement est produit
↓ ↓ ↓
Phase 2 Il est capté par le capteur d'événements
↓ ↓ ↓
Phase 3 Il est traité en fonction de son type


Les deux premières phases sont gérées par Irrlicht, notre boulot va consister à écrire le code décrivant comment traiter tel ou tel type d'événement. Par exemple, imaginons que l'on crée un FPS, on voudra que lorsqu'un clic gauche de la souris est détecté, le personnage tire.



Voyons un peu plus en détail comment cela s'organise dans le code déjà existant du moteur. Le capteur d'event est de la classe IEventReceiver, on peut d'ailleurs voir sur le diagramme UML la liste des classes du moteur susceptibles d'envoyer des événements à un capteur (les caméras et quasiment tous les éléments de la GUI).

Il est indiqué sur la page de documentation que la classe IEventReceiver possède en tout et pour tout 2 méthodes. Dont un destructeur dont nous ne nous préoccuperons pas. Tout va donc se jouer sur OnEvent(SEvent event). Cette méthode est automatiquement appelée dès qu'un événement se produit. C'est la 2ème phase du schéma de tout à l'heure. Par défaut, cette méthode est purement virtuelle, ce qui signifie que si on la laisse en l'état, il ne se passera rien si un événement est capté (enfin de toute façon, on ne pourrait même pas instancier la classe en l'état...).

Tout ce qu'il nous reste à faire est donc de dériver la classe IEventReceiver pour pouvoir implémenter la méthode OnEvent de manière à ce que notre traitement des événements s'applique. C'est la 3ème phase du schéma. J'espère que vous êtes au point sur le C++, on va commencer à faire des choses moins triviales. ^^



Bon, pour le moment on a à peu près tout ce qu'il faut pour gérer "bêtement" les événements, mais comme nous sommes curieux, cela ne nous suffit pas. Alors regardons encore plus en détails dans le code source comment Irrlicht se débrouille pour gérer tout ça. Le point de départ se trouve dans la méthode run() du device. Vous la connaissez forcément, c'est la méthode qu'on appelle dans la boucle de rendu pour savoir s'il faut arrêter l'application ou pas :

Code : C++
1
2
3
4
5
//La boucle de rendu
while (device->run())
{
    /* ... */
}


Réfléchissons un instant, comment cette fonction sait-elle si elle doit retourner true pour que l'application continue ou false pour qu'elle s'arrête ? En détectant les événements bien sûr ! Par exemple, un appui simultané sur Alt et F4 ferme l'application. C'est cette fonction qui va se charger de capter tous les événements, et d'appeler la méthode OnEvent() de la classe IEventReceiver.

On peut donc retrouver le code de cette fonction dans le fichier contenant le code de CDevice. Pas de chance, il y a deux versions possibles de ce fichier. L'une d'entre elles contient le code de CDevice dans le cas d'une utilisation sous systèmes de type Unix (Linux par exemple), et l'autre contient le code pour une utilisation sous Windows. La raison de cette séparation est que, avant de renvoyer un événement de type SEvent (donc un type propre à Irrlicht), celui-ci est obligé de passer par une API système.

Au tout début de la chaîne, un événement n'est qu'un signal électrique partant du clavier jusqu'à l'unité centrale pour indiquer que telle ou telle touche a été enfoncée par exemple. La première couche logicielle à intercepter ce signal pour le traiter est l'OS (le système d'exploitation). Et il existe une bibliothèque permettant de "dialoguer" avec l'OS pour lui demander, par exemple, de nous prévenir quand une touche est enfoncée et de nous dire laquelle, etc... Cette bibliothèque s'appelle une API système et elle est bien sûr différente en fonction de l'OS. Irrlicht va donc se servir des ces API systèmes et c'est ce qui explique les 2 versions différentes de CDevice.



Après ces quelques explications un peu théoriques, nous allons examiner un morceau du code de la fonction run() de la version systèmes type Unix de CDevice. Les systèmes de type Unix utilisent l'API X Window System (souvent abrégée X) pour ce qui concerne l'interface graphique et la gestion des événements. Par conséquent, certaines lignes du code qui va suivre sont spécifiques à cette API. J'expliquerais brièvement à quoi elles servent mais le but de la manoeuvre est plutôt de comprendre le fonctionnement général de la fonction. Aussi j'ai donc coupé pas mal de code et ajouté des commentaires :

Code : C++
 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
bool CIrrDeviceLinux::run()
{
 
    /* ... */
 
    //Une instance de SEvent est cree
    irr::SEvent irrevent;
 
    /* ... */
 
    //Sert a recuperer les events
    XNextEvent(display, &event);
 
    //On teste le type d'event
    switch (event.type)
    {
 
        /* ... */
 
        //Dans le cas d'un deplacement de souris
        case MotionNotify:
            irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
            irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
            irrevent.MouseInput.X = event.xbutton.x;
            irrevent.MouseInput.Y = event.xbutton.y;
            postEventFromUser(irrevent);
            break;
 
        /* ... */
 
    }
}


Vous pouvez admirer ligne 7 l'événement qui sera transmis à la méthode OnEvent. Il est créé au début de la fonction et sera initialisé en fonction de ce que X aura détecté. C'est d'ailleurs le rôle de la ligne 12 comme l'indiquent les commentaires.

Une fois que X a récupéré l'event, un switch est fait pour déterminer quelle est sa nature. Normalement ce switch est assez énorme (allez faire un tour dans le code source pour vous en convaincre), mais un seul case suffit à comprendre. Ligne 21 donc, on teste qu'il s'agit d'un déplacement de souris. Si c'est le cas, les 4 lignes suivantes vont servir à paramétrer l'instance de SEvent. C'est à la ligne 26 que les choses se corsent. On peut voir qu'après avoir été paramétrée, l'instance de SEvent est passée en paramètre à la fonction postEventFromUser.


Ne reculant devant rien dans notre quête de savoir, allons voir dans la classe CIrrDeviceStub (la classe mère de CDevice (quelle que soit la version)) l'implémentation de cette méthode :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void CIrrDeviceStub::postEventFromUser(SEvent event)
{
        bool absorbed = false;
 
        if (UserReceiver)
                absorbed = UserReceiver->OnEvent(event);
 
        if (!absorbed && GUIEnvironment)
                absorbed = GUIEnvironment->postEventFromUser(event);
 
        scene::ISceneManager* inputReceiver = InputReceivingSceneManager;
        if (!inputReceiver)
                inputReceiver = SceneManager;
 
        if (!absorbed && inputReceiver)
                absorbed = inputReceiver->postEventFromUser(event);
}


Bon, normalement à ce stade, j'ai perdu la moitié des lecteurs. :p
Qu'à cela ne tienne, nous n'allons pas nous arrêter en si bon chemin !

Le but de cette fonction est de faire parvenir l'événement aux différents capteurs d'événements. Comment ça ? J'ai oublié de préciser qu'il y en a plusieurs ? :-° C'est assez simple en fait : en premier lieu, la fonction envoie l'événement à "UserReceiver" (ligne 6). Le user c'est nous, il s'agit donc d'une instance de notre classe dérivée de IEventReceiver que nous allons associer au device (c'est la phase 3 du schéma du début). Notez au passage que la ligne 5 sert à vérifier que nous avons bien associé un capteur au device.

Il se trouve que la méthode OnEvent renvoie un booléen. Et celui-ci indique si l'événement a été traité ou pas. Eh oui, il est possible que l'événement détecté soit un clic de souris et que seuls les appuis sur les touches du clavier nous intéressent. Dans ce cas là, la fonction OnEvent renvoie false pour indiquer qu'elle n'a pas traité l'événement.

Seulement voilà, un clic de souris ce n'est pas rien quand même, il se peut que ça intéresse quelqu'un d'autre... la GUI par exemple. C'est tout l'intérêt de la ligne 9. On commence par tester ligne 8 que le booléen renvoyé par notre capteur est bien false, et qu'il existe bien un environnement de GUI. Si la condition est remplie, on envoie l'événement à l'environnement GUI, et il se débrouille avec. On pourrait farfouiller là aussi dans le code source pour découvrir des choses intéressantes mais je crois qu'on fera ça dans un autre chapitre sinon vous allez être dégoûtés d'Irrlicht pour de bon. ^^

De même, pour simplifier, nous allons dire que les lignes restantes servent à envoyer l'événement au scene manager puisqu'il gère la (l'éventuelle) caméra. En partant bien sûr du principe que la fonction OnEvent du capteur de la GUI a elle aussi renvoyé un false. Cette simplification est correcte, c'est véritablement ce qu'il se passe. Mais pas seulement...



Histoire de souffler un peu et de se remettre les idées en place, je vous mets la version améliorée du schéma du début :

Phase 1 Un événement est produit
↓ ↓ ↓
Phase 1.5 Il est capté par l'API système
↓ ↓ ↓
Phase 2 Il est récupéré par Irrlicht et passé à la fonction postEventFromUser
↓ ↓ ↓
Phase 2.5 La fonction postEventFromUser passe l'événement (de type SEvent) de gestionnaire en gestionnaire jusqu'à ce qu'il soit traité
↓ ↓ ↓
Phase 3 Un gestionnaire traite l'événement en fonction de son type


Alors ? Qui a dis que c'était compliqué ? ^^

Le mouvement en action

Normalement le plus dur est passé, si vous avez compris ce qui précède la pratique ne devrait pas être compliquée outre mesure. La première chose à faire est donc de dériver IEventReceiver pour pouvoir implémenter OnEvent à notre sauce. Voilà ce que donne la déclaration de la classe :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <IRR/irrlicht.h>
 
 
class CEventReceiver : public irr::IEventReceiver
{
 
public :
 
    //Capte automatiquement les events.
    virtual bool OnEvent(const irr::SEvent &event);
};


Bon, c'est un début. Maintenant réfléchissons à l'implémentation de OnEvent, qu'est-ce qu'on aimerait faire en rapport avec les événements ? Bouger un personnage par exemple ! (bon ok vous n'avez pas vraiment le choix alors ce sera ça et c'est tout :p ).

L'idée de base est donc que la méthode OnEvent va agir sur la position d'un mesh en fonction de l'événement détecté. Oui mais voilà, encore faut-il pouvoir accéder à ce mesh. Nous allons donc mettre en attribut de la classe un pointeur vers un IAnimatedMeshSceneNode. Il est inutile que le destructeur de notre classe se charge de libérer le modèle pointé puisque c'est le scene manager qui s'en occupe (d'ailleurs il n'y a pas besoin de destructeur du tout).

Voilà comment nous allons nous y prendre pour déplacer le modèle. Si on bougeait le mesh à chaque appui sur la touche, le mouvement serait saccadé, même en laissant la touche enfoncée (surtout en laissant la touche enfoncée). La solution consiste à se servir d'un booléen indiquant si la touche est enfoncée ou pas. A chaque appui sur la touche, on met le booléen à true et à chaque relâchement, il repasse à false. Ainsi, il ne reste plus qu'à tester à chaque frame si le booléen est true ou false, et à agir en conséquence.

Notre déclaration se transforme donc en :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <IRR/irrlicht.h>
 
class CEventReceiver : public irr::IEventReceiver
{
 
public :
 
    //Le constructeur.
    CEventReceiver(irr::scene::IAnimatedMeshSceneNode* Nmodele);
    //Capte automatiquement les events.
    virtual bool OnEvent(const irr::SEvent &event);
    //Met a jour la position du mesh.
    void majPosMesh();
 
 
private :
 
    //Le modele qu'on va controler.
    irr::scene::IAnimatedMeshSceneNode* m_Nmodele;
    //Indique si on est deja en mouvement ou pas.
    bool m_isMoving;
};


Voyons maintenant l'implémentation :

Code : C++
 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
#include "CEventReceiver.h"
 
CEventReceiver::CEventReceiver(irr::scene::IAnimatedMeshSceneNode* Nmodele)
{
    //On pointe le mesh passe en parametre.
    m_Nmodele = Nmodele;
    //Par defaut on ne bouge pas
    m_isMoving = false;
}
 
 
bool CEventReceiver::OnEvent(const irr::SEvent &event)
{
    //On verifie que le pointeur est ok
    if(m_Nmodele != 0
    //Qu'il s'agit d'un event concernant un appui/relachement de touche
    && event.EventType == irr::EET_KEY_INPUT_EVENT
    //Qu'il s'agit de la touche z
    && event.KeyInput.Key == irr::KEY_KEY_Z)
    {
        //Si il s'agit d'un appui
        if(event.KeyInput.PressedDown == true)
            m_isMoving = true;
        //Sinon c'est un relachement
        else
            m_isMoving = false;
        //L'event est traite, on retourne true
        return true;
    }
    //Si on arrive la, c'est qu'on a pas traite l'event
    return false;
}
 
 
void CEventReceiver::majPosMesh()
{
    //On verifie que le pointeur vers le mesh est
    //ok et que la touche est enfoncee
    if(m_Nmodele != 0 && m_isMoving == true)
    {
        //On commence par recuperer la position actuelle
        irr::core::vector3df v = m_Nmodele->getPosition();
        //On y ajoute la valeur de deplacement
        v.X += 1.0f;
        //On renvoie la nouvelle position
        m_Nmodele->setPosition(v);
    }
}


Je pense qu'il y a suffisamment de commentaires pour ne pas avoir à détailler. Notez tout de même que le mouvement du mesh va se limiter à une translation sur l'axe X (on commence petit). On pourrait même optimiser ce code en se servant directement de la valeur de event.KeyInput.PressedDown, étant donné que c'est un booléen valant true lors d'un appui et false lors d'un relâchement (vous pouvez dire merci à minirop pour le tuyau ;) ).

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
bool CEventReceiver::OnEvent(const irr::SEvent &event)
{
    //On verifie que le pointeur est ok
    if(m_Nmodele != 0
    //Qu'il s'agit d'un event concernant un appui/relachement de touche
    && event.EventType == irr::EET_KEY_INPUT_EVENT
    //Qu'il s'agit de la touche z
    && event.KeyInput.Key == irr::KEY_KEY_Z)
    {
        //On assigne la bonne valeur directement
        m_isMoving = event.KeyInput.PressedDown;
        //L'event est traite, on retourne true
        return true;
    }
    //Si on arrive la, c'est qu'on a pas traite l'event
    return false;
}


Ne reste qu'à trouver une application de test pour faire tourner la bête. Allez je suis sympa, je vous fournis le code :

Code : C++
 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
#include "CEventReceiver.h"
 
 
int main(void)
{
 
    //Device, driver et graphe de scene.
    irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL,
        irr::core::dimension2d<irr::u32>(800,800),32,false,false,false);
    irr::video::IVideoDriver* driver = device->getVideoDriver ();
    irr::scene::ISceneManager *sceneManager = device->getSceneManager ();
 
    //On rend invisible le curseur.
    device->getCursorControl ()-> setVisible (false);
 
    //Sydney
    irr::scene::IAnimatedMeshMD2* modele;
    modele = (irr::scene::IAnimatedMeshMD2*)sceneManager->getMesh("sydney.md2");
    irr::scene::IAnimatedMeshSceneNode* Nmodele =
    sceneManager->addAnimatedMeshSceneNode(modele);
 
    //On modifie les proprietes de Sydney
    Nmodele->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    Nmodele->setFrameLoop(0, 0);
    Nmodele->setMaterialTexture( 0, driver->getTexture("sydney.bmp") );
 
    //La camera
    irr::scene::ICameraSceneNode *camera;
    camera = sceneManager->addCameraSceneNodeFPS (0,100.0f,300.0f);
 
    //On cree le capteur d'event et on l'associe au device.
    CEventReceiver receiver(Nmodele);
    device->setEventReceiver(&receiver);
 
    //La boucle de rendu
    while (device->run())
    {
        driver->beginScene(true, true, irr::video::SColor(0,200,200,200));
        //Met a jour la position du mesh
        receiver.majPosMesh();
        sceneManager->drawAll ();
        driver->endScene ();
    }
 
    device->drop ();
    return 0;
}


Oui je l'avoue, c'est l'adaptation du code du chapitre "votre deuxième scène". :-° Les seules lignes qui changent sont les 32 et 33 qui servent respectivement à créer l'instance de CEventReceiver (notre capteur) et à l'associer au device. Ainsi que la 40 qui met à jour la position du modèle en fonction de l'enfoncement de la touche z.

Nous y voilà. Compilez, lancez et appuyez sur la touche z. Et là, sous vos yeux ébahis, Sydney avance ! o_O Et de manière parfaitement fluide qui plus est.

Image utilisateurImage utilisateurImage utilisateur


Maintenant que vous savez comment ça marche, vous pouvez vous entraîner à ajouter quelques "mouvements". L'idéal étant de combiner les déplacements avec l'animation "courir" du modèle. Mais ça sera pour un autre chapitre. ;)

Caméra personnalisée

Si vous avez bonne mémoire, vous devez vous rappeler que lors du chapitre "votre deuxième scène", j'ai passé sous silence certains paramètres de la fonction de création d'une caméra FPS en disant que nous y reviendrions dans le chapitre consacré aux événements. Et bien nous y sommes, alors voyons voir de quoi il retourne. :)

Je remets le prototype de la fonction en question :

Code : C++
1
2
3
virtual ICameraSceneNode* irr::scene::ISceneManager::addCameraSceneNodeFPS(
    ISceneNode* parent, f32 rotateSpeed, f32 moveSpeed, s32 id,
    SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement, f32 jumpSpeed);


Les paramètres qui nous intéressent sont le 5ème et le 6ème, qui permettent de modifier les touches par défaut attribuées aux actions de la caméra. Vous pouvez donc voir qu'Irrlicht se sert d'une keyMap pour attribuer des actions aux touches. Une keymap reprend un peu le même principe qu'une std::map de la STL.

Il s'agit en fait d'un tableau d'instances de SKeyMap, et SKeyMap est une structure composée de 2 éléments :


Il existe 5 actions possibles :
  • EKA_MOVE_FORWARD
  • EKA_MOVE_BACKWARD
  • EKA_STRAFE_LEFT
  • EKA_STRAFE_RIGHT
  • EKA_JUMP_UP

Quant aux touches... Jetez un oeil à votre clavier. ;)


Le but de la manoeuvre est d'associer une (ou plusieurs) touche(s) à une action, de sorte que lorsqu'un événement sur cette (ces) touche(s) est capté, l'action soit effectuée. Par défaut pour une caméra FPS, les associations sont les suivantes :

ActionToucheDescription
EKA_MOVE_FORWARD KEY_UP flèche du haut pour déplacement en avant
EKA_MOVE_BACKWARD KEY_DOWN flèche du bas pour déplacement en arrière
EKA_STRAFE_LEFT KEY_LEFT flèche de gauche pour déplacement à gauche
EKA_STRAFE_RIGHT KEY_RIGHT flèche de droite pour déplacement à droite
EKA_JUMP_UP KEY_KEY_J touche j pour un saut


Les flèches directionnelles ne sont pas ce qu'il y a de plus ergonomique pour se déplacer. Nous allons donc reprendre la bonne vieille configuration : z pour avancer, s pour reculer, q pour aller à gauche, d pour aller à droite et barre espace pour sauter. La keyMap va se construire de la sorte :

Code : C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
irr::SKeyMap keyMap[5];
//avancer
keyMap[0].Action = irr::EKA_MOVE_FORWARD;
keyMap[0].KeyCode = irr::KEY_KEY_Z;
//reculer
keyMap[1].Action = irr::EKA_MOVE_BACKWARD;
keyMap[1].KeyCode = irr::KEY_KEY_S;
//a gauche
keyMap[2].Action = irr::EKA_STRAFE_LEFT;
keyMap[2].KeyCode = irr::KEY_KEY_Q;
//a droite
keyMap[3].Action = irr::EKA_STRAFE_RIGHT;
keyMap[3].KeyCode = irr::KEY_KEY_D;
//saut
keyMap[4].Action = irr::EKA_JUMP_UP;
keyMap[4].KeyCode = irr::KEY_SPACE;


Voilà, rien de compliqué si vous avez compris ce qui précède. Il ne reste plus qu'à la passer à la caméra lors de sa création :

Code : C++
1
2
irr::scene::ICameraSceneNode *camera;
camera = sceneManager->addCameraSceneNodeFPS (0, 100.0f, 300.0f, -1, keyMap, 5, false, 0.4);


C'est au cinquième paramètre que l'on passe le tableau, et au sixième qu'on spécifie sa taille. C'est important ! Si vous spécifiez une taille plus petite par exemple, les cases dépassant ce nombre ne seront pas prises en compte et n'effectueront pas les actions quelles devraient.


Il est maintenant temps de tester tout ça dans un petit exemple. Vous aurez besoin pour cela du fichier "map-20kdm2.pk3" que vous pouvez trouver dans le dossier media du SDK. Le code suivant va charger une map de type .bsp dans laquelle nous allons nous déplacer avec nos toutes nouvelles commandes. Le seul souci c'est qu'on n'a pas encore vu comment charger des fichiers .bsp (et encore moins quand ils sont compressés). Il va donc falloir que vous attendiez un prochain chapitre pour comprendre les quelques lignes concernant la map (ou que vous alliez voir dans la doc ;) ).

Code : C++
 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
#include <IRR/irrlicht.h>
 
int main(void)
{
    //Device, driver et graphe de scene
    irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL,
        irr::core::dimension2d<irr::u32>(800,800),32,false,false,false);
    irr::video::IVideoDriver* driver = device->getVideoDriver ();
    irr::scene::ISceneManager *sceneManager = device->getSceneManager ();
 
    //On rend invisible le curseur
    device->getCursorControl ()-> setVisible (false);
 
 
    //Sert a charger la map
    device->getFileSystem()->addZipFileArchive("map-20kdm2.pk3");
    irr::scene::IAnimatedMesh* mesh = sceneManager->getMesh("20kdm2.bsp");
    irr::scene::ISceneNode* node = 0;
    if (mesh)
        node = sceneManager->addOctTreeSceneNode(mesh->getMesh(0));
    if (node)
        node->setPosition(irr::core::vector3df(-1300,-144,-1249));
    sceneManager->setAmbientLight(irr::video::SColorf(1.0,1.0,1.0,0.0));
 
 
    //On cree la keymap associe a la camera
    irr::SKeyMap keyMap[5];
    //avancer
    keyMap[0].Action = irr::EKA_MOVE_FORWARD;
    keyMap[0].KeyCode = irr::KEY_KEY_Z;
    //reculer
    keyMap[1].Action = irr::EKA_MOVE_BACKWARD;
    keyMap[1].KeyCode = irr::KEY_KEY_S;
    //a gauche
    keyMap[2].Action = irr::EKA_STRAFE_LEFT;
    keyMap[2].KeyCode = irr::KEY_KEY_Q;
    //a droite
    keyMap[3].Action = irr::EKA_STRAFE_RIGHT;
    keyMap[3].KeyCode = irr::KEY_KEY_D;
    //saut
    keyMap[4].Action = irr::EKA_JUMP_UP;
    keyMap[4].KeyCode = irr::KEY_SPACE;
 
    //La camera
    irr::scene::ICameraSceneNode *camera;
    camera = sceneManager->addCameraSceneNodeFPS (0, 100.0f, 0.3f, -1, keyMap, 5, false, 0.4);
 
    //La boucle de rendu
    while (device->run())
    {
        driver->beginScene(true, true, irr::video::SColor(0,200,200,200));
        sceneManager->drawAll ();
        driver->endScene ();
    }
 
    device->drop ();
    return 0;
}


Image utilisateurImage utilisateurImage utilisateur


Pas mal hein ? Il ne manquerait plus qu'une skybox et on s'y croirait vraiment. Bon forcément, vu qu'on n'a pas implémenté de gravité le saut ressemble plutôt à un envol... Mais ça permet d'admirer la map de haut...

Depuis le passage à la version 1.6 du moteur, la fonction de saut de la caméra FPS ne fonctionne que si un détecteur de collision est y est associé. Donc il est fort probable (selon la version que vous utilisez) qu'il vous soit impossible de "sauter" dans la scène précédente.
"That's all folks". J'espère que le chapitre vous aura plu. J'ai tenté ici de vous faire comprendre un peu de la mécanique sous-jacente d'Irrlicht qu'on ne voit pas en restant dans la doc.

Si vous avez bonne mémoire, vous devez vous souvenir que j'insistais parfois au début du tutoriel pour que vous alliez fouiner dans la doc. Eh bien les temps changent et il est peut-être temps pour vous d'aller maintenant fouiner dans le code source. Dans la plupart des cas ce n'est pas nécessaire à la compréhension de la fonctionnalité, mais parfois (comme ici) ça permet d'avoir accès à des parties non documentées du code, et on y fait souvent des découvertes intéressantes. ;)
Chapitre précédent Sommaire Chapitre suivant

Partager

13 commentaires pour "Gestion des périphériques"
Note moyenne : 3.60 / 4 (122 votes)
Pseudo Commentaire
Hors ligne frenchy-blender # Posté le 26/05/2010 à 13:40:02
Avatar

Avis : Très bon
Flux RSS

très très bon tuto très bien expliqué

petite faute de frappe a la fin du chapitre :

la caméra FPS ne fonctionne que si un détecteur de collision est y est associé.
Hors ligne similieng # Posté le 01/03/2011 à 13:19:19

Avis : Mitigé

Bon tuto, dommage que sydney ne se deplace pas selon 2d...Ca aurait ete interessant g pense.
Hors ligne nb440 # Posté le 17/04/2011 à 17:20:49
Cet énoncé est faux !
Avatar

Bon tuto

La seule chose infinie dans l'univers, c'est la bêtise humaine ... :ange:
 
Hors ligne kikoz # Posté le 06/07/2011 à 14:35:16
O0o° :=)]}>
Avatar

Ville : Strasbourg
Pays : France métropolitaine

Bonjour,
je connais déjà la gestion des collision avec la SDL et elle m'a l'air plus simple que avec Irrlicht...
Je me demande si je peut utiliser la gestion d’évènement de la SDL (SDL_Event... ) sans faire de fenêtre SDL et dans une fenêtre Irrlicht
Si non ,très bon tutoriel :) :)

KIX o_O
 
Hors ligne -Dr3ck- # Posté le 23/01/2012 à 20:24:13
///Testostérone\\\
Avatar

Avis : Très bon

Superbe tutoriel

U MAD BRO ? Image utilisateur
 

Voir tous les commentaires