Tutorial de ZX Basic + Fourspriter #17: Esto ya va pareciéndose a un juego

¡Y sólo hemos tardado 17 capítulos! Para seguir, necesitamos un spriteset que contenga la animación de un personaje en las cuatro direcciones, ya que vamos a programar un juego de vista cenital. He reaprovechado este spriteset para ello. Lo reordeno, lo exporto, y lo paso a BASIC… Como ya hemos explicado en anteriores capítulos:

 

Lo primero que haremos será el bucle principal. Aquí hay que llamar a subrutinas que aún no tenemos programadas, pero que haremos enseguida. El bucle principal lo vamos a colocar en feoncio.bas, justo donde teníamos el código de las pruebas. En el bucle principal esperaremos un poco (con halt), llamaremos a una rutina para mover al protagonista, llamaremos a otra rutina que actualizará el gráfico del sprite con el frame de animación correcto, moveremos el sprite a su lugar en la pantalla (acordándonos de usar MAPOFFSETX y MAPOFFSETY), y por último llamaremos a fsp21UpdateSprites para que se vean todos los cambios.

Pero antes tenemos que inicializar algunas cosas. Por lo pronto, necesitamos las variables que representarán la pantalla actual y las coordenadas de nuestro protagonista. Colocamos estas definiciones en engine.bas, al principio, en la zona de variables, donde teníamos nuestro array de comportamiento de tiles:

' Pantalla
Dim nPant as uByte

' Nuestro muñequito
Dim pX, pY, pStep, pFacing as uByte

Usaremos pX y pY como coordenadas, pStep para saber el frame de animación actual (0, 1, 2 o 3) y pFacing como offset al primer frame de cada dirección. Si nos fijamos en nuestro spriteset, pFacing valdrá 0 para abajo, 16 para arriba, 32 para derecha y 48 para izquierda. En efecto, pFacing apunta al primer bloque de el primer frame de animación en cada dirección.

Una vez definido esto, nos volvemos a nuestro feoncio.bas para inicializarlo todo, encender los sprites, y pintar la pantalla:

' Empezar

nPant = 0
pX = 2
pY = 2
pFacing = 0
pStep = 0

' Pintar pantalla

pintaMapa (MAPOFFSETX, MAPOFFSETY, nPant)

' Configurar sprite

fsp21MoveSprite (3, pX, pY)
fsp21DuplicateCoordinatesSprite (3)
fsp21ColourSprite (3, 71, 70, 70, 70)
fsp21ActivateSprite (3)
fsp21InitSprites ()

Todo esto ya lo habíamos hecho antes: llamar a pintaMapa, y luego configurar el sprite número 3. Como veis, no estamos llamando a fsp21SetGfxSprite todavía, ya que eso lo haremos luego, en el bucle principal, según el valor de pStep y pFacing.

Justo después de esto, escribimos nuestro bucle principal, tal y como lo describimos más arriba:

' Bucle principal

While 1
   ' Wait 
   Asm
      halt
      halt
   End Asm

   ' Mover muñeco
   muevePibe ()

   ' Actualizar el frame del sprite
   actualizaFrameProta ()

   ' Mover el sprite
   fsp21MoveSprite (3, MAPOFFSETX + pX, MAPOFFSETY + pY)

   ' Actualizar pantalla
   fsp21UpdateSprites ()
Wend

Ese While 1 inicia un bucle infinito. ZX Basic se quejará y todo al compilar. Pero por ahora nos vale. Luego habrá que modificarlo, porque el bucle del juego tendrá que terminarse, por ejemplo, cuando nos maten del todo.

Como vemos, ahí hay dos funciones que no hemos hecho todavía: muevePibe y actualizaFrameProta. Como hemos dicho, la primera se usará para leer el teclado y mover al protagonista. La segunda, nos servirá para asignarle los gráficos correctos según su frame y orientación.

Necesitamos una tercera función auxiliar que colocaremos en engine.bas:

Sub doStep () 
   pStep = pStep + 1: If pStep = 4 Then pStep = 0: End If
End Sub

Simplemente hace el ciclo de 0 a 3 en pStep. Cada vez que se le llame, avanzará un frame de animación. Es para no repetir código, ya que necesitaremos hacer esto cada vez que avancemos en cada una de las direcciones.

Pasamos pues a la rutina MuevePibe. Empecemos por el principio. Vamos a detectar el teclado exactamente igual que hicimos en el ejemplo anterior. Vamos a ir por pasos para ver qué comprobaciones tendremos que hacer. Sobre todo, vamos a guiarnos por este diagramilla:

Vamos a empezar detectando la pulsación de “O” y moviendo al muñeco a la izquierda. Luego haremos la detección para el resto de las direcciones, que serán muy parecidas.

Lo primero es detectar la tecla “O”. Luego lo que haremos será avanzar un frame la animación y establecer la dirección correcta para el sprite:

   '' Detectar "O": Sexta semifila, bit 1
   If (In (57342) bAnd 2) = 0 Then 
      doStep ()
      pFacing = 48

   End If

Ahora miramos el diagramilla. Nos queremos mover hacia la izquierda. Entonces tendremos que comprobar que las posiciones marcadas en rojo son “traspasables”, ambas las dos. Además, vamos a comprobar que no nos salgamos de la pantalla, o sea, que pX > 0. Si miramos las coordenadas que hay que mirar en el diagramilla, podemos terminar de escribir nuestro IF:

   '' Detectar "O": Sexta semifila, bit 1
   If (In (57342) bAnd 2) = 0 Then 
      doStep ()
      pFacing = 48
      ' Puedo moverme?
      If pX > 0 And getCharBehaviourAt (pX - 1, pY, nPant) < 4 _ 
         And getCharBehaviourAt (pX - 1, pY + 1, nPant) < 4 Then
         pX = pX - 1
      End If
   End If

Como veis, estamos llamando a la función getCharBehaviourAt que escribimos hace poco. Si recordáis, esta función devolvía 0 para traspasable, y 4 para obstáculo. Si se cumple que los dos carácteres que están a la izquierda del muñeco, (pX – 1, pY) y (pX – 1, pY + 1), son traspasables, entonces avanzamos a la izquierda: pX = pX – 1.

De forma análoga, y mirando el diagramilla, podemos escribir las otras tres direcciones. Como véis, lo que cambia es qué tecla se detecta, la comprobación de no salirnos de la pantalla, y el comportamiento de qué caracteres se comprueba. Con esto habremos terminado la rutina muevePibe:

Sub muevePibe () 
    '' Detectar "O": Sexta semifila, bit 1
    If (In (57342) bAnd 2) = 0 Then 
        doStep ()
        pFacing = 48
        ' Puedo moverme?
        If pX > 0 And getCharBehaviourAt (pX - 1, pY, nPant) < 4 _ 
            And getCharBehaviourAt (pX - 1, pY + 1, nPant) < 4 Then
            pX = pX - 1
        End If
    End If
    
    '' Detectar "P": Sexta semifila, bit 0
    If (In (57342) bAnd 1) = 0 Then 
        doStep ()
        pFacing = 32
        ' Puedo moverme?
        If pX < MAPSCREENWIDTH + MAPSCREENWIDTH - TILESIZE _
            And getCharBehaviourAt (pX + 2, pY, nPant) < 4 _
            And getCharBehaviourAt (pX + 2, pY + 1, nPant) < 4 Then
            pX = pX + 1
        End If
    End If
    
    '' Detectar "Q": Tercera semifila, bit 0
    If (In (64510) bAnd 1) = 0 Then
        doStep ()
        pFacing = 16
        ' Puedo moverme?
        If pY > 0 And getCharBehaviourAt (pX, pY - 1, nPant) < 4 _
            And getCharBehaviourAt (pX + 1, pY - 1, nPant) < 4 Then
            pY = pY - 1
        End If
    End If
    
    '' Detectar "A": Segunda semifila, bit 0
    If (In (65022) bAnd 1) = 0 Then
        doStep ()
        pFacing = 0
        ' Puedo moverme?
        If pY < MAPSCREENHEIGHT + MAPSCREENHEIGHT - TILESIZE _ 
            And getCharBehaviourAt (pX, pY + 2, nPant) < 4 _
            And getCharBehaviourAt (pX + 1, pY + 2, nPant) < 4 Then
            pY = pY + 1
        End If
    End If
End Sub

Vemos que en las direcciones abajo y derecha se controla que no nos salgamos de la pantalla por esas direcciones empleando las expresiones MAPSCREENWIDTH + MAPSCREENWIDTH – TILESIZE y MAPSCREENHEIGHT + MAPSCREENHEIGHT – TILESIZE, respectivamente. Estas expresiones representan el máximo valor que pueden tomar las variables pX y pY para no salirnos de la pantalla. Si haces la cuenta, nuestro área de juego es de 12×12 tiles, o sea, 24×24 caracteres, cuyas coordenadas irán de 0 a 23 y de 0 a 23 en los ejes X e Y. Como nuestro sprite ocupa 2×2 tiles, las coordenadas máximas en las que podremos colocarlo serán 22 en X y 22 en Y. MAPSCREENWIDTH + MAPSCREENWIDTH – TILESIZE = 12 + 12 – 2 = 22, y lo mismo para la otra expresión. Podemos coger y escribir un 22 directamente (de hecho, será más rápido), pero estamos escribiendo código genérico. Si luego necesitamos optimizar el juego, es una de las cosas que deberíamos cambiar.

Ahora solo nos queda la rutina para establecer el gráfico correcto según los valores de pStep y pFacing… Nos vale con un sencillo IF. Como tenemos un ciclo de cuatro pasos de animación que emplean 3 gráficos diferentes (1,2,3,2,1,2,3…) nos lo montamos así:

Sub actualizaFrameProta ()
   If pStep = 0 Then
      fsp21SetGfxSprite (3, pFacing, pFacing + 1, pFacing + 2, pFacing + 3)
   ElseIf pStep = 1 Or pStep = 3 Then
      fsp21SetGfxSprite (3, pFacing + 4, pFacing + 5, pFacing + 6, pFacing + 7)
   Else
      fsp21SetGfxSprite (3, pFacing + 8, pFacing + 9, pFacing + 10, pFacing + 11)
   End If
End Sub

Con esto y un bizcocho, tenemos que tener a nuestro muñeco moviéndose por la pantalla respondiendo a las teclas y deteniéndose con los obstáculos.

Pulsa aquí para descargar el paquetito correspondiente a este capítulo. En el próximo, veremos como cambiar de pantalla.

3 Responses to Tutorial de ZX Basic + Fourspriter #17: Esto ya va pareciéndose a un juego

  1. doctor_who dice:

    De aquí a dominar el mundo solo un paso uuuaaHAHAHAH🙂
    Felicidades una semana más🙂

  2. Pingback: SUVLEIR 3.0 (Super Ultra Vector Library Experience Inspire Redux 3.0) « Tetas, Culos y Retroinformática.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: