Cómo hacer scroll de una fila completa en Zx Spectrum
- Bubu
- Atari 1040 STf
- Mensajes: 895
- Registrado: 04 Abr 2018, 23:10
- Sistema Favorito: Spectrum 16Kb/48Kb
- primer_sistema: Spectrum 16Kb/48Kb
- consola_favorita: Atari 2600
- Primera consola: Nintendo GameBoy
- Gracias dadas: 21 veces
- Gracias recibidas: 67 veces
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Pero entóns tarda el doble, ¿nor? La idea era de alguna manera no hacer dos RRA's sino un RRA doble, idear algo que rote en memoria el doble y luego finalmente imprimir en pantalla el resultado final, no imprimir en pantalla las dos rotaciones de 1 pixel c/u.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- explorer
- MSX Turbo R
- Mensajes: 443
- Registrado: 11 May 2014, 17:10
- Sistema Favorito: Atari ST
- primer_sistema: Atari 800XL/600XL
- consola_favorita: Atari 2600
- Primera consola: Atari 2600
- Ubicación: Valladolid, España
- Gracias dadas: 2 veces
- Gracias recibidas: 162 veces
- Contactar:
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Una posibilidad sería cambiar CPU por RAM, usando una tabla de las 256 combinaciones posibles de rotación. Eso suma 512 bytes. Pero no te libra de hacer un AND y un OR de los nuevos bits altos. También puedes sustituir el AND por otra tabla, pero son 256 bytes más.
No hay instrucciones de rotación múltiple. Todas son desplazamientos o rotaciones de un solo bit.
Otra posibilidad es: se desplaza dos veces el byte de pantalla y los acarreos se almacenan, también con un desplazamiento, en un registro temporal. Una vez terminada la segunda rotación, hacemos un OR con otro registro temporal que guardaba los bits rotados del anterior byte.
El caso es que si sumas todas las operaciones, salen bastantes más ciclos que la de hacer la rotación de la línea dos veces.
Y aquí es donde nos damos cuenta del porqué se utilizaban las técnicas de prerotación de los sprites. O de solo rotar las zonas de pantalla que contienen algo (rotar el espacio que solo contiene fondo solo supone un gasto de ciclos de CPU).
Seguiremos pensando...
P.D.: existe la instrucción RRD que hace una rotación de nibbles entre los contenidos de los registros HL y A.
Hay otra posibilidad... hacer que dos bytes consecutivos de la memoria de pantalla estén en un registro doble, ya que desplazar y rotarlos es más rápido que rotar la memoria de pantalla y hacer luego el AND y el OR.
No hay instrucciones de rotación múltiple. Todas son desplazamientos o rotaciones de un solo bit.
Otra posibilidad es: se desplaza dos veces el byte de pantalla y los acarreos se almacenan, también con un desplazamiento, en un registro temporal. Una vez terminada la segunda rotación, hacemos un OR con otro registro temporal que guardaba los bits rotados del anterior byte.
El caso es que si sumas todas las operaciones, salen bastantes más ciclos que la de hacer la rotación de la línea dos veces.
Y aquí es donde nos damos cuenta del porqué se utilizaban las técnicas de prerotación de los sprites. O de solo rotar las zonas de pantalla que contienen algo (rotar el espacio que solo contiene fondo solo supone un gasto de ciclos de CPU).
Seguiremos pensando...
P.D.: existe la instrucción RRD que hace una rotación de nibbles entre los contenidos de los registros HL y A.
Hay otra posibilidad... hacer que dos bytes consecutivos de la memoria de pantalla estén en un registro doble, ya que desplazar y rotarlos es más rápido que rotar la memoria de pantalla y hacer luego el AND y el OR.
- explorer
- MSX Turbo R
- Mensajes: 443
- Registrado: 11 May 2014, 17:10
- Sistema Favorito: Atari ST
- primer_sistema: Atari 800XL/600XL
- consola_favorita: Atari 2600
- Primera consola: Atari 2600
- Ubicación: Valladolid, España
- Gracias dadas: 2 veces
- Gracias recibidas: 162 veces
- Contactar:
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Bueno, esta es mi solución, pero... es un desastre. Ocupa 495 bytes y tarda 16951 ciclos. La versión de un píxel tardaba 5154 ciclos.
Así que mi hipótesis de que es mejor ejecutar dos veces la rutina de un píxel sigue siendo cierta. No sé... habrá que darle una pensada...
Así que mi hipótesis de que es mejor ejecutar dos veces la rutina de un píxel sigue siendo cierta. No sé... habrá que darle una pensada...
Código: Seleccionar todo
; ********************************************************************
; Scroll de doble pixel para Spectrum
;
; Demo en asm80.com
;
; $Date: Sun, 11 agosto 2018 23:34:40 +0100 $
; $Author: Joaquín Ferrero $
; $Revision: $
;
; ********************************************************************
;--------------------------------------------------------------------
; Entorno y constantes
.ENGINE zxs
VIDEORAM = $4000
TERCIO = 1
FILA = 4
;[ 010 TT SSS ] - [ RRR CCCCC ]
INICIO = VIDEORAM | (TERCIO * 2^11) | (FILA * 2^5)
;--------------------------------------------------------------------
.CSEG
.ORG 40000
.ENT $
;--------------------------------------------------------------------
; Relleno de pantalla con un patrón de prueba
; tamaño del bloque a pintar
ANCHO = 16 ; en bytes
ALTO = 8 ; en píxeles
.BLOCK
LD b,ALTO
LD hl,INICIO | (16 - ANCHO/2)
LD ixh,01111111B
LOOPrelleno:
PUSH bc
LD de,hl
INC de
LD bc,ANCHO-1
LD a,ixh
LD (hl),a
RRCA
LD ixh,a
LDIR
INC h
LD a,l
SUB ANCHO-1
LD l,a
POP bc
DJNZ LOOPrelleno
.ENDBLOCK
;--------------------------------------------------------------------
; Bucle principal
.BLOCK
LD bc,$0200
LOOP:
PUSH bc
CALL ROT2_RIGHT
; bucle de espera
LD bc,$1000 ; Cambiar para tener otra espera
WAIT:
DEC c
JR nz,WAIT
DJNZ WAIT
POP bc
DEC c
JR nz,LOOP
DJNZ LOOP
RET
.ENDBLOCK
;--------------------------------------------------------------------
; Desplazar a la derecha dos píxeles
;--------------------------------------------------------------------
.BLOCK
@ROT2_RIGHT: ;16951;
LD hl,INICIO ;10; comienzo del área a rotar
LD c,l ; 4; recordar número de fila (RRR), columna 0
LD b,8 ; 7; número de líneas a rotar
LOOP_SCAN: ;16920;
LD de,0 ;10; caché píxeles (d=anterior,e=actual)
; rota las primeras columnas
.REPT 31 ;2015;
rotaYpinta ;50;
LD d,e ; 4; intercambiamos cachés
LD e,0 ; 7;
INC l ; 4; siguiente columna
.ENDM
; rota última columna
rotaYpinta ;50;
LD l,c ; 4; recuperamos fila, columna 0
LD a,(HL) ; 7; primera columna
OR e ; 4; píxeles que salieron de la última columna
LD (hl),a ; 7; nueva primera columna
INC h ; 4; Siguiente scanline
; DJNZ LOOP_SCAN
DEC b ; 4;
JP NZ,LOOP_SCAN ;10;
RET ;10;
.MACRO rotaYpinta ;50;
LD a,(hl) ; 7; byte de pantalla
SRL a ; 8; primer píxel
RR e ; 8; guardamos C
SRL a ; 8; segundo píxel
RR e ; 8; guardamos C
OR d ; 4; recuperamos los píxeles rotados del byte anterior
LD (hl),a ; 7; lo ponemos en pantalla
.ENDM
.ENDBLOCK
;--------------------------------------------------------------------
- Bubu
- Atari 1040 STf
- Mensajes: 895
- Registrado: 04 Abr 2018, 23:10
- Sistema Favorito: Spectrum 16Kb/48Kb
- primer_sistema: Spectrum 16Kb/48Kb
- consola_favorita: Atari 2600
- Primera consola: Nintendo GameBoy
- Gracias dadas: 21 veces
- Gracias recibidas: 67 veces
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
En resumen, es más rápido desplazar 1 píxel N veces, que desplazar N veces 1 píxel, aunque suene a los mismo. Pues bueno es saberlo. Y por tanto para más velocidad ya sería pre-rotar en tiempo de desarrollo lo que se quiera mostrar. Bueno, voy a tratar de implementar el Frogger a ver cómo se vería con la rutina de desplazamientos normal de 1 píxel. En cuanto lo tenga os comentaré los resultados.
Muchas muchísimas gracias, explorer
Muchas muchísimas gracias, explorer
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- Bubu
- Atari 1040 STf
- Mensajes: 895
- Registrado: 04 Abr 2018, 23:10
- Sistema Favorito: Spectrum 16Kb/48Kb
- primer_sistema: Spectrum 16Kb/48Kb
- consola_favorita: Atari 2600
- Primera consola: Nintendo GameBoy
- Gracias dadas: 21 veces
- Gracias recibidas: 67 veces
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Por cierto, un pequeño cálculo de servilleta; voy a ver qué ocuparía en RAM el almacenamiento de las imágenes de la carretera y río predesplazadas:
son 10 filas, por tanto 10 x 8 x 32 = 2.560 bytes
eso sería una posición, como hay que almacenar las 8 pre-rotaciones:
2560 x 8 = 20.480 bytes
Maaaadredediossss... ¡¡20 KB!! Teniendo en cuén que el Spectrum cuenta con menos de 42KB para pograma, nos quedarían 22KB para hacer el pograma. Nu sé yo...
La técnica que usé yo para hacer este juego en su momento estaba mucho más optimizada: tenía almacenada en RAM sólo la imagen de cada objeto por separado, no de toda la fila. Pero era una locura el tratamiento de todo esto. Aun así lo hice, pero la rutina de detección de choques era una paranoia que no veas... En fins, esto ya es otra historia.
son 10 filas, por tanto 10 x 8 x 32 = 2.560 bytes
eso sería una posición, como hay que almacenar las 8 pre-rotaciones:
2560 x 8 = 20.480 bytes
Maaaadredediossss... ¡¡20 KB!! Teniendo en cuén que el Spectrum cuenta con menos de 42KB para pograma, nos quedarían 22KB para hacer el pograma. Nu sé yo...
La técnica que usé yo para hacer este juego en su momento estaba mucho más optimizada: tenía almacenada en RAM sólo la imagen de cada objeto por separado, no de toda la fila. Pero era una locura el tratamiento de todo esto. Aun así lo hice, pero la rutina de detección de choques era una paranoia que no veas... En fins, esto ya es otra historia.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- explorer
- MSX Turbo R
- Mensajes: 443
- Registrado: 11 May 2014, 17:10
- Sistema Favorito: Atari ST
- primer_sistema: Atari 800XL/600XL
- consola_favorita: Atari 2600
- Primera consola: Atari 2600
- Ubicación: Valladolid, España
- Gracias dadas: 2 veces
- Gracias recibidas: 162 veces
- Contactar:
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Y esa es una de las explicaciones por las cuales muchos juegos no hacían desplazamiento borde a borde, o a toda pantalla. Ponían bordes decorativos para reducir el ancho del juego. O solo ocupaban dos de los tres tercios (el otro tercio reservado para marcadores).
Si con la calculadora en la mano te quedas sin memoria, habrá que empezar a recortar. Lo más obvio es no desplazar las partes vacías, pero volvemos a lo que comentas: llevar el control de todos los objetos que están en pantalla.
Bueno, es cuestión de organizarse.
Las rutinas que he escrito, se podrían mejorar en tiempo triplicando el código utilizado para detectar "espacio vacío" (no es necesario desplazar valores 0 o valores 255 o $AAAA o $5555 y demás patrones que se pueden repetir). Mejoraría la velocidad a cambio de aumentar el código. Pero solo valdría la pena si hay pocos objetos en la fila.
Si con la calculadora en la mano te quedas sin memoria, habrá que empezar a recortar. Lo más obvio es no desplazar las partes vacías, pero volvemos a lo que comentas: llevar el control de todos los objetos que están en pantalla.
Bueno, es cuestión de organizarse.
Las rutinas que he escrito, se podrían mejorar en tiempo triplicando el código utilizado para detectar "espacio vacío" (no es necesario desplazar valores 0 o valores 255 o $AAAA o $5555 y demás patrones que se pueden repetir). Mejoraría la velocidad a cambio de aumentar el código. Pero solo valdría la pena si hay pocos objetos en la fila.
- Bubu
- Atari 1040 STf
- Mensajes: 895
- Registrado: 04 Abr 2018, 23:10
- Sistema Favorito: Spectrum 16Kb/48Kb
- primer_sistema: Spectrum 16Kb/48Kb
- consola_favorita: Atari 2600
- Primera consola: Nintendo GameBoy
- Gracias dadas: 21 veces
- Gracias recibidas: 67 veces
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
OK, centrémonos entonces en el caso que propongo: el Frogger. Como ves, hay una carretera y un río. Unos coches van de izquierda a derecha y otros de derecha a izquierda, y cada fila a diferente velocidad. Al río le pasa lo mismo. Además, depende de la fase, salen más o menos coches y más o menos troncos. Pero eso sí, dada una fase, nunca cambian estos parámetros.
Así las cosas, ¿cuál crees que sería el método más óptimo? ¿Imprimir una sola vez en pantalla la carretera y río, y entóns a scrollear píxel a píxel? Se me ocurre otra manera, creo que es la que más velocidad coge:
Tengo los sprites almacenados por un lado. Ahora, pinto en RAM (no en VRAM) cada fila del río predesplazada en todas sus posibilidades (uséase, 8 veces) tomando como gráficos los sprites almacenados y haciendo los desplazamientos en tiempo de ejecución, antes de empezar a jugar la fase. Ahora, tomo de ese buffer la fila con DESPL=0 y la pinto en VRAM. Pasado un tiempo determinado, tomo de ese buffer esa fila pero con DESPL=1 y la pinto en VRAM, encima de la que tenía DESPL=0.
Así que lo único que voy haciendo aquí es LD A, (DE) + LD (HL), A todo el rato. Eso sí, el buffer ocuparía los 10 x 32 x 8 x 8 bytes, es decir, se necesita un buffer de 20KB. Téngase en cuén que el método anterior de hacer scroll de la VRAM de píxel en píxel haría que la propia rana hiciera scroll en la carretera
Con el buffer no, porque pinto la carretera, pinto la rana, pinto la carretera desplazada, pinto la rana, pinto la carretera más desplazada, pinto la rana, etc, etc.
Así las cosas, ¿cuál crees que sería el método más óptimo? ¿Imprimir una sola vez en pantalla la carretera y río, y entóns a scrollear píxel a píxel? Se me ocurre otra manera, creo que es la que más velocidad coge:
Tengo los sprites almacenados por un lado. Ahora, pinto en RAM (no en VRAM) cada fila del río predesplazada en todas sus posibilidades (uséase, 8 veces) tomando como gráficos los sprites almacenados y haciendo los desplazamientos en tiempo de ejecución, antes de empezar a jugar la fase. Ahora, tomo de ese buffer la fila con DESPL=0 y la pinto en VRAM. Pasado un tiempo determinado, tomo de ese buffer esa fila pero con DESPL=1 y la pinto en VRAM, encima de la que tenía DESPL=0.
Así que lo único que voy haciendo aquí es LD A, (DE) + LD (HL), A todo el rato. Eso sí, el buffer ocuparía los 10 x 32 x 8 x 8 bytes, es decir, se necesita un buffer de 20KB. Téngase en cuén que el método anterior de hacer scroll de la VRAM de píxel en píxel haría que la propia rana hiciera scroll en la carretera

Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!
- Namek
- Atari 1040 STf
- Mensajes: 840
- Registrado: 11 Jul 2011, 13:13
- Gracias dadas: 18 veces
- Gracias recibidas: 63 veces
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Muy buenas, voy a darte mi humilde opinión a ver que te parece.
Ya que vas a usar un buffer para las rotaciones, mejor tener los sprites pre-rotados y ya que no van a tener fondo harias la misma transferencia que con el buffer y para colmo te ahorras el tiempo de ejecución de transferir los huecos vacios, por tanto ahorras memoria y tiempo de CPU que puedes usar para los calculos de posicionamiento de los sprites. Que opinas tu?
Ya que vas a usar un buffer para las rotaciones, mejor tener los sprites pre-rotados y ya que no van a tener fondo harias la misma transferencia que con el buffer y para colmo te ahorras el tiempo de ejecución de transferir los huecos vacios, por tanto ahorras memoria y tiempo de CPU que puedes usar para los calculos de posicionamiento de los sprites. Que opinas tu?

- explorer
- MSX Turbo R
- Mensajes: 443
- Registrado: 11 May 2014, 17:10
- Sistema Favorito: Atari ST
- primer_sistema: Atari 800XL/600XL
- consola_favorita: Atari 2600
- Primera consola: Atari 2600
- Ubicación: Valladolid, España
- Gracias dadas: 2 veces
- Gracias recibidas: 162 veces
- Contactar:
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Dentro de una fase no cambian los enemigos, pero cada X segundos se oye un sonido como de espita de gas, y los coches y el cocodrilo de la última fila aumentan súbitamente de velocidad. Yo creo que incluso alguna fila multiplica su velocidad por dos.Bubu escribió:OK, centrémonos entonces en el caso que propongo: el Frogger. Como ves, hay una carretera y un río. Unos coches van de izquierda a derecha y otros de derecha a izquierda, y cada fila a diferente velocidad. Al río le pasa lo mismo. Además, depende de la fase, salen más o menos coches y más o menos troncos. Pero eso sí, dada una fase, nunca cambian estos parámetros.
Hay personajes que solo aparecen de vez en cuando, como la nutria que te muerde si estás en el extremo del tronco. Generalmente, parece que los objetos que desaparecen por un lado, luego aparecen por el otro, pero... a medida que aumenta la fase suelen tardar más en aparecer.
Todos los objetos de una fila se mueven a la misma velocidad, exceptuando la nutria, que a veces da un acelerón. La serpiente aparece sobre un tronco de las primeras filas o en descansillo de la mitad.
Es lo que he visto hasta ahora. Es un juego cuya versión arcade funciona en z80 a 3 Mhz, por lo que, en teoría, sería posible llevarlo al Spectrum. La pantalla tiene una resolución de 224×768.
Hay que borrar lo pintado, claro. Un truco sería definir un borde negro a los sprites de un ancho igual a la máxima velocidad que puede alcanzar. O usar un método de borrado tan sencillo como pintar 8 bytes 0 siempre.Bubu escribió:Así las cosas, ¿cuál crees que sería el método más óptimo? ¿Imprimir una sola vez en pantalla la carretera y río, y entóns a scrollear píxel a píxel? Se me ocurre otra manera, creo que es la que más velocidad coge:
Tengo los sprites almacenados por un lado. Ahora, pinto en RAM (no en VRAM) cada fila del río predesplazada en todas sus posibilidades (uséase, 8 veces) tomando como gráficos los sprites almacenados y haciendo los desplazamientos en tiempo de ejecución, antes de empezar a jugar la fase. Ahora, tomo de ese buffer la fila con DESPL=0 y la pinto en VRAM. Pasado un tiempo determinado, tomo de ese buffer esa fila pero con DESPL=1 y la pinto en VRAM, encima de la que tenía DESPL=0.
El método que describes es lo que se conoce como doble búfer. Se puede hacer, desde luego, pero luego hay que ver cuánto tarda el micro en volcarlo todo a pantalla. ¿Y eso implica que también debe volcar las zonas vacías? Quizás perdemos las ventajas.
Los sistemas de doble búfer más inteligentes solo borran las diferencias entre cuadros y pintan solo lo que hay de nuevo. No es algo.... sencillo.
Un LDIR podría servir para mover una línea entera del sprite, de (HL)++ a (DE)++.Bubu escribió:Así que lo único que voy haciendo aquí es LD A, (DE) + LD (HL), A todo el rato. Eso sí, el buffer ocuparía los 10 x 32 x 8 x 8 bytes, es decir, se necesita un buffer de 20KB. Téngase en cuén que el método anterior de hacer scroll de la VRAM de píxel en píxel haría que la propia rana hiciera scroll en la carreteraCon el buffer no, porque pinto la carretera, pinto la rana, pinto la carretera desplazada, pinto la rana, pinto la carretera más desplazada, pinto la rana, etc, etc.
El que haya una rana (y si luego pones a la rana macho, también) ya implica que no puedes hacer scroll en la parte de abajo. Sí en la de arriba, ya que todo se mueve. De todas maneras, yo creo que lo mejor es no desplazar toda la fila y pensar más en términos de Sprites.
Bueno... si el juego se hace sencillo, podría valer un desplazamiento de toda la fila, claro.
- explorer
- MSX Turbo R
- Mensajes: 443
- Registrado: 11 May 2014, 17:10
- Sistema Favorito: Atari ST
- primer_sistema: Atari 800XL/600XL
- consola_favorita: Atari 2600
- Primera consola: Atari 2600
- Ubicación: Valladolid, España
- Gracias dadas: 2 veces
- Gracias recibidas: 162 veces
- Contactar:
Re: Cómo hacer scroll de una fila completa en Zx Spectrum
Creo que en una de las Microhobby se comentaba que había un límite en el número de sprites de 16×16 de la rutina que publicaron, a partir del cual se notaba más el parpadeo.
Si consigues que la rutina de pintado sea muy rápida, te puedes ahorrar el pintado de algún sprite porque aún estará en el mismo píxel.
Si consigues que la rutina de pintado sea muy rápida, te puedes ahorrar el pintado de algún sprite porque aún estará en el mismo píxel.
¿Quién está conectado?
Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 5 invitados