Gérer une configuration clavier/souris dynamique

“Binder” une touche cela veut dire lui affecter une action spécifique. Par exemple, vous pouvez faire que, par défaut, l'utilisateur utilise les touches flechées pour se diriger et la touche “Return” pour tirer. De même vous pouvez définir le clic gauche de la souris pour tirer dans un FPS. En réalité, c'est l'action que vous attachez à une touche.

Tout ca c'est très bien, mais que se passe-t-il lorsque le joueur veut changer de touche ? S'il est gaucher, il préferera surement utiliser le bouton droit de la souris pour tirer ! Le bind permet cela de manière très simple. Il suffit de spécifier au programme que telle touche déclenche telle action plutôt que telle autre touche.

La méthode que je vais vous montrer ici n'est pas parfaite, il n'y a pas de vérification (une même touche pourrait déclencher 50 actions), on ne peut binder qu'une seule touche par action, etc… Néanmoins, cela vous donnera une idée pour permettre cela simplement dans vos futurs programmes !

Tout d'abord, il faut que l'on puisse distinguer les différents modes d'entrée de la SFML : souris, clavier, joystick. En effet, un clavier possède plus de 100 touches, un joystick quelques boutons, et la souris peut avoir 2 boutons et plus, ainsi qu'une une molette dans la pluspart des cas :

enum InputType
{
    KeyboardInput,
    MouseInput,
    JoystickInput
};

Il faut ensuite définir un Bind d'action :

struct MyKeys
{
    InputType myInputType;
    sf::Event::EventType myEventType;
    sf::Key::Code myKeyCode;
    sf::Mouse::Button myMouseButton;
};

Voilà, avec cette structure, on peut affecter un type d'entrée, un type d'évènement, et des infos concernant cet évènement.

On crée alors, dans le programme, le conteneur des différents binds que l'on remplira de manière simple comme ici, ou de manière plus poussée (via fichier binaire, xml, etc…) :

std::map<std::string,MyKeys> Keys;
MyKeys key;
//On bind le clic souris gauche à l'action "Shoot"
key.myInputType = MouseInput;
key.myEventType = sf::Event::MouseButtonPressed;
key.myMouseButton = sf::Mouse::Left;
Keys["Shoot"] = key;
//On bind l'appui sur le clavier de la touche Entrée à l'action "Jump"
key.myInputType = KeyboardInput;
key.myEventType = sf::Event::KeyPressed;
key.myKeyCode = sf::Key::Return;
Keys["Jump"] = key;
//On bind l'appui sur le clavier de la touche Control située à gauche à l'action "Use"
key.myInputType = KeyboardInput;
key.myEventType = sf::Event::KeyPressed;
key.myKeyCode = sf::Key::LControl;
Keys["Use"] = key;

L'utilisation d'une std::map permet de savoir de quelle action on parle. Il faut maintenant modifier notre “horrible” gestion des évènements en dur par quelque chose de plus dynamique !

//Manage Events
while (App.GetEvent(Event))
{
   bla bla bla...
   //My events
   //Shoot Event
   if (TestEvent(Keys["Shoot"],Event))
   {
      Shoot ();
   }
   if (TestEvent(Keys["Jump"],Event))
   {
      Jump ();
   }
   if (TestEvent(Keys["Use"],Event))
   {
      Use ();
   }
}

On voit bien, ici, que l'on gère chaque évènement par son nom. Il est alors possible d'utiliser une fonction, ou du code directement, ou ce que l'on veut.

Reste à définir la fonction de test d'un évènement par rapport à nos binds :

bool TestEvent (MyKeys k, sf::Event e)
{
    //Mouse event
    if (k.myInputType==MouseInput && k.myEventType==e.Type && k.myMouseButton==e.MouseButton.Button)
    {
        return (true);
    }
    //Keyboard event
    if (k.myInputType==KeyboardInput && k.myEventType==e.Type && k.myKeyCode==e.Key.Code)
    {
        return (true);
    }
    return (false);
}

Voilà, dès lors que la fonction test renvoie “Vrai”, l'action a été déclenchée. Le programme ne sait pas par qui exactement, mais ce n'est pas nécessaire !

Voilà un code exemple complet à compiler soi-même ;-)

#include <iostream>
#include <fstream>
#include <SFML/Graphics.hpp>
 
enum InputType
{
    KeyboardInput,
    MouseInput,
    JoystickInput
};
 
struct MyKeys
{
    InputType myInputType;
    sf::Event::EventType myEventType;
    sf::Key::Code myKeyCode;
    sf::Mouse::Button myMouseButton;
};
 
bool TestEvent (MyKeys k, sf::Event e);
void Shoot (void);
void Jump(void);
 
int main(int argc, char** argv)
{
    //Variables for main
    sf::RenderWindow App;
    bool Running = true;
    sf::Event Event;
 
    //Variables for demo
    std::map<std::string,MyKeys> Keys;
    MyKeys key;
    //On bind le clic souris gauche à l'action "Shoot"
    key.myInputType = MouseInput;
    key.myEventType = sf::Event::MouseButtonPressed;
    key.myMouseButton = sf::Mouse::Left;
    Keys["Shoot"] = key;
    //On bind l'appui sur le clavier de la touche Entrée à l'action "Jump"
    key.myInputType = KeyboardInput;
    key.myEventType = sf::Event::KeyPressed;
    key.myKeyCode = sf::Key::Return;
    Keys["Jump"] = key;
    //On bind l'appui sur le clavier de la touche Control située à gauche à l'action "Use"
    key.myInputType = KeyboardInput;
    key.myEventType = sf::Event::KeyPressed;
    key.myKeyCode = sf::Key::LControl;
    Keys["Use"] = key;
 
    //Window creation
    App.Create(sf::VideoMode(640, 480, 16), "config test");
 
    //Main loop
    while (Running)
    {
        //Manage Events
        while (App.GetEvent(Event))
        {
            //Using Event normally
 
            //Window closed
            if (Event.Type == sf::Event::Closed)
            {
                Running = false;
            }
 
            //Key pressed
            if (Event.Type == sf::Event::KeyPressed)
            {
                switch (Event.Key.Code)
                {
                    case sf::Key::Escape :
                        Running = false;
                        break;
                    case sf::Key::A :
                        std::cout<<"Key A !"<<std::endl;
                        break;
                    default :
                        break;
                }
            }
 
            //Using Event for binding
            //Shoot
            if (TestEvent(Keys["Shoot"],Event))
            {
                //You can use a function
                Shoot ();
            }
            if (TestEvent(Keys["Jump"],Event))
            {
                Jump ();
            }
            if (TestEvent(Keys["Use"],Event))
            {
                //or only code
                std::cout<<"Use !"<<std::endl;
            }
        }
 
        //Display the result
        App.Display();
    }
 
    //End of application
    return EXIT_SUCCESS;
}
 
bool TestEvent (MyKeys k, sf::Event e)
{
    //Mouse event
    if (k.myInputType==MouseInput && k.myEventType==e.Type && k.myMouseButton==e.MouseButton.Button)
    {
        return (true);
    }
    //Keyboard event
    if (k.myInputType==KeyboardInput && k.myEventType==e.Type && k.myKeyCode==e.Key.Code)
    {
        return (true);
    }
    return (false);
}
 
void Shoot (void)
{
    std::cout<<"Shoot !"<<std::endl;
}
 
void Jump (void)
{
    std::cout<<"Jump !"<<std::endl;
}
 
fr/tutoriels/bindevents.txt · Last modified: 2008/07/03 17:55 by Daazku
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki