Caza la manzana


En este proyecto vas a llevar la programación un poco más lejos y crearás un pequeño videojuego donde nuestro aguerrido héroe, el famoso científico Newton, intenta no perder la oportunidad de que la manzana le caiga en la cabeza.

Vamos a crear, paso a paso, un programa en el que Newton coleccione puntos durante medio minuto, al recibir tantos manzanazos en la cabeza como sea posible.

  1. Crea una manzana y un científico

    Empezarás creando una manzana y un científico. Las manzanas, por ahora, serán círculos que caen del cielo, mientras que Newton será un cuadrado al fondo de la pantalla.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-1

    Resultado

    Se dibuja un circulo que representa la manzana, y un cuadrado para marcar la posición del personaje Newton.

    Comandos

    • rect(x, y, rectWidth, rectHeight): Dibuja un rectángulo. x e y establecen la posición de la esquina superior izquierda, rectWidth y rectHeight establecen el tamaño en píxeles.

    Cómo funciona

    • En la función setup() se establece el tamaño de la ventana a 400 x 400 píxeles.
    • En la función draw() se dibuja un círculo en las coordenadas (15, 15), con x e y de 20 píxeles de diámetro.
    • Se dibuja un cuadrado en la esquina superior izquierda con las coordenadas (width/2, height-25) de 20 x 20 píxeles de tamaño.
  2. Controla a Newton con el teclado

    En este paso, harás que Newton (el cuadrado) se mueva a la derecha y a la izquierda con las flechas del teclado.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-2

    Resultado

    Pulsa las flechas del teclado y verás cómo se mueve el cuadrado.

    Comandos

    • keyPressed(){ statements }: Esta función se llama cada vez que se pulsa una tecla. Es decir, cualquier código escrito dentro de esta función será ejecutado al pulsar una tecla.
    • keyCode: Es una variable interna del sistema que se emplea para detectar qué tecla ha sido pulsada.
    • RIGHT: Constante que contiene el valor del código de la tecla «flecha derecha».
    • LEFT: Constante que contiene el valor del código de la tecla «flecha izquierda».

    Cómo funciona

    • Se declara la variable nX, tipo int, y se inicializa a 0. Esta variable almacenará la posición X de Newton (el cuadrado).
    • En la función draw(), se configura el color del fondo a gris claro. Al pintar de nuevo el fondo en cada iteración de la función draw() se elimina el rastro del cuadrado cuando se mueve.
    • La posición X del cuadrado se fija con la variable nX. La posición Y es aún fija y vale height-25.
    • Se llama a la función keyPressed() cada vez que se pulsa una tecla.
    • Si se pulsa la tecla «fecha derecha», if( keyCode == RIGHT), se suman 3 a la variable nX. Haciendo que el cuadrado se mueva 3 píxeles a la derecha.
    • Si se pulsa la tecla «fecha izquierda», if( keyCode == LEFT), se restan 3 a la variable nX. Haciendo que el cuadrado se mueva 3 píxeles a la izquierda.
  3. Limita los movimientos del cuadrado

    En este paso, emplearás el condicional if, para limitar los movimientos de Newton en el eje X haciendo que esté siempre dentro de la ventana del programa. Es decir, tendrá que ser mayor que 0 y menor que la anchura de la ventana (width).

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-3

    Resultado

    En este caso, el resultado es casi el mismo, con la excepción de que el cuadrado ya no saldrá fuera de la ventana de programa.

    Cómo funciona

    • Al final de la función keyPressed(), hay dos nuevas sentencias if:
      • Si la variable nX es menor de 0, if( nX<0 ), nX se pone a 0. Haciendo así, que el cuadrado no pueda pasar el límite izquierdo.
      • Si la variable nX es mayor que «width – 20», if( nX>width-20 ), nX se pone a width-20. Haciendo que el cuadrado no supere el límite derecho. Se comprueba si nX es mayor que «width-20» en vez de mayor que width para asegurar que el cuadrado completo se ve, ya que su tamaño es de 20 píxeles de ancho.
  4. Manzanas que caen

    En este paso, modificarás el programa para hacer que la manzana (círculo) caiga de lo alto de la pantalla (cielo). Para esto, crearás una variable que almacene la coordenada Y del círculo y, la incrementarás hasta que la manzana toque el suelo, es decir, la parte baja de la ventana del programa.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-4

    Resultado

    Los círculos, o las manzanas, caen del cielo.

    Cómo funciona

    • Se declara la variable aY, tipo int, para almacenar la posición del círculo (manzana) en el eje Y y se inicializa a 0.
    • Cada vez que la función draw() se ejecuta, se suma 1 a la variable aY, aY=aY+1, haciendo que el círculo esté un píxel más cerca del suelo.
    • Una sentencia if comprueba si la variable aY es mayor que height, if( aY>height ). Si lo es, significa que el círculo ha alcanzado la parte baja de la ventana de programa, y la variable se pone nuevo a 0.
  5. Un poco de azar

    Hasta ahora, las manzanas siempre salen de la misma posición en lo alto de la pantalla, esto es bastante predecible. En este paso, vas a generar un número aleatorio para cambiar la X de origen y que cada vez salgan de un sitio distinto.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-5

    Resultado

    Con este cambio en el programa, podrás ver que las manzanas salen desde cualquier punto en lo alto de la pantalla.

    Comandos

    • random(max): Genera un número aleatorio entre 0 y max-1. También puedes usar random(min,max) para generar un número aleatorio entre min y max-1.

    Cómo funciona

    • Se declara aX, una variable tipo int, para almacenar el valor de la posición X de los circulos (manzanas) y se inicializa a 15. Ten en cuenta que la coordenada habrá que cambiarla solo cuando la manzana llegue al suelo, si no cambiará aleatoriamente durante su caída.
    • Cuando el círculo alcanza la parte baja de la ventana (suelo), if( aY>height), se fija una nueva coordenada X. Un número aleatorio entre 0 y width-20, aX = int( random( width-20 ) ).
    • Se dibuja el círculo utilizando aX cómo coordenada X, ellipse( aX, aY, 20, 20).
  6. Detección de colisión

    La acción de detectar que dos objetos se chocan en la pantalla se llama detección de colisión. En este paso, vas a detectar si la manzana choca con la cabeza de Newton empleando una sentencia if. Al detectar colisión, se cambia el color del cuadrado y del círculo a rojo.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-6

    Resultado

    Cuando las manzanas (círculos) colisionan con el cuadrado (Newton) ambos se vuelven rojos.

    Comandos

    • if(test1 && test2){ statements }: Esto se utiliza para realizar varias comprobaciones en un único if(). En este ejemplo, comprobamos si aY+10 > nY y si aY-10 < nY+20. Si estas dos comprobaciones son ciertas simultáneamente, se ejecuta el código entre llaves.

    Cómo funciona

    • Se declara la variable nY, tipo int, para almacenar la coordenada Y de la posición del cuadrado (Newton) y se inicializa a 0. Esta variable facilita la comprobación de las colisiones.
    • En la función setup(), se asigna a la variable nY el valor width-20. Esto se tiene que hacer en la función setup() después de ajustar el tamaño de la ventana. En caso contrario, width no tomará el valor correcto.
    • El color de relleno se fija a blanco, fill(255), así se puede cambiar cuando se detecta una colisión.
    • La detección de colisión se realiza con dos sentencias if, una dentro de otra:
      • La primera, comprueba si el circulo se encuentra a la misma altura que el cuadrado, if( aY+10 > nY && aY-10 < nY+20). Es decir, si la zona inferior del círculo (aY+10) está por debajo de la superior del cuadrado (nY), y la superior del círculo (aY-10) está por encima de la inferior del cuadrado (nY+20). Si esta condición es cierta, se comprueba la segunda.
      • La segunda, comprueba si el círculo se encuentra en la misma posición X que el cuadrado.

    Además, si activas las siguientes líneas en el programa. Verás una serie de líneas en la pantalla enmarcando el movimiento de los objetos. Puedes emplearlas para ver cómo funciona la detección de colisión.

    // lines of code to understand how collision works
    // erase the comment in order to see the code
    line(0,aY-10,width,aY-10);
    line(aX-10,0,aX-10,height);
    line(0,aY+10,width,aY+10);
    line(aX+10,0,aX+10,height);

  7. Más rápido

    Para hacer el juego más interesante, en este paso harás que las manzanas caigan más rápido.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-7

    Resultado

    Las manzanas caen más rápido.

    Cómo funciona

    • Para preparar el siguiente paso, la variable aY se hace de tipo float en lugar de tipo int>/code>.
    • Se declara la variable aV, tipo float, para almacenar el valor 3. Esto es la velocidad de la manzana.
    • En la función draw(), la posición Y de la manzana, se fija incrementando la variable aY con la velocidad, aV.
  8. A Newton le gusta la gravedad, dale más

    En este paso, modificarás la caída de las manzanas para que responda a la aceleración de la gravedad. De este modo, las manzanas irán cada vez más rápido cuanto más cerca estén del suelo.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-8

    Resultado

    Las manzanas caen dependiendo de la aceleración y la gravedad.

    Cómo funciona

    • Cuando se declara la variable de la velocidad, aV, se le asigna el valor 0.
    • Se declara una variable, aA, tipo float, para almacenar un valor de aceleración de 0.05 (en el mundo real esto es 0.98, pero poner ese valor haría muy difícil el juego.)
    • En la función draw(), la velocidad de la manzana se configura incrementando aV con aA. Esto aumenta la velocidad cada vez que la función draw() se ejecuta.
    • La posición Y de la manzana, se fija incrementando la variable aY con aV. Esto hace que la manzana se mueva distancias más grandes cada vez que la función draw() se ejecuta.
    • Cuando se lanza una nueva manzana, esto se hace en la sentencia if donde se comprueba si la variable aY es mayor que height, la velocidad se fija 0.
  9. Cuenta los puntos

    En este paso, implementarás un contador que cuente cuántas manzanas golpearon a Newton.

    Nota: como empiezas a tener muchas variables en tu programa, es recomendable añadir comentarios para recordar qué hace cada una.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-9

    Resultado

    La cantidad de manzanas que golpeen la cabeza de Newton se contarán y se mostrarán en la ventana del programa.

    Comandos

    • text( text, x, y ): escribe un texto (text) en la pantalla en las coordenadas x e y.

    Cómo funciona

    • Se declara la variable, p, tipo int para almacenar los puntos.
    • En la sentencia if para la detección de colisión, una vez que el color de relleno se fija a rojo, la variable p se incrementa en 1.
    • En las últimas líneas de la función draw(), se fija el color de relleno a negro.
    • Se sitúa un texto en las coordenadas ( 3*width/4, 20). El texto dice “Hits: “ y el valor de la variable p. Ten en cuenta que «hits» es «golpes» en español.
  10. Uoops, error

    Te habrás dado cuenta que tu programa ahora mismo está contabilizando puntos de más. Cada vez que la manzana cae sobre la cabeza de Newton, cuando el círculo toca el cuadrado, tu contador sube más o menos 5 puntos. Esto se debe a que el contador continúa contando hasta que la mazana se solapa con Newton por completo.

    Para corregir esto, crearás una variable de tipo boolean (una variable que puede ser verdadero (true) o falso (false)) para decirle al programa si contar puntos o no.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-10

    Resultado

    El contador ha cambiado, ahora solo cuenta una colisión cada vez.

    Comandos

    • if( boolean ){ statements }: Comprueba si una variable tipo boolean es true, si lo es ejecuta el código entre llaves statements. Puedes también comprobar si es false escribiendo if( !boolean ).

    Cómo funciona

    • Se declara la variable pCount, tipo boolean. Los puntos solo se cuentan cuando esta variable es true.
    • Justo después de fijar la velocidad a 0, en la sentencia if que comprueba si la variable aY es mayor que height, la variable pCount se pone a true.
    • Cuando se detecta una colisión, se incrementa en 1 la variable p, siempre y cuando pCount valga true.
    • A continuación, pCount se pone a false.
    • Cuando se lanza una nueva manzana, la variable pCount se pone de nuevo a true.
  11. Y el tiempo empieza

    El objetivo del juego es recibir tantas manzanas en la cabeza de Newton como sea posible en medio minuto. En este paso, crearás un temporizador de cuenta atrás y lo mostrarás en la ventana del programa.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-11

    Resultado

    Verás el temporizador en la ventana del programa.

    Comandos

    • long: Este es un tipo de datos para números enteros muy grandes. Es conveniente usarlos cuando manejamos variables temporales, porque estos datos pueden ser muy grandes. ¿Recuerdas que una variables es cómo un contenedor de datos? Bien, se puede decir que long es un contenedor más grande que int. Un int se queda sin espacio antes que un long.
    • noLoop(): Detiene la ejecución continua de la función draw. Para volver a ejecutar el programa tendrás que llamar a loop().
    • millis(): Esta función devuelve el tiempo en milisegundos que ha pasado desde la última vez que se llamó. Si es la primera vez que la llamas, entonces desde que comenzó el programa.

    Cómo funciona

    • Se declara la variable, t, tipo long para almacenar el tiempo.
    • En la función setup(), se asigna a la variable t el valor que devuelve millis(). Como el valor a t se asigna al final de setup(), este valor será próximo a 0, pero aún más próximo a cuando el juego comienza realmente.
    • En la función draw(), una vez dibujados el cuadrado y el círculo, se declara la variable timer tipo float.
    • Se asigna a timer el valor (millis()-t) / 1000. Al dividirlo entre 1000, esta variable tendrá un valor en segundos en lugar de en milisegundos.
    • Si la variable timer es igual o mayor que 30, han pasado 30 segundos y entonces se llama a la función noLoop() la cual detendrá el programa.
    • Se muestra un texto en las coordenadas (10, 20). El texto dice: “Time: “ y el valor 30 – t. Es decir, se muestra la cuenta atrás. Ten en cuenta que «time» es «tiempo» en español.
  12.  imágenes al juego

    En el último paso, añadirás imágenes (tipo PNG) para el fondo las manzanas y Newton. Las puedes crear tú, buscarlas en Internet, o usar las que te pasamos.

    Nota: Es importante que las imágenes sean de tipo PNG si quieres que haya transparencia entre las imágenes y el fondo. Ten en cuenta que, al cambiar las formas por imágenes, las proporciones también cambian, por lo que tendrás que hacer encajar esos valores en la parte del programa dedicado a la detección de colisiones.

    Código: source: http://verkstad.cc/urler/ctc-g-b1-p-3-12

    Resultado

    Como ves, ahora los círculo son manzanas, el cuadrado es Newton, y en el fondo hay un árbol.

    Para cargar las imágenes utilizamos el mismo método que en los proyectos anteriores, utilizando arrays. En lugar de cambiar el color de las formas cuando una colisión sea detectada, utilizamos el boolean pCount para decidir qué imagen de Newton mostrar.

    Cómo funciona

    • Se declara el array imFiles[], tipo String, para almacenar los nombres de los archivos de las imagenes que se van a utilizar.
    • Se declara el array im[], tipo tipo PImage, para almacenar las imágenes que se van a utilizar.
    • En la función setup(), se utiliza un bucle for para recorrer los nombres de los archivos de las imágenes del array imFiles[], y cargar las mismas en el array im[].
    • im[0] contiene la imagen de fondo y se mostrará ajustada al tamaño de la ventana, esto se hace al empezar la función draw().
    • im[1] contiene la imagen de la manzana y se mostrará después de la detección de colisión.
    • im[2] y im[3] contienen las imágenes de Newton, la primera es Newton normal y la segunda es Newton después de ser golpeado en la cabeza. La variable pCount, tipo boolean se utiliza para decidir qué imagen se mostrará.
    • Si pCount es true, significa que el programa está listo para contar los puntos si una colisión es detectada, y se muestra la imagen de Newton normal,(im[2]).
    • Si pCount no es true, significa que se detecta una colisión y que suma un punto, entonces se muestra la imagen de Newton golpeado (im[3]).
    • En las sentencias if que comprueban la colisión, los valores se han modificado para encajar los tamaños en las imágenes en vez de las formas utilizadas anteriormente.

¡SIGUE EXPERIMENTANDO!

Para mejorar este juego puedes hacer varias cosas:

  • Imágenes personalizadas: Crea tus propias imágenes.
  • Pantalla de inicio: Crea una pantalla de inicio y que se pase al juego una vez se presione un botón.
  • Pantalla final: Crea una pantalla que muestre el resultado una vez se haya terminado el tiempo.
  • Reinicio: Haz posible reiniciar el juego cuando el tiempo haya terminado. No te olvides de reiniciar todas las variables necesarias.
  • Modifica los movimientos: Haz que la manzana se mueva modificando la aceleración en lugar de la velocidad.