Transformaciones

 "El tiempo siempre es un elemento inquietante, un reto para cualquier jugador o jugadora".

SINCRONIZACION

El ZX Spectrum repite un ciclo 50 veces por segundo. EngineZX gasta casi dos ciclos para hacer todo su trabajo, ejecutar sonidos, leer periféricos y si le sobra tiempo, espera al siguiente pulso para completar un "frame" del juego. Cada pulso del ZX Spectrum puede leerse en la variable CLOCK.

TIMER

El código siguiente está basado en el archivo MainLoopClock.AGD que se incluye en el paquete de instalación MPAGD, lo encontrarás en la carpeta AGDScrips.

Abrimos el editor MPAGD. Abrimos el proyecto Pacman. Selecciona la opción "Main loop 1" del menú "Events" edita el script para que quede así:

EVENT MAINLOOP1

; CRONOMETRO

LET A = CLOCK
SUBTRACT O FROM A
IF A >= 50
    ADD 50 TO O    ; variable O (letra o) es última lectura de CLOCK.
    ADD 1 TO M    ; TIMER MODOS
ENDIF

Guarda el script, cierra el editor de textos y guarda el proyecto.

Lo que hace el cronómetro es contar un segundo cada vez que la diferencia entre CLOCK y la última lectura de CLOCK sea de 50 ciclos.

MODOS

"El primer y el segundo período de persecución duran 20 segundos cada uno. ¡El tercer período de persecución es de 20 segundos en el nivel uno, pero luego aumenta a 1.033 segundos para los niveles dos a cuatro, y 1.037 segundos para todos los niveles más allá de más de 17 minutos! Si los fantasmas entran en modo asustado, el temporizador de dispersión / persecución se detiene. Cuando se agota el tiempo, regresan al modo en que estaban antes de asustarse y se reanuda el temporizador de dispersión / persecución".

Dosier fantasma.
 
Recordemos que para proteger las "píldoras energizantes" y atrapar a Pac-man, los fantasmas alternan los modos de dispersión (despliegue a cuadrantes) y persecución.

Despliegue o dispersión en cuadrantes.

Vamos a usar la variable M para gestionar esto. En las centenas codificamos el modo y dejamos el resto para contar segundos. Si M < 100 estamos en modo dispersión. Si 100 =< M < 200 estamos en modo persecución. Cuando Pac-man "tiene el poder" M >= 200 (fantasma Asustado). Genial.

CAMBIO DE SUERTE

Desde que hemos introducido las variables D y M podemos cambiar muchas cosas.
La variable D representa "el poder" de Pac-man, si D cambia significa que Pac-man acaba de comer un "píldora de poder".
La variable M gestiona los periodos entre modos.
Vamos a "tocar" en distintos Eventos del programa para que todo funcione de la manera siguiente:

TRANSFORMACION EVENT SPRITETYPE4

Introduciremos un mecanismo al dentro del script del fantasma tipo 4:

IF M >= 200         ; PACMAN TIENE EL PODER
    IF D > SETTINGB     ; BOLA NUEVA
LET TYPE = 3     ; transforma a TIPO "ASUSTADO"
LET IMAGE = 5
LET FRAME = 0
    ENDIF
ENDIF

Si ocurre que Pac-man come un NUEVA "bola de poder" el fantasma se transforma al tipo asustado (tipo 3) con otra forma y otro color.

EVENT SPRITETYPE4

Selecciona la opción "Sprite type 4" del menú "Events" edita el script para que quede así:

EVENT SPRITETYPE4

; FANTASMAS

SPRITEINK SETTINGA        ; Soy mi color

IF M >= 200         ; PACMAN TIENE EL PODER
    IF D > SETTINGB     ; BOLA NUEVA
LET TYPE = 3     ; transforma a TIPO "ASUSTADO"
LET IMAGE = 5
LET FRAME = 0
    ENDIF
ENDIF

; define el objetivo.

IF SETTINGA = 2    ; BLINKY
    LET T = X            ; Revelo X para Inky
    LET U = Y            ; Revelo y para Inky

    IF M < 100            ; modo despliegue
LET Q = 160     ; segundo cuadrante.
LET R = 16
    ELSE                  ; modo perseguir
LET Q = V     ; TARJET
LET R = W
    ENDIF
ENDIF

IF SETTINGA = 3    ; PINKY
    IF M < 100            ; modo despliegue
LET Q = 16            ; primer cuadrante
LET R = 16
    ELSE                  ; modo perseguir
        LET Q = V            ; X TRAJET
        LET R = W            ; Y TRAJET

        IF I = RIGHT        ; si Pac-man mira a la derecha
    ADD 32 TO Q        ; apunta 4 celdas por delante
        ELSE
    IF I = LEFT        ; lo mismo para izquierda
                SUBTRACT 32 TO Q
    ELSE
        IF I = UP
    SUBTRACT 32 TO R
        ELSE
    ADD 32 TO R
        ENDIF
    ENDIF
        ENDIF
    ENDIF
ENDIF

IF SETTINGA = 5    ; INKY
    IF M < 100            ; modo dispersión
LET Q = 160            ; cuarto cuadrante
LET R = 120
    ELSE         ; modo persecución
LET Q = V     ; X TRAJET
LET R = W     ; Y TRAJET

IF I = RIGHT
    ADD 16 TO Q
ELSE
    IF I = LEFT
SUBTRACT 16 TO Q
            ELSE
IF I = UP
    SUBTRACT 16 TO R
ELSE
            ADD 16 TO R
ENDIF
            ENDIF
ENDIF

MULTIPLY Q BY 2 ; INTERPOLAR CON BLINKY
SUBTRACT T TO Q
MULTIPLY R BY 2
SUBTRACT U TO R
    ENDIF
ENDIF

IF SETTINGA = 6    ; Clyde
    IF M < 100            ; despliegue
LET Q = 56          ; tercer cuadrante
LET R = 120
    ELSE           ; persigue
        LET Q = X
        IF X < V            ; asegurar numero positivo. (absoluto).
    SUBTRACT X TO V
    LET Q = V       ; Q = DISTANCIA horizontal con PAC-MAN       
    ADD X TO V ; restaura V
        ELSE
    SUBTRACT V TO Q ; Q = DISTANCIA horizontal con PAC-MAN
        ENDIF

        LET R = Y
        IF Y < W            ; asegurar numero positivo. (absoluto).
            SUBTRACT Y TO W
    LET R = W       ; Q = DISTANCIA horizontal con PAC-MAN 
    ADD Y TO W      ; restaura W
        ELSE
    SUBTRACT W TO R ; R = DISTANCIA vertical con PAC-MAN
        ENDIF

        IF Q < 64    ; si Pac-man está a menos de 4 celdas entonces
    IF R < 64
        LET Q = 56 ; despliegue tercer cuadrante
        LET R = 120
    ENDIF
        ELSE       ; si no, entonces persigue.
            LET Q = V
            LET R = W
        ENDIF
    ENDIF
ENDIF
; movimiento

IF DIRECTION = UP
    ; gira a favor del reloj
    IF CANGOUP
        SPRITEUP
    ELSE
        LET DIRECTION = RIGHT
    ENDIF

    ; PERSIGUE EN UNA BIFURCACION
    IF X > Q
        IF CANGOLEFT
            LET DIRECTION = LEFT
            ANIMATE
        ENDIF
    ELSE
        IF CANGORIGHT
            LET DIRECTION = RIGHT
            ANIMATE
        ENDIF
    ENDIF
ENDIF

IF DIRECTION = DOWN
    ; gira en contra del reloj
    IF CANGODOWN
        SPRITEDOWN
    ELSE
        LET DIRECTION = LEFT
    ENDIF

    ; PERSIGUE EN UNA BIFURCACION
    IF X > Q
        IF CANGOLEFT
            LET DIRECTION = LEFT
            ANIMATE
        ENDIF
    ELSE
        IF CANGORIGHT
            LET DIRECTION = RIGHT
            ANIMATE
        ENDIF
    ENDIF
ENDIF

IF DIRECTION = LEFT
    ; gira a favor del reloj
    IF X <= LEFTEDGE
        LET X = RIGHTEDGE
        EXIT
    ELSE
    IF CANGOLEFT            
            SPRITELEFT
        ELSE
            LET DIRECTION = UP
        ENDIF
    ENDIF

    ; PERSIGUE
    IF Y > R
        IF CANGOUP
            LET DIRECTION = UP
            ANIMATE
        ENDIF
    ELSE
        IF CANGODOWN
            LET DIRECTION = DOWN
            ANIMATE
        ENDIF
    ENDIF
ENDIF

IF DIRECTION = RIGHT
    ; gira a favor del reloj
    IF X >= RIGHTEDGE
        LET X = LEFTEDGE
        EXIT
    ELSE
        IF CANGORIGHT
            SPRITERIGHT
        ELSE
            LET DIRECTION = DOWN
        ENDIF
    ENDIF

    ; PERSIGUE
    IF Y > R
        IF CANGOUP
            LET DIRECTION = UP
            ANIMATE
        ENDIF
    ELSE
        IF CANGODOWN
            LET DIRECTION = DOWN
            ANIMATE
        ENDIF
    ENDIF
ENDIF

Guarda el script, cierra el editor de textos y guarda el proyecto.

Hemos introducido también una nueva condición en cada comportamiento de los fantasmas. IF M < 100 ...dispersión... ELSE ...persecución... ENDIF. Esto hace cambiar la suerte de Pac-man, durante unos segundos se librará de la persecución de los fantasmas que parecen dispersarse por el laberinto.

TRANSFORMACION EVENT SPRITETYPE3

Hagamos también cambios en el fantasma tipo 3.

Selecciona la opción "Sprite type 3" del menú "Events", edita el script para que quede así:

EVENT SPRITETYPE3

; MODO MIEDO ASUSTADO

SPRITEINK 1    ; COLOREAMOS

IF M < 100                ; Pac-man pierde el poder
    IF SETTINGB < 16     ; PARPADEO
GETRANDOM 8
LET A = RND
SPRITEINK A
ADD 1 TO SETTINGB
    ELSE
LET TYPE = 4     ; CAMBIA A MODO PERSEGUIR
LET IMAGE = 4
LET FRAME = 0
LET SETTINGB = 0    ; RESET PARPADEO
    ENDIF
ENDIF

; movimiento

GETRANDOM 4    ; GENERAR NUMERO PSEUDOALEATORIO 4=(0,1,2,3)(SEED)
LET A = RND    ; A = DIRECCIONES (0,1,2,3)

IF DIRECTION = UP
    IF CANGOUP
        SPRITEUP
    ELSE                    ; CUANDO SE ENCUENTRA UN OBSTÁCULO
LET DIRECTION = A    ; GENERAR DIRECTION = RND Y VAGAR
    ENDIF
ENDIF

IF DIRECTION = DOWN
    IF CANGODOWN
        SPRITEDOWN
    ELSE
LET DIRECTION = A    ; VAGAR
    ENDIF
ENDIF

IF DIRECTION = LEFT
    IF X <= LEFTEDGE
        LET X = RIGHTEDGE    ; TUNEL
EXIT
    ELSE
    IF CANGOLEFT
            SPRITELEFT
ELSE
    LET DIRECTION = A ; VAGAR
ENDIF
    ENDIF
ENDIF

IF DIRECTION = RIGHT
    IF X >= RIGHTEDGE
LET X = LEFTEDGE        ; TUNEL
EXIT
    ELSE
IF CANGORIGHT
    SPRITERIGHT
ELSE
    LET DIRECTION = A ; VAGAR
ENDIF
    ENDIF
ENDIF

Guarda el script, cierra el editor de textos y guarda el proyecto.

"Modo Asustado : los fantasmas entran en modo asustado cuando Pac-Man come uno de los cuatro energizadores ubicados en los rincones más alejados del laberinto. Durante los primeros niveles, los fantasmas se volverán azul oscuro (lo que significa que son vulnerables) y deambularán sin rumbo por el laberinto durante unos segundos. Parpadearan momentos antes de volver a su modo de comportamiento anterior".

IF M < 100                ; Pac-man pierde el poder
    IF SETTINGB < 16     ; PARPADEO
GETRANDOM 8
LET A = RND
SPRITEINK A
ADD 1 TO SETTINGB
    ELSE
LET TYPE = 4     ; CAMBIA A MODO PERSEGUIR
LET IMAGE = 4
LET FRAME = 0
LET SETTINGB = 0    ; RESET PARPADEO
    ENDIF
ENDIF

Este código que hemos insertado al principio del EVENT SPRITETYPE3 hace su trabajo. Transforma nuestro fantasma asustado en Perseguidor en el caso de que Pac-man pierda su poder. Antes de hacer esto, el fantasma parpadea 16 veces con un color aleatorio.

Enhorabuena. Por si no lo sabes, el script EVENT SPRITETYPE3 está completo al 100%.

EVENT INITSPRITE

Queda gestionar la variable D. Para que el fantasma detecte una "BOLA DE PODER NUEVA" le tenemos que gravar en su memoria la "última bola de poder" que Pac-man come. Esto lo hacemos en el script EVENT INITSPRITE. Edítalo para que quede así:

EVENT INITSPRITE

; aparecer fantasmal

IF TYPE = 4                   ; si el Sprite es Perseguidor
    REPEAT A                  ; repite para A.
        READ SETTINGA         ; lee el color y resérvalo en SETTINGA
LET SETTINGB = D      ; reserva "última bola de poder" en SETTINGB
    ENDREPEAT
    ADD 1 TO A                ; pasamos al siguiente fantasma
    IF A = 5
        LET A = 1             ; si aparecieron 4, reinicia A. 
    ENDIF
ENDIF

LET FRAME = 0                 ; asegura fotograma = 0.

DATA 2, 3, 5, 6               ; RED, MAGENTA, CYAN, YELLOW

Guarda el script, cierra el editor de textos y guarda el proyecto.

Reserva la "última bola de poder" en SETTINGB para que los fantasmas que reaparecen en la "Guarida Fantasmal" no pasen a modo asustado hasta que Pac-man se coma una "nueva bola de poder".

MAIN LOOP 1

He dejado para el final el algoritmo que alterna los modos según el "dosier fantasma" mencionado al principio.

Vuelve a selecciona la opción "Main loop 1" del menú "Events" edita el script para que quede así:

EVENT MAINLOOP1

; CRONOMETRO

LET A = CLOCK
SUBTRACT O FROM A
IF A >= 50
    ADD 50 TO O    ; variable O (letra o) es última lectura de CLOCK.
    ADD 1 TO M    ; TIMER MODOS
ENDIF

; Gestor de modos

IF M < 100            ; DISPERSION
    IF N > 128           ; finalizando el laberinto (N = BOLAS)
        IF M > 1            ; agotamos periodo de solo un segundo
            LET M = 100        ; y cambio a persecución.
ENDIF
    ELSE                 ; al comienzo del laberinto
        IF M > 5            ; agotamos periodo de 5 segundos
            LET M = 100        ; y después persigue.
        ENDIF
    ENDIF
ELSE
    IF M < 200          ; PERSECUCION
        IF M > 120          ; agotamos periodo de 20 segundos
            LET M = 0          ; y otra vez dispersión.
ENDIF
    ELSE     ; Pac-man "tiene el poder" ASUSTADO
        LET A = 210         ; periodo inicial de 10 segundos.
        SUBTRACT P TO A     ; resta un segundo por nivel (210 - P).
        IF P >= 20          ; a partir del nivel 20
    LET M = 0          ; ya no tienen miedo
        ELSE
    IF M > A        ; agotamos periodo
                LET M = 0      ; volvemos a dispersión.
            ENDIF
        ENDIF
    ENDIF
ENDIF

El programa "gestor de modos" comprueba el modo 000 DISPERSION, 100 PERSECUCION o 200 ASUSTADO. Agota los periodos de 5, 20, 10 segundos que correspondan. Aplica la dificultad de nivel: en el final del laberinto (N > 128) los fantasmas solo se dispersan un segundo, en los niveles superiores a 20 (P >= 20) los fantasmas ya no se asustan y cada nivel que completamos resta un segundo al periodo de dispersión (210 - P).

"Tenemos el segundo acto, le hemos puesto las cosas difíciles a nuestro protagonista, le hemos dado un poder para decidir el futuro desenlace de esta  historia".

EVENT GAMEINIT

Vamos a documentar las dos variables globales que hemos incorporado. Selecciona la opción "Game initialisation" del menú "Events", edita las siguientes variables:

LET O = 0    ; CRONOMETRO
LET P = 1    ; PANTALLAS 1-99, NIVELES
LET M = 0    ; MODO "DISPERSION/PERSECUCION", "ASUSTADO" + TIMER.
LET D = 0    ; CONTADOR PILDORAS PODER

Introducimos por primera vez un valor inicial P = 1.
EngineZX inicia su trabajo con todas las variables a cero. Hemos duplicado el trabajo para documentar las variables. Puedes perfectamente borrar todas las que tengan valor 0 y el juego no se verá afectado.

Guarda el texto, cierra el editor, guarda el proyecto. Buen trabajo.

"Reúne al grupo. Comunica a todo el mundo que hemos cumplido con gran parte del proyecto, estamos a punto de pasar al tercer acto".

La guarida fantasma.

Comentarios

Entradas populares de este blog

El laberinto