Curso Programación ZX SpectrumCursos

Ensamblador para ZX Spectrum – Pong: $08 Campo, palas, bola y temporización

PorompomPong empieza a tomar forma.

5
(2)

Ensamblador para ZX Spectrum – Pong: Paso 6, campo, palas, bola y temporización

Creamos la carpeta Paso06 y copiamos desde la carpeta Paso05 los archivos Game.asm, Sprite.asm y Video.asm, y desde la carpeta Paso03 el archivo Controls.asm. También creamos el archivo Main.asm.

Empezamos editando el archivo Main.asm, indicando la posición de carga, poniendo el borde en negro, limpiando la pantalla, pintando la línea central y haciendo un bucle infinito para no volver al Basic.

También vamos a incluir el resto de ficheros e indicarle a PASMO dónde llamar al cargar el programa:

org     $8000

Main:
ld      a, $00
out     ($fe), a
call    Cls
call    PrintLine

Loop:
jr      Loop

include "Controls.asm"
include "Game.asm"
include "Sprite.asm"
include "Video.asm"

end     $8000

Compilamos y vemos el resultado en el emulador.

Ensamblador para ZX Spectrum, línea central
Ensamblador para ZX Spectrum, línea central

Pintamos el campo

El siguiente paso es pintar el borde del campo.

Incluimos al inicio del fichero Sprite.asm una nueva constante:

FILL:   EQU $ff

La rutina para pintar el borde la implementamos en el archivo Video.asm, antes de la rutina PrintLine:

PrintBorder:
ld      hl, $4100
ld      de, $56e0
ld      b, $20

Cargamos en HL la dirección del tercio 0, línea 0, scanline 1, LD HL, $4100, cargamos en DE la dirección del tercio 2, línea 7, scanline 6, LD DE, $56E0, y en B las 32 columnas en las que pintar el borde, LD B, $20.

Implementamos el bucle para pintar el borde:

printBorder_loop:
ld      a, FILL
ld      (hl), a
ld      (de), a
inc     l
inc     e
djnz    printBorder_loop
ret

Cargamos en A el sprite del borde, LD A, FILL, lo pintamos en la dirección a la que apunta HL, LD (HL), A, y hacemos los mismo con la dirección a la que apunta DE, LD (DE), A.

Apuntamos HL a la siguiente columna, INC L, y hacemos lo mismo con DE, INC E. Repetimos hasta que B valga 0, DJNZ printBorder_loop, tras lo cual salimos de la rutina, RET.

El aspecto final de la rutina PrintBorder es el siguiente:

; – ---------------------------------------------------------------------------
; Pinta el borde del campo.
; Altera el valor de los registros AD, B, DE y HL.
; – ---------------------------------------------------------------------------
PrintBorder:
ld      hl, $4100               ; Carga en HL la dirección del tercio 0, línea 0 y scanline 1
ld      de, $56e0               ; Carga en DE la dirección del tercio 2, línea 7 y scanline 6
ld      b, $20                  ; Carga en B las 32 columnas en las que pintar

printBorder_loop:
ld      a, FILL                 ; Carga en A el byte a pintar
ld      (hl), a                 ; Pinta en la dirección apuntada por HL
ld      (de), a                 ; Pinta en la dirección apuntada por DE
inc     l                       ; Apunta HL a la siguiente columna
inc     e                       ; Apunta DE a la siguiente columna
djnz    printBorder_loop        ; Bucle hasta que B llegue a 0
ret

Para probar esta rutina, volvemos al archivo Main.asm y tras la llamada a PrintLine ponemos la llamada a la nueva rutina.

call		PrintBorder

Compilamos y vemos los resultados en el emulador.

Ensamblador para ZX Spectrum, pintamos el borde del campo
Ensamblador para ZX Spectrum, pintamos el borde del campo

Ya tenemos dibujado el campo donde se va a desarrollar la acción.

Pintamos la bola

Vamos a introducir la bola en nuestro campo. Como la vamos a estar moviendo y pitando constantemente, vamos a introducir las llamadas a mover y pintar la bola dentro del bucle, entre Loop y JR Loop:

call    MoveBall
call    PrintBall

Compilamos y vemos los resultados en el emulador:

Ensamblador para ZX Spectrum, pintamos la bola
Ensamblador para ZX Spectrum, pintamos la bola

Al ver el resultado, observamos dos problemas: la bola borra la línea central y el borde, y se mueve a una velocidad endiablada.

Lo primero que vamos a abordar es la velocidad a la que se mueve la bola.

En el paso anterior poníamos un HALT para esperar el refresco de la pantalla, pero esto hace que vaya demasiado lenta.

Para reducir la velocidad de la bola, vamos a hacer que no se mueva cada vez que pase por el bucle; se va a mover una de cada N veces.

Seguimos en el archivo Main.asm y, antes de END $8000, declaramos la variable donde vamos a llevar la cuenta de las veces que se ha pasado por el bucle:

countLoopBall:  db $00

Y ahora vamos a implementar la parte en la que comprobamos si ha pasado las veces suficientes para que movamos la bola, justo después de la etiqueta Loop:

ld      a, (countLoopBall)
inc     a
ld      (countLoopBall), a
cp      $0f
jr      nz, loop_continue
call    MoveBall

Cargamos el contador donde guardamos las veces que se ha pasado por el bucle sin mover la bola en A, LD A, (countLoopBall), lo incrementamos, INC A, y lo guardamos en memoria, LD (countLoopBall), A.

Comparamos si el contador ha llegado al número de veces necesarias para mover la bola, CP $0F, y si no ha llegado salta, JR NZ, loop_continue.

Si ya hemos llegado al número de veces necesarias de pasadas por el bucle para mover la bola, la movemos, CALL MoveBall.

La etiqueta loop_continue es nueva y la vamos a poner justo encima de la llamada a PrintBall:

loop_continue:
call    PrintBall

Tenemos que hacer una última cosa. Si el contador ha llegado al número de veces necesario para mover la bola, después de moverla hay que volver a poner el contador a cero, de lo contrario habría que esperar otras 255 veces, en lugar de las que hemos puesto.

Añadimos las siguientes líneas después de la llamada a MoveBall y antes de la etiqueta loop_continue:

ld      a, ZERO
ld      (countLoopBall), a

La implementación de Main.asm quedaría así:

org     $8000
Main:
ld      a, $00
out     ($fe), a            ; Pone el borde en negro

call    Cls                 ; Limpia la pantalla
call    PrintLine           ; Pinta la línea central
call    PrintBorder         ; Pinta el borde

Loop:
ld      a, (countLoopBall)  ; Carga en A el contador de la bola
inc     a                   ; Incrementa el contador
ld      (countLoopBall), a  ; Carga el valor en memoria
cp      $0f                 ; Comprueba si el contador ha llegado a 15
jr      nz, loop_continue   ; Si no ha llegado, salta
call    MoveBall            ; Mueve la posición de la bola
ld      a, ZERO             ; Pone A = 0
ld      (countLoopBall), a  ; Carga el valor en memoria

loop_continue:
call    PrintBall           ; Pinta la bola
jr      Loop                ; Bucle infinito

include "Game.asm"
include "Controls.asm"
include "Sprite.asm"
include "Video.asm"

countLoopBall:  db $00      ; Contador para controlar cuando se mueve la bola
end     $8000

Compilamos y vemos el resultado en el emulador. Esta vez si vemos como se mueve la bola a una velocidad más aceptable.

No hemos definido una constante para la comprobación con el contador de la bola ya que, en un futuro, la velocidad será variable.

Ahora vamos a abordar el problema de las partes que va borrando la bola a su paso, y vamos a empezar por la línea central.

En una primera aproximación, vamos a repintar la parte de la línea que coincide en la coordenada Y con la bola, sin importar si la bola está pasando por encima o no. Parece innecesario, pero nos va a ayudar a temporizar.

Abrimos el archivo Video.asm e implementamos después de la rutina PrintLine:

ReprintLine:
ld      hl, (ballPos)
ld      a, l
and     $e0
or      $10
ld      l, a

Cargamos la posición de la bola en HL, LD HL, (ballPos), cargamos la línea y columna en A, LD A, L, nos quedamos con el valor de la línea, AND $E0, ponemos la columna a 16, que es donde está la línea vertical, OR $10, y cargamos el valor en L, LD L, A.

Vamos a repintar 6 scanlines, que son los mismos que tiene la bola:

ld      b, $06
reprintLine_loop:
ld      a, h

Carga en B el número de scanlines que se repintan, LD B, $06, y carga tercio y scanline en A, LD A, H.

Para pintar la línea, en los scanlines 0 y 7 pintábamos en blanco, y en el resto la parte visible de la línea:

and     $07
cp      $01
jr      c, reprintLine_00
cp      $07
jr      z, reprintLine_00

Nos quedamos con la parte del scanline, AND $07, y comprobamos si es 1, CP $01. Si el scanline es menor que 1 saltamos, JR C, reprintLine_00, en el caso contrario comprobamos si es 7, CP $07. Si el scanline es 7 saltamos, JR Z, reprintLine_00.

Si no hemos saltado, el scanline está entre 1 y 6:

ld      c, LINE
jr      reprintLine_loopCont

Cargamos el sprite de la línea en C, LD C, LINE, y saltamos, JR reprintLine_loopCont.

Si anteriormente saltamos, el scanline es 0 o 7:

reprintLine_00:
ld      c, ZERO

Cargamos el sprite blanco en C, LC C, ZERO, y pintamos lo que corresponda:

reprintLine_loopCont:
ld      a, (hl)
or      c
ld      (hl), a	
call    NextScan
djnz    reprintLine_loop

ret

Cargamos el valor de la dirección de memoria del byte que vamos a repintar en A, LD A, (HL), le añadimos los píxeles del repintado de la línea, OR C, y lo pintamos en pantalla, LD (HL), A. Calculamos la dirección de memoria del scanline siguiente, CALL NextScan, y repetimos la operación hasta que B valga 0, DJNZ reprintLine_loop. Por último, salimos, RET.

El aspecto final de la rutina es el siguiente:

; – ---------------------------------------------------------------------------
; Repinta la línea central.
; Altera el valor de los registros AF, BC y HL.
; – ---------------------------------------------------------------------------
ReprintLine:
ld      hl, (ballPos)           ; Carga en HL la posición de la bola
ld      a, l                    ; Carga la línea y columna en A
and     $e0                     ; Se queda con la línea
or      $10                     ; Pone la columna a 16 ($10)
ld      l, a                    ; Carga el valor en L. HL = Posición inicial repintar

ld      b, $06                  ; Se repintan 6 scanlines
reprintLine_loop:
ld      a, h                    ; Carga tercio y scanline en A
and     $07                     ; Se queda con el scanline
; Si está en los scanlines 0 o 7 pinta ZERO
; Si está en los scanlines 1, 2, 3, 4, 5 o 6 pinta LINE
cp      $01                     ; Comprueba si está en scanline 1 o superior
jr      c, reprintLine_00       ; Si está por debajo, pinta $00
cp      $07                     ; Comprueba si está en scanline 7
jr      z, reprintLine_00       ; Si es así, pinta ZERO

ld      c, LINE                 ; Esta en scanline 1 a 6, pinta LINE
jr      reprintLine_loopCont    ; Salta
reprintLine_00:
ld      c, ZERO                 ; Está en scanline 0 o 7, pinta ZERO
reprintLine_loopCont:
ld      a, (hl)                 ; Obtiene los pixeles de la posición actual
or      c                       ; Los mezcla con C
ld      (hl), a                 ; Pinta el resultado en la posición actual
call    NextScan                ; Obtiene el scanline siguiente
djnz    reprintLine_loop        ; Hasta que B = 0

ret

Podemos ahorrar 5 bytes y 22 ciclos de reloj, modificando 8 líneas de la rutina. Lo dejamos en vuestras manos y veremos la forma de hacerlo en la última entrega.

Ensamblador para ZX Spectrum

Ya solo queda probar lo que hemos implementado, para lo cual abrimos el archivo Main.asm y después de la llamada a PrintBall incluimos la llamada a ReprintLine.

call    ReprintLine

Compilamos y vemos los resultados en el emulador:

Ensamblador para ZX Spectrum – Pong: $08 Campo, palas, bola y temporización 1
Ensamblador para ZX Spectrum, repintamos la línea central

La línea central ya no se borra, pero podemos apreciar que la velocidad de la bola ha disminuido. Hay que tener en cuenta que ahora realizamos más operaciones que antes. Según avancemos iremos ajustando la velocidad de la bola.

Vamos a evitar que se borre el borde, para lo cual vamos a modificar los límites superior e inferior de la bola, en el fichero Sprite.asm:

BALL_BOTTOM:    EQU	$b8
BALL_TOP:       EQU	$02

Compilamos, cargamos en el emulador y comprobamos que ya no se borra el borde.

Incluímos las palas

Ahora vamos a empezar con las palas. Volvemos a Main.asm y añadimos las siguientes líneas entre CALL ReprintLine y JR Loop:

ld      hl, (paddle1pos)
call    PrintPaddle
ld      hl, (paddle2pos)
call    PrintPaddle

Cargamos la posición de la pala 1 en HL, LD HL, (paddle1pos), y pintamos, CALL PrintPaddle. Hacemos los mismo con la pala 2.

Como se puede apreciar, las palas se pintan en todas las iteraciones del bucle, al igual que la bola y el repintado de línea.

Compilamos y vemos los resultados en el emulador:

Ensamblador para ZX Spectrum – Pong: $08 Campo, palas, bola y temporización 2
Ensamblador para ZX Spectrum, incluimos las palas

Se dibujan las palas y la bola no las borra al pasar. También se aprecia que ahora la bola va mucho más lenta, debido a que hacemos más operaciones en cada iteración del bucle.

Para que la bola vuelva a ir más rápida, vamos a cambiar en Main.asm el valor que tenía que alcanzar el contador para que la bola se moviese:

ld      (countLoopBall), a
cp      $06                 ; # Cambiamos $0f por $06 #
jr      nz, loop_continue

Compilamos, cargamos en el emulador y comprobamos que la bola vuelve a ir más rápido.

Ahora vamos a implementar la rutina para mover las palas. Ya vimos como hacerlo en el paso 03. Editamos el archivo Game.asm y vamos al final del mismo.

La rutina que vamos a implementar, recibe en el registro D las pulsaciones de las teclas de control:

MovePaddle:
bit     $00, d
jr      z, movePaddle_1Down

Evaluamos si se ha pulsado la tecla arriba del jugador 1, BIT $00, D. Si no se ha pulsado saltamos a comprobar si se ha pulsado la tecla abajo, JR Z, movePaddle_1Down.

Si no salta, se ha pulsado la tecla abajo del jugador 1:

ld      hl, (paddle1pos)
ld      a, PADDLE_TOP
call    CheckTop
jr      z, movePaddle_2Up

Cargamos la posición de la pala 1 en HL, LD HL, (paddle1pos), el límite superior para las palas en A, LD A, PADDLE_TOP, y comprobamos si se ha alcanzado, CALL CheckTop. Si se ha alcanzado el límite, saltamos a comprobar los controles del jugador 2, JR Z, movePaddle_2Up.

Si no se ha alcanzado el límite superior, movemos la pala 1:

call    PreviousScan
ld      (paddle1pos), hl
jr      movePaddle_2Up

Calculamos la nueva posición para la pala 1, CALL PreviousScan, la cargamos en memoria, LD (paddle1pos), HL, y saltamos a comprobar los controles del jugador 2, JR movePaddle_2Up.

Si no se ha pulsado la tecla arriba del jugador 1, comprobamos si se ha pulsado la tecla abajo:

movePaddle_1Down:
bit     $01, d 
jr      z, movePaddle_2Up

Evaluamos si se ha pulsado la tecla abajo del jugador 1, BIT $01, D. Si no se ha pulsado salta a comprobar los controles del jugador 2, JR Z, movePaddle_2Up.

Si no salta, se ha pulsado la tecla abajo del jugador 1:

ld      hl, (paddle1pos)
ld      a, PADDLE_BOTTOM
call    CheckBottom
jr      z, movePaddle_2Up

Cargamos la posición de la pala 1 en HL, LD HL, (paddle1pos), el límite inferior para las palas en A, LD A, PADDLE_BOTTOM, y comprobamos si se ha alcanzado, CALL CheckBottom. Si se ha alcanzado el límite saltamos a comprobar los controles del jugador 2, JR Z, movePaddle_2Up.

Si no se ha alcanzado el límite inferior, mueve la pala 1:

call    NextScan
ld      (paddle1pos), hl

Calculamos la nueva posición para la pala 1, CALL NextScan, y la cargamos en memoria, LD (paddle1pos), HL.

Hacemos las comprobaciones con los controles del jugador 2. Dada la semejanza, simplemente marcamos los cambios con respecto a la comprobación del jugador 1:

movePaddle_2Up:                 ; # Cambio #
bit     $02, d                  ; # Cambio #
jr      z, movePaddle_2Down     ; # Cambio #
ld      hl, (paddle2pos)        ; # Cambio #
ld      a, PADDLE_TOP
call    CheckTop
jr      z, movePaddle_End       ; # Cambio #
call    PreviousScan
ld      (paddle2pos), hl        ; # Cambio #
jr      movePaddle_End          ; # Cambio #

movePaddle_2Down:               ; # Cambio #
bit     $03, d                  ; # Cambio #
jr      z, movePaddle_End       ; # Cambio #
ld      hl, (paddle2pos)        ; # Cambio #
ld      a, PADDLE_BOTTOM
call    CheckBottom
jr      z, movePaddle_End       ; # Cambio #
call    NextScan
ld      (paddle2pos), hl        ; # Cambio #

movePaddle_End:                 ; # Cambio #
ret                             ; # Cambio #

El aspecto final de la rutina es el siguiente:

; – ---------------------------------------------------------------------------
; Calcula la posición de las palas para moverlas.
; Entrada:  D -> Pulsaciones de los controles
; Altera el valor de los registros AF y HL.
; – ---------------------------------------------------------------------------
MovePaddle:
bit     $00, d              ; Evalúa si se ha pulsado la A
jr      z, movePaddle_1Down ; Si no se ha pulsado salta
ld      hl, (paddle1pos)    ; Carga en HL la posición de la pala 1
ld      a, PADDLE_TOP       ; Carga en A el margen superior
call    CheckTop            ; Evalúa si se ha alcanzado el margen superior
jr      z, movePaddle_2Up   ; Si se ha alcanzado, salta
call    PreviousScan        ; Obtiene el scanline anterior a la posición de la pala 1
ld      (paddle1pos), hl    ; Carga en memoria la nueva posición de la pala 1
jr      movePaddle_2Up      ; Salta

movePaddle_1Down:
bit     $01, d              ; Evalúa si se ha pulsado la Z               
jr      z, movePaddle_2Up   ; Si no se ha pulsado salta
ld      hl, (paddle1pos)    ; Carga en HL la posición de la pala 1
ld      a, PADDLE_BOTTOM    ; Carga en A el margen inferior
call    CheckBottom         ; Evalúa si se ha alcanzado el margen inferior
jr      z, movePaddle_2Up   ; Si se ha alcanzado, salta
call    NextScan            ; Obtiene el scanline siguiente a la posición de la pala 1
ld      (paddle1pos), hl    ; Carga en memoria la nueva posición de la pala 1

movePaddle_2Up:
bit     $02, d              ; Evalúa si se ha pulsado el 0
jr      z, movePaddle_2Down ; Si no se ha pulsado salta
ld      hl, (paddle2pos)    ; Carga en HL la posición de la pala 2
ld      a, PADDLE_TOP       ; Carga en A el margen superior
call    CheckTop            ; Evalúa si se ha alcanzado el margen superior
jr      z, movePaddle_End   ; Si se ha alcanzado, salta
call    PreviousScan        ; Obtiene el scanline anterior a la posición de la pala 2
ld      (paddle2pos), hl    ; Carga en memoria la nueva posición de la pala 2
jr      movePaddle_End      ; Salta

movePaddle_2Down:
bit     $03, d              ; Evalúa si se ha pulsado la O
jr      z, movePaddle_End   ; Si no se ha pulsado salta
ld      hl, (paddle2pos)    ; Carga en HL la posición de la pala 2
ld      a, PADDLE_BOTTOM    ; Carga en A el margen inferior
call    CheckBottom         ; Evalúa si se ha alcanzado el margen inferior
jr      z, movePaddle_End   ; Si se ha alcanzado, salta
call    NextScan            ; Obtiene el scanline siguiente a la posición de la pala 2
ld      (paddle2pos), hl    ; Carga en memoria la nueva posición de la pala 2

movePaddle_End:
ret

Podemos ahorrar 2 bytes y 2 ciclos de reloj, de la misma forma que en la entrega anterior. Esta vez no daremos la solución en la última entrega, ya que es similar a la que se verá para la entrega anterior.

Ensamblador para ZX Spectrum

Para terminar, vamos a implementar en Main.asm las llamadas a esta rutina, dentro de nuestro bucle infinito, justo encima de la etiqueta loop_continue:

loop_paddle:
call    ScanKeys
call    MovePaddle

Primero comprobamos las teclas de control que se han pulsado, CALL ScanKeys, y luego movemos las palas, CALL MovePaddle.

También tenemos que cambiar la etiqueta a la que salta cuando la bola no se mueve, 4 líneas más arriba:

cp      $06
jr      nz, loop_paddle     ; # Cambio #
call    MoveBall

Compilamos y probamos en el emulador:

Ensamblador para ZX Spectrum – Pong: $08 Campo, palas, bola y temporización 3
Ensamblador para ZX Spectrum, las palas borran el campo

Observamos dos problemas:

  1. Las palas borran el borde.
  2. Las palas se mueven muy rápido y son difíciles de controlar.

Para resolver el primer problema vamos a modificar las constantes que marcan los límites superior e inferior de las palas, que están en Sprite.asm:

PADDLE_BOTTOM:  EQU $a6
PADDLE_TOP:     EQU $02

Compilamos, cargamos en el emulador y comprobamos que ya no se borra el borde:

Ensamblador para ZX Spectrum, las palas ya no borran el campo
Ensamblador para ZX Spectrum, las palas ya no borran el campo

Para reducir la velocidad del movimiento de las palas, vamos a usar la misma técnica que usamos con la bola; no vamos a mover las palas a cada iteración del bucle.

Lo primero es declarar la variable que usaremos como contador, lo que hacemos antes de END $8000:

countLoopPaddle:    db $00

Ahora, justo debajo de la etiqueta loop_paddle, implementamos la comprobación del contador:

ld      a, (countLoopPaddle)
inc     a
ld      (countLoopPaddle), a
cp      $02
jr      nz, loop_continue
call    MovePaddle

Cargamos el contador en A, LD A, (countLoopPaddle), lo incrementamos, INC A, y lo cargamos en memoria, LD (countLoopPaddle), A. Evaluamos si han pasado las veces que hemos definido para mover las palas, CP $02, y si no es así saltamos, JR NZ, loop_continue.

Si no salta, movemos las palas, CALL MovePaddle, y tal y como hicimos con la bola, hay que poner el contador a cero. Añadimos las líneas siguientes antes de la etiqueta loop_continue:

ld      a, ZERO
ld      (countLoopPaddle), a

Cargamos 0 en A, LD A, ZERO, y lo cargamos en memoria, LD (countLoopPaddle), A, poniendo el contador a 0.

Compilamos y cargamos en el emulador. Ahora el control de las palas es menos rápido y más preciso.

El código final de Main.asm es el siguiente:

; Pintado de campo, movimiento de palas y bola y temporización
org     $8000

; – ---------------------------------------------------------------------------
; Entrada al programa
; – ---------------------------------------------------------------------------
Main:
ld      a, $00                  ; A = 0
out     ($fe), a                ; Pone el borde en negro

call    Cls                     ; Limpia la pantalla
call    PrintLine               ; Imprime la línea central
call    PrintBorder             ; Imprime el borde del campo

Loop:
ld      a, (countLoopBall)      ; Carga el contador de vueltas de la bola	
inc     a                       ; Lo incrementa
ld      (countLoopBall), a      ; Lo carga en memoria
cp      $06                     ; Comprueba si ha llegado a 6
jr      nz, loop_paddle         ; Si no ha llegado a 4 salta
call    MoveBall                ; Mueve la bola
ld      a, ZERO                 ; Pone el contador a 0
ld      (countLoopBall), a      ; Lo carga en memoria

loop_paddle:
ld      a, (countLoopPaddle)    ; Carga el contador de vueltas de las palas
inc     a                       ; Lo incrementa
ld      (countLoopPaddle), a    ; Lo carga en memoria
cp      $02                     ; Comprueba si ha llegado a 2
jr      nz, loop_continue       ; Si no ha llegado a 2 salta
call    ScanKeys                ; Escanea las teclas pulsadas
call    MovePaddle              ; Mueva las palas
ld      a, ZERO                 ; Pone el contador a 0
ld      (countLoopPaddle), a    ; Lo carga en memoria

loop_continue:
call    PrintBall               ; Pinta la bola
call    ReprintLine             ; Repinta la línea
ld      hl, (paddle1pos)        ; Carga en HL la posición de la pala 1
call    PrintPaddle             ; Pinta la pala 1
ld      hl, (paddle2pos)        ; Carga en HL la posición de la pala 2
call    PrintPaddle             ; Pinta la pala 2
jr      Loop                    ; Bucle infinito

include "Game.asm"
include "Controls.asm"
include "Sprite.asm"
include "Video.asm"

countLoopBall:      db $00      ; Contador de vueltas de la bola
countLoopPaddle:    db $00      ; Contador de vueltas de las palas

end     $8000

En el próximo capítulo de Ensamblador para ZX Spectrum, implementaremos la detección de colisiones.

Enlaces de interés

Ficheros

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en una estrella para puntuar!

Etiquetas

Un comentario

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Publicaciones relacionadas

Botón volver arriba
Cerrar
Cerrar
Configuración de Cookie Box