El lenguaje de programación iJava (6)

Control de teclado y ratón

Ya hemos visto como hacer una animación usando la función animate pero, por ejemplo, para hacer un videojuego, además de mover dibujos por la pantalla tenemos que ser capaces de controlar su comportamiento usando el ratón o el teclado. Para conseguirlo vamos a utilizar algunas variables globales que existen en iJava y que tendremos disponibles en todos nuestros programas sin necesidad de declararlas:

  • mouseX: Guarda en todo momento la coordenada horizontal del ratón.
  • mouseY: Guarda en todo momento la coordenada vertical del ratón.
  • mousePressed: Contiene un valor true si algún botón del ratón está pulsado.
  • mouseButton: Indica qué botón (LEFTBUTTON, MIDDLEBUTTON o RIGHTBUTTON) es el que está pulsado.
  • keyPressed: Contiene un valor true si alguna tecla está pulsada.
  • key: Contiene una cadena indicando el nombre de la tecla pulsada.

En el siguiente ejemplo se utilizan las tres primeras variables para conseguir que se dibuje un círculo en la posición que esté el ratón pero sólo si hay algún botón del ratón pulsado:

void dibuja() {
  background(0,0,0);
  if (mousePressed) {
    ellipse(mouseX, mouseY, 50,50);
  }  
}

void main() {
  animate(dibuja);
}

Como puedes ver el uso de estas variables es muy sencillo. Si además queremos que sólo funcione cuando se pulsa un botón en particular usaremos la variable mouseButton para comprobar de qué botón se trata comparándo su valor con el de una de las tres constantes que incluye iJava para referirse a uno de los tres posibles botones del ratón: LEFTBUTTON, MIDDLEBUTTON o RIGHTBUTTON.

void dibuja() {
  background(0,0,0);
  if (mousePressed) {
    if (mouseButton == RIGHTBUTTON) {
    	ellipse(mouseX, mouseY, 50,50);
    }
  }  
}

void main() {
  animate(dibuja);
}

Fíjate como sólo hemos tenido que añadir una nueva comprobación y ahora, al ejecutar el programa, sólo se dibuja el círculo cuando pulsamos con el botón derecho. Prueba a cambiar el código para que sólo funcione, por ejemplo, con el botón izquierdo.

Para aprender a utilizar las variables keyPressed y key vamos a hacer un pequeño programa que escriba el nombre de la tecla pulsada cuando haya alguna en esa situación. El programa es el siguiente:

void dibuja() {
  background(0,0,0);
  if (keyPressed) {
    text(key, 100,100);
  }  
}

void main() {
  animate(dibuja);
}

Cuando pruebes el programa pulsa las teclas de las letras y los números y verás que el nombre que guarda la variable key se corresponde justamente con la letra o el número en cuestión independientemente de que pulsemos mayúsculas o no. De hecho, si pulsamos mayúsculas el nombre que se muestra es shift. Esto es así con las teclas de control y los nombres que se pueden obtener son los siguientes:

  • shift: para la tecla mayúsculas.
  • control: para la tecla ctrl.
  • valt: para la tecla alt.
  • vbackspace: para la tecla de borrar hacia atrás.
  • tab: para la tecla del tabulador.
  • enter: para la tecla de retorno de carro.
  • return: para la tecla de retorno de carro.
  • esc: para la tecla de escape.
  • delete: para la tecla de suprimir (borrar lo que hay a la derecha del cursor).
  • capslk: para la tecla de bloqueo mayúsculas.
  • pgup: para la tecla de página anterior.
  • pgdn: para la tecla de página siguiente.
  • end: para la tecla de fin.
  • home: para la tecla de inicio.
  • left: para la flecha izquierda.
  • up: para la flecha arriba.
  • right: para la flecha derecha.
  • down: para la flecha abajo
  • left-meta: para la tecla de AltGr o Cmd del lado izquierdo
  • right-meta: para la tecla de AltGr o Cmd del lado izquierdo

Aspectos avanzados

Utilizando las variables key y keyPressed podemos programar casi cualquier tipo de aplicación interativa o videojuego que use el teclado. Sin embargo, a veces necesitamos tener un control más preciso para poder actuar de una manera cuando se pulsa una tecla y de otra cuando se suelta. Si en nuestro programa incluimos una función llamada onKeyPressed que reciba como parámetro una cadena y devuelva null, dicha función será invocada automáticamente cada vez que se pulse una tecla. El nombre de la tecla en cuestión se le pasará a la función como parámetro. Es importante tener en cuenta que sólo se ejecuta la función al pulsarse la tecla, aunque esta permanece pulsada no se vuelve a ejecutar la función.

Del mismo modo, si incluimos una función llamada onKeyReleased seremos capaces de controlar cuando se suelta cualquier tecla. El siguiente programa muestra un ejemplo de uso de las dos funciones en el que, usando las variables globales aPulsada y bPulsada podemos saber en todo momento el estado de las teclas A y B respectivamente para mostrar por pantalla un dibujo asociado a cada una.

boolean aPulsada;
boolean bPulsada;

void onKeyPressed(String tecla) {
  switch (tecla) {
    case "a": 
    	aPulsada = true;  
    	break;
    case "b":
    	bPulsada = true;
    	break;
  }
}

void onKeyReleased(String tecla) {
  switch (tecla) {
    case "a":
    	aPulsada = false;
    	break;
    case "b":
    	bPulsada = false;
    	break;
  }
}

void dibuja() {
  background(0,0,0);
	if (aPulsada) {
    ellipse(100,100, 50,50);
  }  
  if (bPulsada) {
    rect(75, 200, 50,50);
  }
}

void main() {
  animate(dibuja);
}

Normalmente usamos la animate indicando entre paréntesis el nombre de la función que queremos que se anime, es decir, que se ejecute una vez tras otra de forma indefinida. De esta forma, el ordenador ejecuta la función 25 veces por segundo o, dicho de otro modo, cada 40 milisegundos. Sin embargo, existe la opción de pasar un segundo parámetro a la función animate indicando el tiempo a esperar entre cada ejecución de la función a animar. De este modo podemos hacer animaciones más fluidas o más lentas según nos interese.

En el siguiente ejemplo vemos una animación que va muy lenta pues estamos haciendo que se ejecute la función dibuja cada medio segundo (500milisegundos)

int x = 25;
int dx = 1;

void dibuja() {
  background(0,0,0);
  if (x > 295) dx = -1;
  if (x < 25) dx = 1;
  x = x + dx;
  ellipse(x,160,50,50);
}

void main() {
  animate(dibuja, 500);
}

Además, podemos usar la función animate a mitad de una animación para hacer que el ordenador deje de hacer la animación actual y pase a hacer la nueva. Esto nos puede resultar muy útil para definir las distintas fases de nuestro juego: menú principal, juego, ventana de resultados, etc. En el siguiente ejemplo se demuestra esta técnica usando dos funciones de animación distintas, una para mover un círculo en horizontal y otra en vertical, al pulsar una tecla se pasa de una animación a la otra:

int x = 25;
int y = 25;
int dx = 1;
int dy = 1;

void dibujaHorizontal() {
  background(0,0,0);
  if (x > 295) dx = -1;
  if (x < 25) dx = 1;
  x = x + dx;
  ellipse(x,y,50,50);
  if (keyPressed) animate(dibujaVertical);
}

void dibujaVertical() {
  background(0,0,0);
  if (y > 295) dy = -1;
  if (y < 25) dy = 1;
  y = y + dy;
  ellipse(x,y,50,50);
  if (keyPressed) animate(dibujaHorizontal);
}

void main() {
  animate(dibujaHorizontal);
}

Sigue en aprendiendo en El lenguaje de programación iJava (7)