“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; }