Estuve intentando ver que tal sería darle soporte de joysticks a mi motor. Me di cuenta que no es tan simple como parece. Por suerte la interfaz de sf::Joystick es bastante intuitiva. He probado con dos gamepads: un USB Genérico (similar al de Playstation), y el controlador de XboX 360. Lo primero que hice fue crear un std::vector para almacenar todos los joysticks que SFML detecte como conectados:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// vector para almacenar los Joysticks que hay conectados
std::vector <unsigned int> ListaJSConectados;
// Buscar si hay joysticks conectados
for (unsigned int a = 0; a < sf::Joystick::Count; ++a) {
if (sf::Joystick::isConnected (a)) {
std::cout << "Joystick num " << a << " esta conectado y tiene "
<< sf::Joystick::getButtonCount(a) << " botones" << std::endl;
ListaJSConectados.push_back (a);
} // if
} // for
std::cout << "Detectados " << ListaJSConectados.size() << " joysticks" << std::endl; |
Luego de eso escribí el código para verificar si algún botón fue presionado. Para eso, hay que recorrer el vector ListaJSConectados, y luego verificar cada uno de los botones, dependiendo de cuantos botones tenga cada dispositivo. Eso se puede saber gracias al método sf::Joystick::getButtonCount.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Revisar el estado de los JS detectados
// nj = Numero de JS, nb = Numero de boton
for (unsigned int nj = 0; nj < ListaJSConectados.size(); ++nj) {
// Revisar los botones presionados
for (unsigned int nb = 0; nb < sf::Joystick::getButtonCount (nj); ++nb) {
if (sf::Joystick::isButtonPressed (nj, nb)) {
std::cout << "Boton " << nb << " presionado en el JS num " << nj << std::endl;
}
}
} |
Finalmente está el tema de tratar de mover un personaje de nuestro juego (el protagonista) usando los ejes del joystick. Esto puede llegar a ser un infierno. Cada dispositivo es libre de manejar los ejes y botones a su antojo. Entonces.. ¿Cómo puedo escribir código que sea compatible con todos los dispositivos? .. Buena pregunta..
Por lo general todos los dispositivos deberían tener un eje X y un eje Y (por suerte!). Esto se puede saber consultando el método hasAxis, el cual devuelve true si el dispositivo tiene determinado eje. El método getAxisPosition devuelve un float con la posición del eje que le demos como parámetro. SFML maneja valores entre -100 y 100. La cuestión es que algunos joysticks son más sensibles que otros.. cuando alguna palanca sea movida hacia la izquierda, podemos obtener instantáneamente el valor -100, o podemos ir obteniendo valores negativos intermedios (-23, -42, etc). Incluso puede que el valor nunca llegue exactamente a -100, puede que quede fijo en -96, -99 (como me pasó con mi joystick de X360).
Entonces, la mejor forma que encontré para saber si debo mover el personaje a la izquierda de la pantalla utilizando el eje X del joystick, es esta:
|
1 2 3 4 5 6 |
float EjeXpos = sf::Joystick::getAxisPosition (0, sf::Joystick::X);
// J0 izquierda
if (EjeXpos < -50.0f) {
pos1.x -= velocidad * tiempoDelta.asSeconds();
} |
Consulto la posición del eje X para el joystick 0, que en mi caso, es el primer joystick instalado en mi PC (el joystick número 0 no es necesariamente el primer joystick conectado o el primero detectado). Si la posición es menor a -50, lo tomo como que el eje fue desplazado a la izquierda, por lo tanto actualizo la posición de mi personaje (según la velocidad y el tiempo delta, como se acostumbra hacer). Este código fue probado con mis dos joysticks, y funcionó por igual con ambos.
Claro que se podría hacer algo para aprovechar la sensibilidad de algunos dispositivos como el controlador de la X360. Se podría por ejemplo tratar de aumentar la aceleración de una entidad dependiendo del valor del eje. Los botones LT y RT no son detectados como botones, sino como ejes, y devuelven valores entre -99 y 99 aprox. Tal vez un dispositivo diseñado para simuladores de vuelo tengan más ejes, más sensibilidad, etc. Pero bueno, eso quedará para más adelante…







