Anuncios

Bienvenidos sean a este post, hoy veremos como poder manejar los botones de nuestro joystick.

Anuncios

Esto va a ser una tarea mucho mas simple que manejar los ejes porque en este caso solo debemos saber el estado del mismo, si esta siendo pulsado o no. Para poder trabajar vamos a utilizar al proyecto del post anterior. Sino lo poseen les dejo un link para descargarlo:

Proyecto Juego

Anuncios

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. Nuestro primer paso es ir a la parte privada de ManejarEntradas.h y agregaremos la siguiente variable:

std::vector<std::vector<bool>> m_estadoBoton;
Anuncios

Declaramos un array con otro array de estados booleanos, el primer array sera para el joystick y el array interno almacenara todos los estados de los botones del joystick correspondiente. El siguiente paso sera agregar un prototipo en la parte publica de la clase en el mismo archivo:

bool getEstadoBoton(int, int);
Anuncios

Despues de esto, vayamos a ManejarEntradas.cpp y pasemos definir esta funcion para recuperar el estado del boton:

bool ManejarEntradas::getEstadoBoton(int joy, int numBoton) {
	return m_estadoBoton[joy][numBoton];
}
Anuncios

La funcion recibira dos valores, el primero sera para identificar cual es el joystick y el segundo sera para saber cual boton. En el bloque devolveremos el estado del boton mediante los datos informados. Observen como primero informamos el valor para el primer vector, joy, y luego el otro valor para el vector interno, numeroBoton, nuestro siguiente paso sera modificar a iniciarJoystick para poder operar con los botones. Para ello, vamos a modificarlo de la siguiente manera:

void ManejarEntradas::iniciarJoysticks() {
	if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
		SDL_InitSubSystem(SDL_INIT_JOYSTICK);

	joysticks = SDL_GetJoysticks(&total_joy);

	if (total_joy > 0) {
		for (int i = 0; i < total_joy; i++) {
			SDL_Joystick* joy = SDL_OpenJoystick(joysticks[i]);
			if (joy) {
				m_joysticks.push_back(joy);
				m_valoresJoystick.push_back(std::make_pair(
					new Vector2D(0, 0), new Vector2D(0, 0)));
				std::vector<bool> tempBotones;
				for (int j = 0; j < SDL_GetNumJoystickButtons(joy); 
					j++) {
					tempBotones.push_back(false);
				}
				m_estadoBoton.push_back(tempBotones);
			}
			else {
				OutputDebugStringA(SDL_GetError());
			}
		}
		SDL_SetJoystickEventsEnabled(true);
		m_bJoyIniciados = true;
		char bufmsj[200] = "";
		sprintf_s(bufmsj, "Joysticks Iniciados: %d\n", m_joysticks.size());
		OutputDebugStringA(bufmsj);
	}
	else {
		m_bJoyIniciados = false;
	}
}
Anuncios

En este caso, la primera modificacion que hicimos fue crear otro array, vector, de tipo bool para almacenar de manera temporal el estado de los botones, luego usaremos un for donde pasara por todos los botones de nuestro dispositivo gracias a SDL_JoystickNumButtons y el valor informado en joy. Como estamos iniciando el estado de nuestros botones consideramos que ninguno esta presionado y por ende establecemos como false a todos los botones. Una vez completo nuestro array, lo pasaremos a m_estadosBoton. Con nuestro array de los estados de los botones iniciados, solo nos resta agregar los eventos para los botones. Para ello debemos ir a la funcion actualizar, y vamos a modificarla de la siguiente manera:

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

Los cambios que introducimos fueron principalmente para evaluar cuando se presiona y se libera el boton. Pero al inicio definimos un char para almacenar texto que usaremos mas adelante. Como mencionamos, agregamos dos case que evaluan a los eventos de boton apretado (SDL_EVENT_JOYSTICK_BUTTON_DOWN) y cuando lo soltamos (SDL_EVENT_JOYSTICK_BUTTON_UP), sin modificar al que tenemos para los sticks que vimos en el post anterior. Veamos como es el case de cuando presionamos el boton. Primero pasaremos a true el boton almacenado mediante los valores que tenemos del mismo. Luego con sprintf_s le agregaremos el texto indicando que boton presionamos a bufmsj. Para luego mostrarlo en la ventana de depuracion con OutputDebugStringA. El otro case solamente vuelve al boton en el vector al estado false para indicarnos que lo dejamos de presionar.

Anuncios

Vamos a hacer la ultima para poder ver como trabaja mediante la implementacion en Jugador, pero vamos a hacer una modificacion mas. Esta sera para ver como afecta a nuestro sprite la pulsacion del boton, para ello debemos ir a la funcion manejaEntrada en Jugador.cpp y agregaremos el siguiente bloque:

if (Controles::instanciar()->getEstadoBoton(0, 1))
	m_velocidad.setX(1);
Anuncios

Agregamos un condicional donde instancia a la funcion getEstadoBoton para que trabaje con el boton 1, en mi caso al ser un gamepad de PS4 equivale al boton de circulo, y cuando sea verdad procede a movilizar hacia la derecha el sprite, compilemos veamos que sucede

Anuncios

Como pueden ver en el video tenemos todavia el movimiento de nuestros sticks, pero ahora tambien lo desplazamos cuando presionamos el boton de circulo de mi mando.

Anuncios
Nota: 
Les recuerdo que este es un mando de PS4, si tienen otro mando les recomiendo averiguar cual es el valor que devuelve cada boton para ajustar el codigo a su mando.
Anuncios

En resumen, hoy hemos agregado la posibilidad de interceptar botones, en realidad de poder ver sus dos posibles estados, pulsado y suelto, hemos visto como poder tener un control de cada uno de ellos en cada uno de los joysticks que tenemos conectados y por ultimo hicimos un par de leves modificaciones para poder ver cual boton presionamos y como podemos trabajar con el. Espero les haya sido de utilidad y les dejo un link a GitHub donde estan los codigos creados hoy:

Los botones del mando / GitHub

Les dejo algunas de mis redes sociales para seguirme o recibir una notificacion cada vez que subo un nuevo post:

Anuncios
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50