EL JUEGO
Vuelven los invasores del espacio!!!
En el año 1977 intentaron invadir las ciudades de la tierra, y fracasaron.
Ahora vuelven con un malvado plan: destruir las centrales nucleares para dejar el planeta inhabitable.
Con la ayuda de nuestro tanque debemos evitar que cumplan con su objetivo.
Cada nivel lo componen 30 invasores, y al superarlo aparecerá una central más grande y los invasores deberán recorrer menos distancia para llegar a ella.
Destruye el UFO que aparece por la parte superior para conseguir puntos extras.
EL PROGRAMA
Me he tomado la molestia de repicar el programa en el emulador "EUPHORIC" (MSDOS) con el cual he podido generar el TAP, y he podido listarlo a un fichero de texto con el "ORICUTRON" (Windows).
Fichero TAP:
BLOQUES
He dividido el listado en 14 bloques:
- Declaración de las matrices.
- Control de nuestro tanque.
- Control de nuestro disparo.
- Mover UFO.
- Mover invasor.
- Destruir enemigo ó UFO.
- Perder una vida.
- Pasar Nivel.
- Presentación.
- Mostrar pantalla de juego.
- Cargar gráficos. SPRITES y UDG.
- Inicializar variables y matrices del juego.
- Rutinas varias.
- Bloques de gráficos.
COMO FUNCIONA
Todo el programa ocupa 79 líneas.
A continuación indico el principio de las distintas partes del programa:
10 - Definimos las matrices del juego.
30 – Llamada a rutinas para leer gráficos (3000), mostrar presentación(2000).
100 – Comprobamos si se ha de mover nuestro tanque, mostrándolo en la nueva posición.
130 – Si hay un disparo en pantalla lo movemos, sino miramos si se ha pulsado disparo (RETURN).
170 – Si hay un UFO en pantalla lo movemos, sino decrementamos el contador (W).
200 – Rutina de movimiento de invasores. Se mueve uno distinto en cada pasada. Primero miramos si todavía hay invasores en la posición correspondiente (3 por posición), sino hay, salimos. Si tiene alguna velocidad asignada lo movemos, y sino mediante un número aleatorio decidimos si se ha de empezar a mover. Durante el movimiento cambiamos su animación y miramos si ha llegado a la central nuclear.
250 – Contador del próximo invasor a mover (M).
260 – Si no se han destruido todos los invasores (T) volvemos al REPEAT en 100, y si no quedan seguimos hasta 300.
300 - Código de pasar nivel. Se ejecuta cuando destruimos los 30 invasores. Se incrementa el control de dificultad (C) que indicará la anchura de la central nuclear.
400 – Esta rutina se ejecuta cuando el disparo detecta que ha tocado algo (en 160). Aquí se calcula si se ha tocado un invasor o el UFO y actúa en consecuencia. En 410 se destruye un invasor y en 450 se destruye el UFO.
500 – Rutina que se ejecuta cuando un invasor llega a la central nuclear. Se reproduce un sonido y se borra una vida. Si quedan vidas volvemos a empezar el nivel y sino vamos a la pantalla de presentación después de una pausa.
2000 – Pantalla de presentación del juego.
disparar se guarda el control en la variable (G).
2100 – Borrado de la pantalla de presentación. Mensaje al jugador uno para que esté listo y se dibuja la central nuclear.
2800 – Posiciona y muestra a los invasores y nuestro tanque en pantalla. Reinicia el valor de ciertas variables.
3000 – Cargamos los gráficos desde las líneas DATA a la VRAM. Primero se cargan los SPRITES y después los UDG.
3000 – Cargamos los gráficos desde las líneas DATA a la VRAM. Primero se cargan los SPRITES y después los UDG.
5000 – Rutina para imprimir un número en un marcador. Pasar el valor en (I) y la posición en (N).
5200 – Rutina de borrado de parte de la pantalla, respetando los marcadores superiores y inferiores.
9000 – Datos de los gráficos UDG del juego.
9500 – Datos de los invasores según posición y animación.
EL LISTADO
Código: Seleccionar todo
10 DIM X(10),Y(10),Q(10),S(10),G(5),B$(11,2)
30 GOSUB 3000:GOTO 2000
*** Mover tanque
100 REPEAT
105 K=PEEK(520):IF K=56 THEN 130
110 IF K=169 THEN POKE #26A,3:CLS:END
115 IF K=170 THEN IF H>2 THEN H=H-1:PLOT H,22,"mno "
120 IF K=176 THEN IF H<35 THEN PLOT H,22," mno":H=H+1
*** Control disparo
130 IF D THEN 150
140 IF K=175 THEN D=23:G=H+1 ELSE 170
150 IF SCRN(G,D)=115 THEN PLOT G,D," "
155 IF D=3 THEN D=0:GOTO 170
160 D=D-2:IF SCRN(G,D)<>32 THEN 400 ELSE PLOT G,D,"s"
*** Control UFO
170 IF U=0 THEN W=W-1:IF W THEN 200
180 IF U<35 THEN U=U+1:PLOT U,3," pqr":GOTO 200
185 PLOT U,3," ":U=0:W=200
*** Control Invasores
200 IF Q(M)=0 THEN 250
210 IF S(M) THEN 240 ELSE IF RND(1)<.6 THEN 250
220 S(M)=(INT(RND(1)*2)+1)/2:IF M>5 THEN S(M)=-S(M):GOTO 250 ELSE 250
240 F=X(M):X(M)=F+S(M):PLOT F,Y(M),B$(M,ABS(A)):IF ABS(19-F)<E THEN 500
250 IF M=10 THEN M=1:A=NOT(A) ELSE M=M+1
260 UNTIL T=0
*** Pasar nivel
300 WAIT 300:N=22:GOSUB 5200:IF C<6 THEN C=C+1
310 GOTO 2500
*** ¿Que toca el disparo? (410=Invasor / 450=UFO)
400 IF D=3 THEN 450 ELSE F=(D-5)/2:IF F>5 THEN D=0:GOTO 170
410 I=ABS(G>20):K=F+I*5:PLOT X(K),Y(K),B$(11,I):S(K)=0:Q(K)=Q(K)-1
420 P=P+G(F):T=T-1:PLOT X(K),Y(K)," ":ZAP
430 X(K)=I*37:IF Q(K) THEN PLOT X(K),Y(K),B$(K,0):GOTO 470 ELSE 470
450 U=U+1:PLOT U,3,"z {":WAIT 20:SHOOT:F=INT(RND(1)*3+1)*50:P=P+F
460 PLOT U,3,MID$(STR$(F),2)+" ":WAIT 30:PLOT U,3," ":U=0:W=200
470 D=0:N=4:I=P:GOSUB 5000:GOTO 170
*** Perder vida / Fin partida
500 EXPLODE:FOR F=1 TO 5:INK 0:PAPER 7:WAIT 25
510 INK 7:PAPER 0:WAIT 25:NEXT:IF L=1 THEN 540 ELSE L=L-1
520 A$=MID$(STR$(L),2)+" ":IF L>1 THEN FOR F=2 TO L:A$=A$+"mno":NEXT
530 PLOT 2,24,A$+" ":N=22:GOSUB 5200:GOTO 2500
540 PLOT 15,19,"GAME OVER":WAIT 500:IF R<P THEN R=P
*** Pantalla presentación
2000 CLS:PLOT 2,0,"SCORE<1> HI-SCORE SCORE<2>"
2010 N=4:I=P:GOSUB 5000:N=18:I=R:GOSUB 5000
2030 PLOT 2,24," mnomno":PLOT 29,24,"CREDIT 00"
2040 PLOT 18,5,"PLAY":PLOT 12,7,"NUCLEAR INVADERS"
2050 PLOT 9,11,"*SCORE ADVANCE TABLE*"
2060 PLOT 12,13,"pqr =? MYSTERY":PLOT 13,15,"cd =30 POINTS"
2080 PLOT 13,17,"gh =20 POINTS":PLOT 13,19,"kl =10 POINTS"
2090 IF KEY$<>CHR$(13) THEN 2090
*** Inicio partida: Escenario
2100 N=23:GOSUB 5200:PLOT 13,12,"PLAY PLAYER<1>":P=0:L=3:C=3
2110 FOR F=1 TO 10:PLOT 4,1," ":WAIT 10
2120 PLOT 4,1,"0000":WAIT 10:NEXT:N=23:GOSUB 5200
2130 PLOT 2,24,"3":PLOT 1,23,"uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu"
2500 F=(C+1)*2+2:A$="":B$="":E=(C*2+4)/2
2510 PLOT 18-C,6,LEFT$(D$,F):PLOT 18-C,17,LEFT$(D$,F)
2520 FOR F=1 TO C+1:A$=A$+"vw":B$=B$+"xy":NEXT:A$="t"+A$+"t":B$="t"+B$+"t"
2530 FOR F=7 TO 15 STEP 2:PLOT 18-C,F,A$:PLOT 18-C,F+1,B$:NEXT
*** Inicio partida: Mostrar invasores y tanque
2800 FOR F=1 TO 5:Y(F)=F*2+5:Y(F+5)=Y(F):X(F)=0:X(F+5)=37:NEXT
2810 FOR F=1 TO 10:PLOT X(F),Y(F),B$(F,0):Q(F)=3:NEXT
2820 PLOT 2,22,"mno":H=2:M=1:D=0:U=0:W=200:T=30:A=0:GOTO 100
*** Pantalla Instrucciones, lectura gráficos e inicializar variables
3000 CLS:INK 7:PAPER 0:POKE #BBA3,0:POKE #26A,10
3010 PLOT 12,0,"NUCLEAR INVADERS":PLOT 8,7,"CONTROLS: LEFT = Z"
3011 PLOT 18,8,"RIGHT = X":PLOT 18,9,"FIRE = RETURN"
3015 PLOT 10,16,"*PRESS KEY TO START*":PLOT 9,24,"(C) SCAINET SOFT, 2013"
3020 FOR F=46856 TO 47071:READ D:POKE F,D:NEXT
3030 D$="tttttttttttttttt":G(1)=30:G(2)=20:G(3)=20:G(4)=10:G(5)=10:R=0
3040 FOR F=1 TO 5:READ A$,C$:B$(F,0)=" "+A$:B$(F,1)=" "+C$
3050 B$(F+5,0)=A$+" ":B$(F+5,1)=C$+" ":NEXT:B$(11,0)=" z{":B$(11,1)="z{ "
3060 GET A$:RETURN
*** Rutinas varias (5000=Marcador / 5200=CLS)
5000 PLOT N,1,RIGHT$("000"+MID$(STR$(I),2),4):RETURN
5200 FOR F=3 TO N:PLOT 1,F," ":NEXT
5210 RETURN
*** Gráficos y Tipo de invasores
9000 DATA 1,3,7,13,15,5,8,4,32,48,56,44,60,40,4,8
9005 DATA 1,3,7,13,15,2,5,10,32,48,56,44,60,16,40,20
9010 DATA 8,36,47,59,63,31,8,16,4,9,61,55,63,62,4,2
9015 DATA 8,4,15,27,63,63,40,6,4,8,60,54,63,63,5,24
9020 DATA 3,31,63,57,63,14,25,12,48,62,63,39,63,28,38,12
9025 DATA 3,31,63,57,63,6,13,48,48,62,63,39,63,24,44,3
9030 DATA 0,0,0,15,31,31,31,31,8,28,28,63,63,63,63,63,0,0,0,56,60,60,60,60
9035 DATA 0,0,3,7,13,31,7,2,0,63,63,63,45,63,12,0,0,0,48,56,44,62,56,16
9040 DATA 0,8,8,8,8,8,0,0,47,47,47,0,61,61,61,0,0,0,0,0,0,0,63,0
9050 DATA 3,12,19,16,17,19,17,21,48,12,50,2,34,50,34,42
9055 DATA 22,23,22,18,16,12,3,0,26,58,26,18,2,12,48,0
9060 DATA 2,17,8,4,48,2,9,18,16,34,4,8,3,16,36,18
9500 DATA "cd","ab","gh","ef","gh","ef","ij","kl","ij","kl"
APUNTES FINALES
La principal dificultad del juego ha consistido en conseguir una buena velocidad de ejecución, teniendo en cuenta que el juego original no es especialmente rápido. He utilizado distintas técnicas para conseguirlo. Entre ellas, guardar las distintas animaciones de los invasores según su posición.
Los gráficos del ORIC están compuestos por una rejilla de 6x8, 6 de ancho por 8 de alto. Como ningún invasor ocupa más de 12 pixels, han entrado perfectamente. Para el tanque y el UFO he tenido que usar 3 caracteres. He redefinido las minúsculas para poder listar el programa sin problemas.
La pantalla de presentación es un “duplicado” de la del juego original, excepto por el cambio del nombre del juego. La forma de presentación es distinta ya que aquí se muestra todo de golpe y no letra a letra.
El bucle principal de desarrollo va de la línea 100 hasta la 260, 19 líneas en total. Aquí se controla el tanque, el disparo, el UFO y un invasor. Como el proceso es rápido, todo se mueve de forma bastante fluida. De todas formas, la imposibilidad de usar el ELSE con seguridad, unido a la limitación en la longitud de las líneas ha hecho que este bloque ocupe más que en la versión MSX.
Para detectar si el disparo toca algún enemigo, antes de mostrar el disparo en su nueva posición miro si hay algo, y en caso afirmativo salto a la línea 400. Aquí compruebo por posición vertical si es el UFO, y sino, es un invasor que por posición vertical calculo la fila y por posición horizontal la columna.
En esta versión muestro una pantalla previa de instrucciones donde indico las teclas de control. Mientras, se van redefiniendo los gráficos e inicializando algunas matrices y variables.
El editor del ORIC es muy parecido al de los ACORN BBC/ELECTRON, pero en lugar de la tecla “COPY []” aquí se usa el “CTRL+A”. La diferencia es que en los ACORN vas viendo lo que vas copiando en el buffer, pero en el ORIC no. Esto hace que sea recomendable hacer un LIST de la línea para asegurarte que los cambios se han introducido bien.
Hay un importante “bug” con el comando ELSE. Entre otras cosas, no identifica bien a que IF va asociado y hace que el programa no lo procese correctamente. Esto hace que algunas líneas se deban dividir en dos o tres para evitarlos.
Respecto a la grabación en cinta, el ORIC-1 suele grabar mal en modo FAST (por defecto) y has de usar el parámetro “,S” para hacerlo en modo SLOW, que es mucho más lento pero seguro. En el ORIC ATMOS no falla la grabación rápida, y el propio ORIC-1 lo carga sin problemas.
Para el tema de sonido, en el que soy un perfecto inútil, después de varias pruebas en las que caía el rendimiento del ORIC más de lo necesario, e optado por usar los sonidos predefinidos que tiene. El ORIC tiene unas buenas prestaciones sonoras pero desde BASIC son algo engorrosas de usar.
Con la tecla “ESC” abandonamos el programa y mediante el POKE #26A,3 activo el cursor y el key click.
Para terminar, todo este desarrollo se ha programado en un ORIC-1 original.
Os invito a probarlo.
AGRADECIMIENTOS
Agradecer públicamente a silicebit y chema la ayuda prestada para poder acabar el programa.
-thanks