Bienvenidos sean a este post, hasta aca ya tenemos todos los dispositivos configurados pero mejoremos como controlarlos.
Si bien tenemos todo configurado si miramos con retrospectiva, nos daremos cuenta que todo es un lio. En este post, vamos a centrarnos en ordenar todo un poco y resolver un poco el codigo redundante con el cual vinimos trabajando hasta ahora. Para ello, seguiremos utilizando el codigo que vinimos trabajando hasta el post anterior. Sino lo poseen les dejo un link para descargarlo:
Descarguen el archivo y extraigan el contenido en el PC. Lo unico que deben hacer es revincular a SDL y SDL_Image. Para ello, les recomiendo este post donde comento como hacerlo para SDL y este otro post donde hago lo mismo para SDL_Image. Una vez que este todo funcionando correctamente, podemos continuar. Primero vamos a agregar la siguiente lista de prototipos dentro de la parte publica en la clase ManejarEntradas en ManejarEntradas.h:
void enTeclaAbajo();
void enTeclaArriba();
void enMoverMouse(SDL_Event&);
void enBotonMouseAbajo(SDL_Event&);
void enBotonMouseArriba(SDL_Event&);
void resetear();
void enJoyMoverEje(SDL_Event&);
void enBotonJoyAbajo(SDL_Event&);
void enBotonJoyArriba(SDL_Event&);
int obtenerJoystick(SDL_Event&);
Como pueden ver son solo los prototipos de las funciones que usaremos para cada uno de los evento que hicimos hasta ahora, nuestro siguiente paso sera modificar la funcion actualizar en ManejadorEntrada.cpp, veamos como es su codigo actual:
void ManejarEntradas::actualizar() {
SDL_Event evento;
char bufmsj[200] = "";
while (SDL_PollEvent(&evento)) {
int joy_usando = 0;
int cualEs = evento.jdevice.which;
for (int i = 0; i < m_joysticks.size(); i++) {
if (joysticks[i] == cualEs)
joy_usando = i;
}
switch (evento.type) {
case SDL_EVENT_QUIT:
Eljuego::instanciar()->limpiar();
break;
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
switch (evento.jaxis.axis) {
case 0:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->
setX(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->
setX(-1);
else
m_valoresJoystick[joy_usando].first->
setX(0);
break;
case 1:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->
setY(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->
setY(-1);
else
m_valoresJoystick[joy_usando].first->
setY(0);
break;
case 2:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->
setX(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->
setX(-1);
else
m_valoresJoystick[joy_usando].second->
setX(0);
break;
case 3:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->
setY(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->
setY(-1);
else
m_valoresJoystick[joy_usando].second->
setY(0);
break;
}
break;
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
m_estadoBoton[joy_usando][evento.jbutton.button] = true;
sprintf_s(bufmsj, "Boton presionado: %d\n",
evento.jbutton.button);
OutputDebugStringA(bufmsj);
break;
case SDL_EVENT_JOYSTICK_BUTTON_UP:
m_estadoBoton[joy_usando][evento.jbutton.button] = false;
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
switch (evento.button.button) {
case SDL_BUTTON_LEFT:
m_estadoBotonMouse[IZQUIERDO] = true;
break;
case SDL_BUTTON_MIDDLE:
m_estadoBotonMouse[MEDIO] = true;
break;
case SDL_BUTTON_RIGHT:
m_estadoBotonMouse[DERECHO] = true;
break;
}
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
switch (evento.button.button) {
case SDL_BUTTON_LEFT:
m_estadoBotonMouse[IZQUIERDO] = false;
break;
case SDL_BUTTON_MIDDLE:
m_estadoBotonMouse[MEDIO] = false;
break;
case SDL_BUTTON_RIGHT:
m_estadoBotonMouse[DERECHO] = false;
break;
}
break;
case SDL_EVENT_MOUSE_MOTION:
m_posicionMouse->setX(evento.motion.x);
m_posicionMouse->setY(evento.motion.y);
break;
}
}
}
Todo esto lo modificaremos de la siguiente manera:
void ManejarEntradas::actualizar() {
SDL_Event evento;
while (SDL_PollEvent(&evento)) {
switch (evento.type) {
case SDL_EVENT_QUIT:
Eljuego::instanciar()->limpiar();
break;
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
enJoyMoverEje(evento);
break;
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
enBotonJoyAbajo(evento);
break;
case SDL_EVENT_JOYSTICK_BUTTON_UP:
enBotonJoyArriba(evento);
break;
case SDL_EVENT_MOUSE_MOTION:
enMoverMouse(evento);
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
enBotonMouseAbajo(evento);
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
enBotonMouseArriba(evento);
break;
case SDL_EVENT_KEY_DOWN:
enTeclaAbajo();
break;
case SDL_EVENT_KEY_UP:
enTeclaArriba();
break;
default:
break;
}
}
}
En lugar de usar distintos case para verificar cada uno de los eventos y ejecutar el bloque de acciones o instrucciones, lo reemplazamos por un llamado a la funcion que reemplazara a las instrucciones que teniamos antes. Nuestro siguiente paso sera definir cada una de estas funciones. Pero antes de comenzar con esto, vamos a definir la siguiente funcion:
int ManejarEntradas::obtenerJoystick(SDL_Event& evento) {
int encontrado = 0;
int cualEs = evento.jdevice.which;
for (int i = 0; i < m_joysticks.size(); i++) {
if (joysticks[i] == cualEs)
encontrado = i;
}
return encontrado;
}
Esta funcion es la encargada de informarnos cual es el joystick que envio el evento. Primero obtendremos cual es su id, luego mediante un bucle buscaremos en que posicion se encuentra dentro del vector donde los almacenamos. Una vez hallado, lo devolvemos y lo utilizaremos en algunas de las siguientes funciones. Comencemos con la definicion de las funciones para manejar los eventos, agreguemos la primera de ellas:
void ManejarEntradas::enJoyMoverEje(SDL_Event& evento) {
int joy_usando = obtenerJoystick(evento);
switch (evento.jaxis.axis) {
case 0:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->setX(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->setX(-1);
else
m_valoresJoystick[joy_usando].first->setX(0);
break;
case 1:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->setY(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].first->setY(-1);
else
m_valoresJoystick[joy_usando].first->setY(0);
break;
case 2:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->setX(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->setX(-1);
else
m_valoresJoystick[joy_usando].second->setX(0);
break;
case 3:
if (evento.jaxis.value > m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->setY(1);
else if (evento.jaxis.value < -m_joystickZonaMuerta)
m_valoresJoystick[joy_usando].second->setY(-1);
else
m_valoresJoystick[joy_usando].second->setY(0);
break;
}
}
En esta accion volveremos a tener las instrucciones para controlar los cuatro ejes que teniamos antes, son exactamente las mismas que vimos en este post, agreguemos las siguiente dos funciones:
void ManejarEntradas::enBotonJoyAbajo(SDL_Event& evento) {
int joy_usando = obtenerJoystick(evento);
m_estadoBoton[joy_usando][evento.jbutton.button] = true;
}
void ManejarEntradas::enBotonJoyArriba(SDL_Event& evento) {
int joy_usando = obtenerJoystick(evento);
m_estadoBoton[joy_usando][evento.jbutton.button] = false;
}
La primera funcion la usamos para detectar cuando presionamos un boton y la segunda para detectar cuando lo soltamos, el codigo lo explicamos en este post, agreguemos la siguiente funcion:
void ManejarEntradas::enMoverMouse(SDL_Event& evento) {
m_posicionMouse->setX(evento.motion.x);
m_posicionMouse->setY(evento.motion.y);
}
Este sera la funcion que hara el movimiento del mouse tal como antes, agreguemos las siguientes tres funciones:
void ManejarEntradas::enBotonMouseAbajo(SDL_Event& evento) {
switch (evento.button.button) {
case SDL_BUTTON_LEFT:
m_estadoBotonMouse[IZQUIERDO] = true;
break;
case SDL_BUTTON_MIDDLE:
m_estadoBotonMouse[MEDIO] = true;
break;
case SDL_BUTTON_RIGHT:
m_estadoBotonMouse[DERECHO] = true;
break;
}
}
void ManejarEntradas::enBotonMouseArriba(SDL_Event& evento) {
switch (evento.button.button) {
case SDL_BUTTON_LEFT:
m_estadoBotonMouse[IZQUIERDO] = false;
break;
case SDL_BUTTON_MIDDLE:
m_estadoBotonMouse[MEDIO] = false;
break;
case SDL_BUTTON_RIGHT:
m_estadoBotonMouse[DERECHO] = false;
break;
}
}
void ManejarEntradas::resetear() {
m_estadoBotonMouse[IZQUIERDO] = false;
m_estadoBotonMouse[MEDIO] = false;
m_estadoBotonMouse[DERECHO] = false;
}
Las dos primeras funciones son para detectar cuando presionamos un boton o lo soltamos, la primera funcion verifica cual de los tres presionamos y establecemos como true. En la segunda funcion vemos cual se solto y establecemos como false. La ultima funcion se encarga de resetear todos los botones del mouse y esto nos servira para mas adelante pero es basicamente para resetear el estado de los botones del mouse a false. Agreguemos las ultimas dos funciones:
void ManejarEntradas::enTeclaAbajo(){
m_estadoTecla = SDL_GetKeyboardState(0);
}
void ManejarEntradas::enTeclaArriba(){
m_estadoTecla = SDL_GetKeyboardState(0);
}
Estas dos funciones detectaran cuando presionamos una tecla o la soltamos, aunque tecnicamente son iguales porque lo unico que hacen es establecer el valor del array keystate en m_estadoTeclas. Con esto ya tenemos todas las funciones definidas pero antes de terminar debemos ir a la funcion manejaEntrada en Jugador.cpp y al comienzo de la misma agregaremos las siguientes lineas:
Vector2D* v = Controles::instanciar()->getPosicionMouse();
m_velocidad = (*v - m_posicion);
Esto les recomiendo que lo agreguen antes del resto de los eventos porque sino anulara al que este posterior de ese, les dejo como queda el bloque final:
void Jugador::manejaEntrada() {
Vector2D* v = Controles::instanciar()->getPosicionMouse();
m_velocidad = (*v - m_posicion);
if (Controles::instanciar()->joysticksIniciados()) {
if (Controles::instanciar()->valorX(0, 1) > 0 ||
Controles::instanciar()->valorX(0, 1) < 0) {
m_velocidad.setX(1 * Controles::instanciar()->valorX(0, 1));
}
if (Controles::instanciar()->valorY(0, 1) > 0 ||
Controles::instanciar()->valorY(0, 1) < 0) {
m_velocidad.setY(1 * Controles::instanciar()->valorY(0, 1));
}
if (Controles::instanciar()->valorX(0, 2) > 0 ||
Controles::instanciar()->valorX(0, 2) < 0) {
m_velocidad.setX(1 * Controles::instanciar()->valorX(0, 2));
}
if (Controles::instanciar()->valorY(0, 2) > 0 ||
Controles::instanciar()->valorY(0, 2) < 0) {
m_velocidad.setY(1 * Controles::instanciar()->valorY(0, 2));
}
if (Controles::instanciar()->getEstadoBoton(0, 1))
m_velocidad.setX(1);
}
if (Controles::instanciar()->getEstadoBotonMouse(DERECHO))
m_velocidad.setX(1);
if (Controles::instanciar()->teclaPresionada(SDL_SCANCODE_RIGHT)) {
m_velocidad.setX(2);
}
if (Controles::instanciar()->teclaPresionada(SDL_SCANCODE_LEFT)) {
m_velocidad.setX(-2);
}
if (Controles::instanciar()->teclaPresionada(SDL_SCANCODE_DOWN)) {
m_velocidad.setY(2);
}
if (Controles::instanciar()->teclaPresionada(SDL_SCANCODE_UP)) {
m_velocidad.setY(-2);
}
}
Con todo esto podemos probar nuevamente nuestro proyecto y ver como funciona ahora mediante el siguiente video
En resumen, con esto hemos completado las distintas formas de poder controlar a nuestros sprites, ya sea con un Joystick, un mouse o el teclado, hemos ordenado el codigo de una forma que quede de una manera mas legible ante cualquier inconveniente. Espero les haya sido de utilidad y les dejo un link a GitHub donde estan los codigos creados hoy:
Les dejo algunas de mis redes sociales para seguirme o recibir una notificacion cada vez que subo un nuevo post:


Donación
Es para mantenimento del sitio, gracias!
$1.50





