Como estamos trabajando en un clásico juego de ZX Spectrum, sería un descuido no incluir unos cuantos sonidos nostálgicos del altavoz del Speccy. Aunque podríamos añadir sonidos AY para máquinas de 128K, eso no es realmente algo para principiantes. Así que nos quedaremos con el altavoz y usaremos dos comandos de MPAGD que pueden hacer ruido.
BEEP
El comando BEEP espera un número que controla durante cuánto tiempo suena. Ten en cuenta que no podemos controlar directamente el tono: los BEEP de MPAGD empiezan graves y van subiendo poco a poco durante la duración del BEEP... básicamente suena como un chapoteo. Acepta valores hasta (creo que 125, a partir de ahí empieza a dar la vuelta (así que BEEP 130 suena igual que BEEP 5)
Aquí tienes un trozo de código que puedes probar. Ponlo al final de tu evento Game Initialisation:
LET A = 5 ; store the value 5 in A WHILE A < 255 ; do the following as long as A is less than 255 WAITKEY ; Wait for a key to be pressed AT 10 10 ; start at line 10 column 10 PRINT "BEEP " ; display "BEEP" AT 10 15 DISPLAY TRIPLEDIGITS A ; ...and the current value of A BEEP A ; make the BEEP sound for current value of A ADD 5 TO A ; increase A by 5 and repeat the process ENDWHILE
guarda tu evento y compila el juego:
Como puedes oír, BEEP 5 es poco más que un golpecito, mientras que BEEP 125 es un sonido largo y de chapoteo.
¡Está claro que aquí no tenemos mucho con lo que jugar!
CRASH
El otro sonido que podemos usar es CRASH, que produce un sonido de ruido blanco. Vamos a sustituir los BEEP de nuestro código de arriba por CRASH y a ver cómo suena:
Vale, esto va a dar trabajo.
Ese BEEP 5 corto, el golpecito, podría quedar bien cuando Stinky Dog se mueve. Veamos qué pasa si lo añadimos a su código de movimiento. Abre tu evento PLAYER y busca las dos sentencias que controlan el movimiento a izquierda y derecha. Vamos a meter BEEP 5 en ellas:
IF KEY LEFT ; Is the left key pressed?
LET DIRECTION = LEFT ; if so, remember I am going LEFT
LET IMAGE = 1 ; display the left facing image
IF X <= LEFTEDGE ; are we at the left edge of the screen?
SCREENLEFT ; if so, go to the screen to left on the map
LET X = RIGHTEDGE ; and put me at the right edge of that screen
EXIT ; and stop processing this event
ELSE ; if I'm not at the left edge
IF CANGOLEFT ; is there space to the left of me?
SPRITELEFT ; if so move me left
BEEP 5 ; make a tap sound
ANIMATE ; and animate me
ELSE ; if I can;t go left
DIG LEFT ; dig away any fodderblocks there
ENDIF
ENDIF
ENDIF
IF KEY RIGHT ; Is the right key pressed?
LET DIRECTION = RIGHT ; if so, remember I am going RIGHT
LET IMAGE = 0 ; display the right facing image
IF X >= RIGHTEDGE ; Am I at the right edge of the screen?
SCREENRIGHT ; if so go to the screen to right on the map
LET X = LEFTEDGE ; and put me at the left edge
EXIT ; and stop processing this event
ELSE ; if I'm not at the right edge
IF CANGORIGHT ; is there space to the right of me?
SPRITERIGHT ; if so, move me right
BEEP 5 ; make a tap sound
ANIMATE ; and animate me
ELSE ; if I cant go right
DIG RIGHT ; dig away any fodderblocks there
ENDIF
ENDIF
ENDIFProbémoslo...
Vale, funciona, pero creo que hay un par de cosas que mejorar. Primero, creo que da demasiados golpecitos, nos vendría bien reducir su número. Segundo, los golpecitos continúan cuando Stinky Dog salta a izquierda o derecha.
Ambos problemas se deben a que el comando BEEP está dentro de las sentencias IF KEY LEFT/RIGHT. Pero los dos se pueden resolver.
Primero, veamos cómo reducir el número de golpecitos. Lo conseguiremos introduciendo un temporizador de uso general. Usaremos una variable, A, y escribiremos un poco de código que asegure que la mitad del tiempo A contiene 0 y la otra mitad contiene 1. Después haremos que el BEEP dependa de que A contenga 0.
Como siempre queremos que este temporizador esté funcionando, el mejor sitio para ponerlo es el evento MAIN LOOP 1. MPAGD ejecuta este evento en cada ciclo antes de todos los eventos de nuestros sprites (después ejecuta MAIN LOOP 2.
Abre MAIN LOOP 1, puede que ya contenga algo de código (no te preocupes por él) y añade el código resaltado de abajo:
ADD 1 TO A ; increment A IF A = 2 ; does A contain 2? LET A = 0 ; if so make A contain 0 ENDIF
Vale, ahora en nuestro código del jugador solo tenemos que envolver los BEEP 5 en una condición de que A sea 0, es decir:
IF A = 0 BEEP 5 ENDIF
Así que ahora el sonido de golpecito solo ocurrirá la mitad de las veces (un ciclo sí y otro no)
El segundo problema, que el golpecito suene cuando Stinky Dog está en el aire, también se resuelve fácilmente. Para cada sprite, MPAGD también guarda una variable especial que nos dice si el sprite está 'en el aire' o sobre suelo firme, y se llama AIRBORNE. Como cualquier variable, contiene un valor de 0 a 255. Si es 0, significa que el sprite NO está en el aire. De nuevo, tenemos que envolver nuestros BEEP 5 en una condición que compruebe que Stinky Dog está en el suelo. Y podemos hacerlo dentro de la condición IF A = 0:
IF A = 0 ; if A contains 0
IF AIRBORNE = 0 ; and Stinky Dog is not in the air
BEEP 5 ; make the tap sound
ENDIF
ENDIFTu código de movimiento en el evento Player debería verse ahora así:
IF KEY LEFT ; Is the left key pressed?
LET DIRECTION = LEFT ; if so, remember I am going LEFT
LET IMAGE = 1 ; display the left facing image
IF X <= LEFTEDGE ; are we at the left edge of the screen?
SCREENLEFT ; if so, go to the screen to left on the map
LET X = RIGHTEDGE ; and put me at the right edge of that screen
EXIT ; and stop processing this event
ELSE ; if I'm not at the left edge
IF CANGOLEFT ; is there space to the left of me?
SPRITELEFT ; if so move me left
IF A = 0 ; if A contains 0
IF AIRBORNE = 0 ; and Stinky Dog is not in the air
BEEP 5 ; make a tap sound
ENDIF
ENDIF
ELSE ; if I can't move left
DIG LEFT ; dig any fodder blocks to the left
ENDIF
ENDIF
ENDIF
IF KEY RIGHT ; Is the right key pressed?
LET DIRECTION = RIGHT ; if so, remember I am going RIGHT
LET IMAGE = 0 ; display the right facing image
IF X >= RIGHTEDGE ; Am I at the right edge of the screen?
SCREENRIGHT ; if so go to the screen to right on the map
LET X = LEFTEDGE ; and put me at the left edge
EXIT ; and stop processing this event
ELSE ; if I'm not at the right edge
IF CANGORIGHT ; is there space to the right of me?
SPRITERIGHT ; if so, move me right
IF A = 0 ; if A contains 0
IF AIRBORNE = 0 ; and stinky dog is not in the air
BEEP 5 ; make a tap sound
ENDIF
ENDIF
ANIMATE ; and animate me
ELSE ; if I can't move right
DIG RIGHT ; remove any fodderblcoks on the right
ENDIF
ENDIF
ENDIFHora de probar...
¡Con eso vale!
A continuación quiero probar algo un poco distinto: quiero un sonido especial para cuando maten a Stinky Dog
Lo que podríamos hacer es repetir algunos sonidos en sucesión, quizá usando una variable para controlar el valor del BEEP... Algo así:
LET RND = 5 ; use RND as a temporary variable staring value of 5 REPEAT 20 ; do the following 20 times BEEP RND ; make sound based on current RND DELAY 2 ; a very brief pause ADD 5 TO RND ; increase the BEEP value by 5 ENDREPEAT ;
¿Por qué uso RND como variable? En pocas palabras, las variables son algo precioso en MPAGD, solo tenemos unas cuantas, y si solo necesitamos usar una variable brevemente, suelo usar RND.
Normalmente el valor guardado en RND será el último número aleatorio que haya generado nuestro código si hemos usado el comando RANDOMISE.
Dicho esto, en el código de arriba podrías usar la variable que quieras, pero en mi experiencia, usa tus variables principales de MPAGD (ABC, etc.) para 'variables globales': cosas que necesitas guardar y con las que trabajar a lo largo de todo el juego.
También he puesto un DELAY muy pequeño. DELAY pausará tu juego durante un tiempo que depende del número que pongas después. 2 es tan bajo que probablemente no se note.
Creo que el sonido que genera este código podría ser bueno para cuando maten a Stinky Dog, así que vamos a meterlo en el evento KILL PLAYER...
EVENT KILLPLAYER LET RND = 5 ; use RND as a temporary variable staring value of 5 REPEAT 20 ; do the following 20 times BEEP RND ; make sound based on current RND DELAY 2 ; a very brief pause ADD 5 TO RND ; increase the BEEP value by 5 ENDREPEAT SUBTRACT 1 FROM LIVES ; reduce the number of lives by one COLOUR 66 ; bright red on black AT 0 27 ; line 0 column 27 DISPLAY DOUBLEDIGITS LIVES ; display lives in xx format ZEROBONUS ; remove any accrued fart bonus
Vamos a probarlo...
Volveremos para hacer más sonidos en otra ocasión, pero espero que este tutorial te haya dado una buena idea de lo que se puede conseguir con los sonidos básicos del altavoz del Speccy en MPAGD. También hemos aprendido a usar:
AIRBORNE para comprobar si el jugador está en el aire o no
y hemos creado un temporizador de uso general en el bucle principal. Lo usaremos para otras cosas más adelante.
Por último, también hemos aprendido cómo usar variables temporales cuando necesitamos una variable rápida de usar y tirar, y por qué RND es una buena opción en este caso.
