Curso de Juegos (7)


Curso “Programación de Juegos”

Curso Gratuito con codigo fuente.
Entrega 7. Juego completo "El minero"


Juego “El Minero”
 

Ahora vamos a empezar a aplicar lo que aprendimos en las notas anteriores para armar un pequeño y simple programa, en el que vamos a controlar a un “minerito” que excava en la montaña buscando oro y diamantes.


Pero la tarea de nuestro minero no es fácil ni está exenta de peligros: debe excavar en la montaña creando túneles para poder llegar a los tesoros y en su camino puede toparse con paredes de roca sólida. Al mismo tiempo la montaña esconde depósitos de dinamita explosiva, que si son movidas por el minero explotan y le restan vida.


A medida que el minero recoge oro y diamantes, se incrementa un contador de puntos. Si llega a los depósitos de dinamita, hay una explosión (con un efecto mínimo) y se restan puntos de su vida.



En esta ocasión no están grabados los records ni los nombres de los concursantes. Sería algo simple de hacer, pero como quiero enfocarme en el desarrollo de las rutinas del juego, no las incluí (por ahora).


El juego tiene  la misma estructura que los anteriores:

1) Inicialización de variables, declaraciones de subrutinas y funciones
2) Dibujo de pantalla
3) Bucle de ejecución con llamadas para capturar los eventos del programa

Empecemos:

La estructuras GetColision%() y Dibuja.Pantalla () ya fueron tratadas en las notas anteriores y siguen vigentes cumpliendo las mismas funciones.

La única diferencia ahora es que la función GetColision%() nos informa sobre el tipo de colisión que tiene el minero.

En los programas anteriores simplemente nos interesaba saber que el cursos chocaba con algo, ahora nos interesa saber contra qué choca el minero:
 
  •  si choca contra la roca = no puede atravesarla
  • si es arena = puede excavarla
  • si es dinamita = se debe generar una explosión (y además pierde puntos)
  • si es oro = suma una cierta cantidad de puntos
  • si es diamante = suma otra cantidad de puntos  

Esto lo resolvemos haciendo que la función GetColision%() detecte la colisión y nos devuelva un número especial para cada colisión generada.


¿Se pone interesante, verdad?

Para cuando hay que sumar puntos, nos ayuda una subrutina nueva: Asigna.Puntos (TipoColision%). Esta subrutina trabaja en la asignación (suma o resta) de puntos, de acuerdo a la colisión. Además cumple una función secundaria pero no menos importante: si la colisión es con dinamita, genera el efecto de la explosión (muy simple, por supuesto)

Todo está trabajado en gamas de grises. No he implementado color para concentrar su atención en el desarrollo.

Están las variables usuales que implementamos enteriormente: 


INTEGER c, f para controlar las dimensiones generales de la pantalla y usadas por el sistema de control de movimientos generales que evita que nos salgamos de pantalla.



STRING KeyPress para detectar nuestrto teclado (aún no hemos implementado mouse)

INTEGER FlagColision que es un flag que alerta sobre una colisión detectada

STRING Screen$(4 TO 20) para dibujar la pantalla con sus detalles
INTEGER Colision%  para detectar una colision

Han aparecido nuevas variables:

INTEGER Puntos para sumar o restar puntos a la labor de nuestro minero
INTEGER Tiempo para darle emoción al trabajo. Asigna un tiempo límite al trabajo de nuestro  minero (para ver como se comporta bajo “presión”)
INTEGER Objetos lleva la cuenta de los objetos encontrados por el minero (en este juego hay 17 objetos disponibles entre pepitas de oro y diamantes)

Hasta el bucle DO/LOOP todo es claro para el programador de juegos en que se ha convertido (¿verdad?) o por lo menos… así debería ser… La única diferencia es que la pantalla ahora tiene un tipo de dibujo más creativo y hemos asignado un dibujo (carácter ASCII) diferente a cada objeto que hay en pantalla. Cuando se produzca el evento de colisión, la rutina detectora de la colisión, nos informará contra qué chocó nuestro minero y eso hara que el programa se comporte de diferentes modos:

  • si choca contra roca le impedirá perforarla (probablemente se le rompa el martillo o el pico que use), pero lo cierto es que se impedirá el movimiento del minero
  • si choca contra arena…. Simplemente el programa le permitirá pasar dejando un hueco porque nuestro minero va creando un tunel de extracción de minerales preciosos…
  •  si choca contra una pepita de oro o un diamante, incrementará su fortuna
  • si encuentra un cartucho de dinamita mientras va picando con su herramienta… volará el peluquín de nuestro amigo (no le matará para no ser trágicos)… pero perderá parte de la fortuna encontrada 

¿Cómo se logra ese comportamiento? Pues a través de ciertas rutinas implementadas en cada detección de tecla. Veamos un ejemplo (usted puede descifrar los otros)



Dentro del DO/LOOP está la rutina que detecta la tecla presionada:

      KeyPress = UCASE$(INKEY$)


La variable KeyPress es analizada por los IF siguientes (Estructura If – elseif –elseif, etc)

Analicemos el evento de oprimir la tecla CURSOR UP:

      IF KeyPress = CHR$(0) + CHR$(72) AND f > MnFila THEN
               ' si el jugador presionó cursor arriba y no se ha salido del límite respectivo de pantalla
               ' recuerde que la comparación [ AND f > MnFila ] analiza si el movimiento es válido y
               ' no ha superado el límite de pantalla. En caso de que el movimiento salga de pantalla
               'es ignorado por el programa y el minero no se mueve una décima de centímetro

               Colision% = GetColision%(f - 1, c)
               ' Si el movimiento es válido, se verifica si hay una colisión.
               'Para eso tenemos estas variables, que son retornadas por GetColision%
               '    CONST Nada = 0         'no ha colisionado con nada
               '    CONST Roca = 1         'colision con roca (impasable)
               '    CONST Arena = 2        'colision con arena (puede atravesarla)
               '    CONST Oro = 3          'encontro oro (suma puntos)
               '    CONST Diamante = 4     'encontro un diamante (suma puntos)
               '    CONST Dinamita = 5     'encntro dinamita escondida (resta puntos)

                 SELECT CASE Colision% 'dependiendo de GetColision% el programa toma decisiones:
                    CASE No, Arena, Oro, Diamante, Dinamita
                     'en estos casos se hace el movimiento y hay que cambiar la posición del minero en
                     'la pantalla, lo que se hace borrando primero al minero con estas dos instrucciones
                       LOCATE f, c
                       PRINT " "
                     'luego se mueve su posición una linea hacia arriba en la pantalla
                       f = f - 1
                    CASE Roca
                   ' el el caso de que haya colisionado con una roca…no hay movimiento! Nuestro                 
                   'minero no tiene herramientas para romper la roca…
                 END SELECT

               'dependiendo también del tipo de colisión esta rutina asignará puntos cuando         
               'corresponda. También los restará si chocó con una dinamita… (cuidado)
                 CALL Asigna.Puntos(Colision%)

               'se reinicializa el flag de colisión para hacer una nueva detección de movimiento
               FlagColision = No

Las otras rutinas para las otras tres teclas de cursor, trabajan de la misma manera.

Al terminar el IF/END nos encontramos con la opción de cortar el juego en cualquier momento al presionar ESCAPE

      ELSEIF KeyPress = CHR$(27) THEN EXIT DO 'escape
      END IF

Al salir del IF/END IF no encontramos con la variable de tiempo para ver si superamos el tiempo límite que le hemos dado al minero para cumplir con su tarea:

      Tiempo = Tiempo – 1

Las sentencias que siguen son de “refresco de pantalla” o actualización de datos, sencillas de entender.

Más abajo en el programa, tenemos una sentencia que corta el programa cuando se agota el tiempo programado

      IF Tiempo < 1 THEN EXIT DO     


Analicemos la Rutina Asigna.Puntos (TipoColision%)

    DIM z%, fila%, columna%

     IF TipoColision% = Oro THEN
                ' si el minero encuentra oro suma puntos….(guardados en la variable “Oro”)
                Puntos = Puntos + Oro
                '…y hay un objeto menos para descubrir
                Objetos = Objetos - 1
     ELSEIF TipoColision% = Diamante THEN
                ' si el minero encuentra diamantes suma puntos….(guardados en la variable
                ' “Diamante”)
                Puntos = Puntos + Diamante
                '…y hay un objeto menos para descubrir
                Objetos = Objetos - 1
     ELSEIF TipoColision% = Dinamita THEN
                Puntos = Puntos - Dinamita
                '…si encuentra dinamita, se le resta puntos (pierde vida)

                'y también se genera el efecto de explosion
                FOR z% = 1 TO 100
                   LOCATE f - 1, c - 1: PRINT "***"
                   LOCATE f, c - 1: PRINT "***"
                   LOCATE f + 1, c - 1: PRINT "***"
                   LOCATE f - 1, c - 1: PRINT "   "
                   LOCATE f, c - 1: PRINT "   "
                   LOCATE f + 1, c - 1: PRINT "   "
                NEXT z%

                'finalmente se reescribe la pantalla para evitar la presencia “fantasmal” de objetos
                'que no están en la pantalla (a la vista) pero que permanecen en memoria ram
                'y generarían efectos indeseable (vea las notas 5 y 6 – el “BUG” del programa)
                LOCATE f - 1, c - 1: PRINT MID$(Screen$(f - 1), c - 1, 3)
                LOCATE f, c - 1: PRINT MID$(Screen$(f), c - 1, 3)
                LOCATE f + 1, c - 1: PRINT MID$(Screen$(f + 1), c - 1, 3)

     END IF

  END SUB

Queda el análisis de la función GetColisión%, que ahora esta programada para avisar del tipo de colisión que se hace entre un objeto y nuestro amigo minero:

La estructura SELECT/CASE es la encargada de leer el punto de pantalla en el que se produce el choque. Lo hace extrayendo de la memoria RAM el contenido de la pantalla con la función MID$


                  SELECT CASE MID$(Screen$(fila%), columna%, 1)

Una estructura IF/END IF analiza el carácter ASCII encontrado y determina si es arena, roca, diamante, oro o dinamita…. o si no hay colisión alguna.

                            IF MID$(Screen$(fila%), columna%, 1) = "°" THEN
                                  GetColision% = Arena
                               ELSEIF MID$(Screen$(fila%), columna%, 1) = "­" THEN
                                  GetColision% = Dinamita
                               ELSEIF MID$(Screen$(fila%), columna%, 1) = "Ü" THEN
                                  GetColision% = Oro
                               ELSE
                                  GetColision% = Diamante
                               END IF    


Conclusiones

Si lo analiza un poco, ya hemos abierto la “caja de pandora” y ahora depende de usted mismo.
Con esta misma base de elementos, técnicas y rutinas, usted puede implementar:

1)      Programas de tipo “laberinto” en los cuales se podría incluir la recolección de tesoros. 
2)      Programas de tipo PacMan pero sin enemigos dinámicos. Recuerde que todavía no implementamos enemigos (lo haremos por primera vez en la nota 9) 

3)      Programas de tipo aventura (incluso podría ser conversacional), porque a partir de un plano se pueden además generar más de un nivel (que incluya varios planos o pisos) implmementando adicionalmente variables bidimensionales en donde el primer indice indique el piso: Screen$(piso, fila) y con pequeñas modificaciones podemos hacer que nuestro heroe “salte” de piso a piso al llegar a una posición que tenga una escalera que suba o baje de nivel.

4)      Programas del tipo “calabozos y dragones” simples sin enemigos.

Esto es todo por ahora.

Como puede ver… muy rápidamente se puede crear un juego simple con poquitos conocimientos nuevos.

Todavía hay grandes cantidades de técnicas por ver y analizar. Vamos a encarar (quizá ya en la nota próxima) la creación de enemigos que trabajen con voluntad propia (bots) para darle un poco más de dinámica a estos juegos, que no por ser simples dejan de ser interesantes.

Hasta la proxima entrega.






----------------------------------------------------------------------
Curso Gratuito de Programación de VideoJuegos

  1. Introducción

  2. A quienes va dirigido el curso
  3.Temario del curso / Herramientas
  4.Primer programa (codigo fuente) 
  
  ----------------------------------------------------------------------
Share: