Commodore manía
Commodore 64 => Desarrollo => Ensamblador => Mensaje iniciado por: Laddh en Marzo 01, 2026, 19:23:33
-
Una pregunta a los coders del foro, os pongo en situación, tengo un mapa de 4 pantallas en horizontal, hago un scroll izquierda y derecha, y quiero poner sprites enemigos en diversas plataformas y la pregunta es como sincronizas el movimiento de los sprites para que vaya acorde al movimiento de la pantalla ( se mantengan en su plataforma, desaparezcan cuando esa parte del mapa no este en pantalla, etc ).
Alguna teoría, algoritmo o ejemplos sobre el tema? He buscado y no encuentro nada.
-
Es una buena pregunta y tiene que haber tratados sobre eso.
Yo me imagino dos tipos de escenarios:
- Permanente: todos los sprites están vivos, moviendose por el mapa según su programación aunque el mapa esté en memoria
- Efímero: los enemigos se activan cuando están a X pixels de aparecer en pantalla y al salir de ese rango se reinician
-
Una pregunta a los coders del foro, os pongo en situación, tengo un mapa de 4 pantallas en horizontal, hago un scroll izquierda y derecha, y quiero poner sprites enemigos en diversas plataformas y la pregunta es como sincronizas el movimiento de los sprites para que vaya acorde al movimiento de la pantalla ( se mantengan en su plataforma, desaparezcan cuando esa parte del mapa no este en pantalla, etc ).
Alguna teoría, algoritmo o ejemplos sobre el tema? He buscado y no encuentro nada.
Pues es algo que no he hecho nunca (al menos horizontalmente), pero a bote pronto se me ocurre guardar las coordenadas en X de cada sprite y de la pantalla actual de caracteres en formato 16bits, e ir comprobando si cada sprite tiene que mostrarse en la ventana gráfica actual. Con esta solución se debería traducir la dirección en 16bits o "absoluta" a la dirección de lo que se ve en pantalla (relativa al marco izquierdo de la pantalla), cuando un sprite tenga que salir en pantalla. No sé si me he explicado bien...
-
Una pregunta a los coders del foro, os pongo en situación, tengo un mapa de 4 pantallas en horizontal, hago un scroll izquierda y derecha, y quiero poner sprites enemigos en diversas plataformas y la pregunta es como sincronizas el movimiento de los sprites para que vaya acorde al movimiento de la pantalla ( se mantengan en su plataforma, desaparezcan cuando esa parte del mapa no este en pantalla, etc ).
Alguna teoría, algoritmo o ejemplos sobre el tema? He buscado y no encuentro nada.
A las contestaciones de @PacoBlog64 y de @josepzin, que son MUY correctas, te recuerdo además que los sprites se pueden ocultar por detrás del borde, con lo cual su entrada y salida en pantalla es gradual. Es decir, para dibujar sus coordenadas en pantalla tienes que tener en cuenta que salen/se meten 24 pixels antes/después en horizontal y 50 pixels antes/después en vertical. La posición de coordenadas menores con el total de un sprite en pantalla es de (24,50) para la esquina superior izquierda
-
De todos modos, seguramente laddh está buscando algo mas técnico y específico.
-
Yaaa....yo es por no estropearle la "peleilla". ;D
Las ideas principales son:
- El sprite tiene que tener una velocidad horizontal de la misma magnitud que la pantalla, pero en dirección opuesta. Por lo tanto, la velocidad del sprite en x es Vxsprite - Vxpantalla. Hayq ue tener en cuenta el signo de la velocidad, por supuesto, ya que si ambas velocidades tiene la misma dirección las maginitudes SE SUMARÁN y si son opuestas se restarán. Eso ya te lo da la fórmula. Para los enemigos estáticos, cuya Vxsprite = 0, su velocidad en PANTALLA será -Vxpantalla por lo tanto. Es lo que se llama una velocidad relativa a la pantalla. La velocidad en y del sprite será la propia del sprite, ya que NO HAY SCROLL VERTICAL
- Con esa velocidad, la coordenada del sprite sera X=X+Vx e Y=Y+Vy...eso como siempre
- Para situar las coordenadas del Sprite "en el mundo" yo empezaría por asignarle coordenadas del Tile correspondiente a la esquina superior izquierda del sprite. Para que aparezca en pantalla antes o después hay que tener en cuenta su tamaño. SI tienes sprites de diferentes tamaños, yo no me liaría y usaría siempre las mismas dimensiones, las estandar:24x21. Como el scroll es horizontal, tienes que tener en cuenta el borde de la pantalla(los sprites se representan por debajo de él) y ponerlos con una X=0 cuando queden 3 tiles para que "salgan" (3 tiles x 8 pixels/tile = 24, que es la anchura estándar del sprite y de los bordes derecho e izquierdo). No tienes que pensar nada parecido en vertical.
-Como los sprites se "PINTAN" debajo del borde, hay que tener en cuenta que desaparecen con una coordenada 0(por la izquierda, que es el "borde izquierdo bajo el borde izquierdo) o 24+40*8+1= 345, (que es cuando su esquina superior izquierda queda bajo el borde derecho). En ambos casos no hay ningún pixel del sprite en pantalla (salvo que no tengan puesto el x2 en X o en Y...o que no sean multisprite....en cualquiera de estos casos especiales, dinos y te ayudamos
-Las buenas prácticas con sprites de C64 te dicen que NO apagues el sprite...que los dejes bajo el borde y lo recicles para evitar ciclos perdidos y tirones
-Cómo se traducen las coordenadas del sprite desde coordenadas de tiles?Pues teniendo en cuenta el sistema diferente de coordenadas de los sprites (ya que su cero es distinto y se mueven al pixel).Las fórmulas serían Xsprite=24+8*Xtile Ysprite=50+8*Ytile(ya que los bordes superior e inferior son de 50 pixels.Una vez "conectado" el sprite, es más fácil ir operando con la velocidad de la pantalla, que es unica para todos, y la velocidad del propio sprite(que será cero si está "anclado al suelo"), que traducir las coordenadas, que es más lento. el sprite quedaría "desactivado" si su x se sale del rango [0,344). En Y su rango visible es desde 50-24 = 26 hasta 26+25*8+1 = 227, es decir [26, 227)
-
cómo se traduce "cuando queden 3 tiles para que salga el Sprite"? Pues fácil. pongamos que las coordenadas de la pantalla en el mundo son (20,0) (la coordenada Y de la pantalla SIEMPRE SERÁ cero en tu caso, porque la altura del mundo es de 1 pantalla).En pantalla se pintarán las columnas 20 a 59 del mundo.si hay sprites en los tiles de la columna 20-3 = 17, deberán asociarse a un sprite con una X=0 y su Y correspondiente -> Ysprite=50+8*Ytile (ya que los bordes supeior e inferior tienen 50 pixels de anchura en lo que a sprites se refiere)...et voilá!
Esto es más lío de explicar que de hacer....cualquier duda que vayas teniendo cuenta
-
Vaya.., gracias por todas estas anotaciones, me las apunto y a ver si las puedo aplicar.
El tema tiles sigue siendo una de mis asignaturas pendientes, aún no ha caído en mis manos un source que me explique claro (no soy bueno con la teoría, solo aprendo cuando veo un ejemplo práctico que expone y se ve lo que hace)
Voy con la "peleilla" ;)
-
Para las multiplicaciones en ensamblador. Lo vemos con las fórmulas de las coordenadas del sprite en funcióna de las del tile:
Xsprite = 24 + 8*Xtile => Xsprite = 8*3 + 8*Xtile ; Xsprite = 8*(Xtile + 3); Xsprite = 3ASL(Xtile + 3).
Es decir en ensamblador
LDA Xtile
CLC
ADC #$3
ASL
ASL
ASL
y ya tienes la X del sprite!
(NOTA: Multiplicar por dos equivale a una rotación de 1 BIT a la izquierda en binario. Por eso 8*=2*2*2=3ASL
(estamos hablando de tiles de 8x8 pixels, of course. Si fueran de 2x2 chars, sustituir el 8 inicial por un 16 ,esto es Xsprite=24+16*Xtile, y ver cómo simplificar la operación en ensamblador)
-
Vaya.., gracias por todas estas anotaciones, me las apunto y a ver si las puedo aplicar.
El tema tiles sigue siendo una de mis asignaturas pendientes, aún no ha caído en mis manos un source que me explique claro (no soy bueno con la teoría, solo aprendo cuando veo un ejemplo práctico que expone y se ve lo que hace)
Voy con la "peleilla" ;)
El tema Tiles está tirado. EL C64 en modo "normal" está preparado para textos, luego puedes definir un juego de caracteres que sean los tiles del juego(256 diferentes simultáneos). La pantalla será entonces una matriz de 25*40 bytes (1000 bytes) y en cada uno de esos bytes te cabe un número entre 0 y 255, que es la posición del tile en el charset: posición 0->@, posición 1->A, etc ,etc...este número es el ScreenCode del Char
Es decir, aunque suene ANTINATURAL, para escribir una Z en la esquina zuperior izquierda de la pantalla tienes que pokear:Poke1024,26. La pantalla estándar está en $400->1024 y la Z es el screen code 26
Los colores de cada char están en $D800 y también son 1000 bytes porque la correspondencia es 1 a 1 con la pantalla....es un "gemelo" de la pantalla con el valor de sus colores (colores de pixels sólo, no de fondo). Es decir, el byte cero de la pantalla tiene un color representado en el byte cero de la ColorRam($D800 o 55.296). Vamos, que si quieres pintar la Z de antes de color blanco, tienes que poner POKE55296,1
Esta es la base de los tiles...pero puedes tener diferentes modos de tile además del "por defecto"....tienes el tile multicolor y el modo "con color de fondo extendido" que básicamente funcionan igual, pero con "ciertas peculiaridades"
-
El tema Tiles está tirado. EL C64 en modo "normal" está preparado para textos, luego puedes definir un juego de caracteres que sean los tiles del juego(256 diferentes simultáneos). La pantalla será entonces una matriz de 25*40 bytes (1000 bytes) y en cada uno de esos bytes te cabe un número entre 0 y 255, que es la posición del tile en el charset: posición 0->@, posición 1->A, etc ,etc...este número es el ScreenCode del Char
Es decir, aunque suene ANTINATURAL, para escribir una Z en la esquina zuperior izquierda de la pantalla tienes que pokear:Poke1024,154. La pantalla estándar está en $400->1024 y la Z es el screen code 154
Huumm, esto que explicas es para el manejo de chars normales, no? Los tiles son grupos de chars (2*2,3*3,etc) que es lo que aun no se aplicar
-
Es lo mismo, pero tienes que definir el TileSet de 2x2(por ejemplo) con la misma filosofía del charset.
Es decir, defines en memoria un lugar para esos tiles y los pones todos seguidos (lo mismo que el charset). Apuntarás por ejemplo, que el tile 0 es "abcd"....bueno, mejor dicho"1,2,3,4"...y así con todos uno tras otro
Tu pantalla de tiles tendrá ahora un tamaño de 20x12=240 bytes (procura no tener MáS de 255 tiles diferentes), que es MUCHO menos de 1000 bytes....es decir, se comprime la imagen
También tendrás que tener unas rutinas de pintado que cuando vean un cero, vayan a la tabla de tiles y lean"1,2,3,4"...y pinten en pantalla
AB
CD
...y tengan en cuenta que la pantalla de tiles tiene ahora 20 columnas y 12 filas
Esto es la base....pero puedes modificarla a conveniencia....por ejemplo....imagina que sólo tienes 16 tiles diferentes de 2x2. En cada Byte te caben 2 tiles, por lo que la definición de cada pantalla ahora será de 240/2 = 120 bytes, aunque la operativa de la "recuperación" se complica algo (no demasiado, para el espacio que se gana)
-
un tile de 3x3 yo JAMÁS lo definiría.....porque un ordenador "piensa" y almacena en binario, que es la matemática del 2,4,8,16, etc
Un 3x3=9 es MUCHO MAS complicado de gestionar porque los datos quedan totalmente "desalineados"...o si no, pierdes memoria metiendo ceros para "alinearlos"...y multiplicar por 3 o por 9 es mucho más complicado que por 2 o por 4
resumiendo..haría tiles de 1x1, 2x2, 4x4, 8x8, 4x2, etc
-
Es lo mismo, pero tienes que definir el TileSet de 2x2(por ejemplo) con la misma filosofía del charset.
Es decir, defines en memoria un lugar para esos tiles y los pones todos seguidos (lo mismo que el charset). Apuntarás por ejemplo, que el tile 0 es "abcd"....bueno, mejor dicho"1,2,3,4"...y así con todos uno tras otro...
Una vez que tienes claro esto y lo manejas con soltura (y siguiendo el ejemplo del tileSet de 2x2), YA CREAS EL CHARSET con el orden correcto: para el primer tile, el cero, defines en los 8x4=32 bytes el "dibujo de la A, la B, la C y la D"....y ya no tienes por qué tener un charset y un tileset "en paralelo"....tu programa en ensamblador verá el charset de 32 en 32 bytes y lo pintará en el orden y coordenadas correctas con los scripts definidos antes, ya que para la rutina de pintar, los chars son de 32 bytes y la definición de pantalla es de 20x12
Esto son ideas...si te interesa tener a la vez tiles de diferentes tamaños, no te queda otra que definir un tileset por tamaño....aunque el tamaño de 4x4, es en realidad de 2x2 de tiles de 2x2....jejeje...parece un trabalenguas, pero ahorras MUCHO espacio
Con varios tilesets de diferentes tamaños, ahora sólo te queda idear una manera de marcarlos de alguna manera en la definición de la pantalla para poder recuperarlos....para esto hay muchas técnicas diferentes y dependerá del número de tiles en cada tileset, de cuantos bits te quedan libres en cada byte para poder usarlos de FLAG o de marcador de tamaño de tile, etc...o quizás uses un criterio POSICIONAL, es decir, los 20 primeros tiles son de 2x2, los 20 siguientes de 8x8, etc
En esto de la informática, yo te aconsejo que vayas de lo fácil a lo difícil, es decir, intenta probar a definir un tileset de 2x2 sobre el charset estándar del C64 (para empezar) y vas creando poco a poco las rutinas y las vas complicando a medida que entiendes y dominas la base...yo te puedo soltar el chorizo de ensamblador y de fórmulas y de timings y no te enterarás de nada si te dan eso de salida
Aquí te podemos ayudar bastante en el proceso si vas sacando las dudas
-
Pues muchas gracias, haré mis pinitos en cuanto a los tiles con tus indicaciones, aparte de seguir con lo que estaba, me has dado faena ;D
-
Otra cosa importante, para cuando tengas que "definir" o "dibujar" el charset base de los tiles.
Hay dos rangos de memoria en el que no podrías meterlo, ya que el "cableado" del charset estándar te lo taparía, aunque el charset esté oculto (que es como está normalmente). Estos rangos son:
-$1000 a $1FFF (es decir el cableado del charset en el banco 0 del VIC)
-$9000 a $9FFF (es decir, el cableado del charset en el banco 2 del VIC)
Si te fijas, ambos cableados están en la posición relativa +$1000 y tienen $1000 bytes de tamaño, esto es 4096 bytes->4k->2k del charset "modo dibujo" y 2k del charset "máquina de escribir". Por lo tanto las posiciones 2 y 3 de las 8 posibles en el banco 0 y el banco 2, están PROHIBIDAS para la definición base del tileset. Tendrías que coger la 0,1,4,5,6 o 7 ....o usar otro banco
Observa que digo "prohibidas para un charset", ya que el cableado sólo afecta al charset que el VIC ve, en esas posiciones puedes poner código o definiciones de sprites o lo que sea, que puedes acceder a ello sin problemas
Esto aparece comentado el la Guía Oficial del Programador del C64 en 3.PROGRAMMING GRAPHICS - Graphic Locations - Character Memory (página 104)
-
No hay problema, ya hace tiempo me acostumbre a que el VIC apunte siempre al banco 1, así pongo los chars editados que necesite donde quiera dentro de ese banco
-
Apunta siempre al banco 0->0000 a 16384. Recuerda que el charset estándar está cableado entre 4096 a 8191 (posiciones 2 y 3 del VIC, de las 8 posibles)
-
a esto me refiero...
Y recuerda que en el banco 0, no debes poner el charset en la posición cero (ya que está la página cero, la pila y la pantalla en posición estándar). Y en la posición 1 tampoco (o con mucho cuidado y dejando sin definir los primeros chars), ya que en $800 (2048) se inicia el basic, por lo que si usas un cargador, ojo con no pisarle hasta que se haya ejecutado
-
jajaja....estoy constantemente corrigiendo....hablo de memoria y al mirar los papeles veo que he metido el cuezo!
Perdona por el caos
-
Cómo lo llevas @Laddh ?
Qué tal va la cosa, has avanzado algo?
-
Hola, pues de lo que pregunté y los tiles aún no he llegado, primero tengo que acabar de pulir el scroll de un bigmap de 4 pantallas en horizontal que ya he conseguido que los chars los muestre bien pixel a pixel pero no se porque el color me falla y produce unos destellos, y eso que hago doble buffer y no apunto a la pantalla hasta que esta hecho, te pongo el .prg para que lo veas, es más fácil de ver que explicar.
-
No sigo muy bien el tema pero la memoria de color no tiene doble bufer. Para cambios en la memoria de color, si tienes alguna interrupción raster, quizá cambiando el orden de ejecucion de los distintos bloques de código.
-
Hola, pues de lo que pregunté y los tiles aún no he llegado, primero tengo que acabar de pulir el scroll de un bigmap de 4 pantallas en horizontal que ya he conseguido que los chars los muestre bien pixel a pixel pero no se porque el color me falla y produce unos destellos, y eso que hago doble buffer y no apunto a la pantalla hasta que esta hecho, te pongo el .prg para que lo veas, es más fácil de ver que explicar.
Efectivamente @javierglez tiene razón: sólo hay una Color Ram en 55296 ($D800, ahí está toda la info del color, a no ser que estés en modo multicolor o enhanced background color o Bitmap(o cualquier modo "no oficial"). La manera correcta de proceder es ir pintando el siguiente fotograma en el dobble buffer (mientras usas el scroll hardware te suele dar tiempo), y, en el momento en que toque, hacer el scroll de la Color RAM (que los colores acompañen a los tiles) y redireccionar el VIC al nuevo frame. Hay que hacer un movimiento de 1000 bytes en la Color Ram, por lo que le da tiempo de sobra al 6510. La clave es CUANDO
Los 1000 bytes del color da tiempo de sobra a moverlos desde que el raster entra en la primera línea del borde inferior hasta que vuelve a entrar por la primera línea superior de la pantalla (la primera tras el borde superior). EL cambio de VIC al buffer es casi inmediato, eso si, como es casi inmediato hay que hacerlo cuando el raster esta saliendo por el borde inferior de la pantalla. Yo he hecho las dos cosas sin problema. Eso si, conviene al inicio del juego, coordinar las interrupciones por tiempo (las que tengas para música, sonido, lectura del teclado, etc) con las del raster, y darles la misma frecuencia.
Esta coordinación se puede hacer al arrancar el juego, y sería tan "sencillo" como programar una interrupción de raster en la primera línea del borde inferior, y justo en esa interrupción, cambiar la frecuencia de la interrupción por tiempo a la del Raster y poner el "cronómetro" a cero y eliminar la interrupción por raster (esto NO ES DEL TODO EXACTO, pero si ves que cada cierto tiempo hay flickering, puedes ir corrigiéndolo, en las muertes, en los cambios de fase, etc...) De esta manera, en cada interrupción puedes hacer lo que sea necesario, tanto de gráficos como de cualquier otra cosa (sonido, animaciones, movimiento de sprites, etc)
@Laddh , si puedes pásanos mejor el código fuente o un archivo .d64 con los binarios (aunque esto último es más incómodo, ya que habría que descompilar, etc... si optas por archivo binario, no estaría de más un archivo de etiquetas o un mapa de memoria del juego etc...para que se puede entender bien el desensamblado
-
Veo que la rutina del movimiento de bytes está en $8c0 y que usas el modo de direccionamiento indirecto indexado. Veo además que intentas pintar el buffer y mover el color A LA VEZ, y por eso el raster te pillla enseguida. La mejor estrategia es pintar los tiles en el buffer en momentos en los que el procesador "está libre" mientras usas el scroll hardware (tienes más de un frame para hacerlo). Y en el momento que el Raster toca el borde inferior, hacer el scroll SOLO del color y cambiar de pantalla a buffer y vuelta a empezar.
También veo que debes tener dos espacios de 1000 bytes para mover el color: uno un buffer de lectura (puntero en $f7) y el otro de escritura en el D800 (puntero $f9)....a ver creo que sólo necesitas leer el buffer de color para la línea de tiles que entra. El resto de bytes YA ESTAN EN LA PANTALLA, con lo que los puedes mover de una forma mucho más rápida que con el indirect indexed....la Color RAM SIEMPRE está en $D800, no te hace falta una Indirect Indexed, ya que tienes que coger un tile en la color ram, pongamos que en $D805 y ponerlo en $D804 (o viceversa, según el scroll se mueva a derecha o izquierda) y repetirlo 1000 veces.
Si no quieres cambiar la rutina de mover el color, lo que si puedes hacer es empezar a mover el color Justo cuando el ráster entre en la primera fila de pixels de la segunda línea de tiles ($D828) e ir POR DETRÁS DE ÉL...con lo que tendrás MUUUUCHO mas tiempo que esperando a que esté en el borde inferior. Sólo deberías esperar a este momento justo para cambiar pantalla por buffer, ya que tarda unos 5 ciclos de reloj (el tiempo que tardas en cambiar el valor del screen pointer)
-
Je, te me has adelantado, te estaba escribiendo esto:
Te he aislado el programa solo con la parte que concierne al scroll para clarificar mejor.
Las rutinas importantes son las Bigmap, que escriben la pantalla entera en $4400 o $6400 (trabajo con el banco 1) después del scroll por hardware y a la de color.
Con el JOY 2 te mueves izq y der.
En $a000 esta en mapa de 4 pantallas de chars creado con el charpad y en $b000 el mapa de color, en $7000 los chars.
; 10 SYS (2064)
*=$0801
BYTE $0E, $08, $0A, $00, $9E, $20, $28, $32, $30, $36, $34, $29, $00, $00, $00
*=$0810
zp=$f9
zs=$fb
screen=$4400
screen2=$6400
maptab=$a000
zpc=$f7
zc=$fd
colortab=$b000
color=$d800
screen_control_register1 = $d011
screen_control_register2 = $d016
lda 1 ;quita el basic
and #%11111110
sta 1
jsr PANCHAR
jsr pantalla
jsr int
init jsr bigmap1
jsr bigmap2
LDA $D018
AND #15
ORA #144 ;POSICIÓN PANTALLA DENTRO DEL BANCO1 $6400
STA $D018
LDA screen_control_register2
AND #$F7 ;38 columnas
STA screen_control_register2
lg jsr raster_wait ;Loop game
jsr PlayerControl
jmp lg
PlayerControl
lda #4 ;Read LEFT on joystick port 2
bit $dc00
bne NotDENLeft
jsr right ;muevecajai
NotDENLeft
lda #8 ;Read RIGHT on joystick port 2
bit $dc00
bne NotDENRight
jsr left ;muevecajad
NotDENRight
rts
bigmap1
lda #<maptab
sta zp
lda #>maptab
sta zp+1
lda #<colortab
sta zpc
lda #>colortab
sta zpc+1
fixcol lda cornrx
clc
adc zp
sta zp
lda #0
adc zp+1
sta zp+1
lda cornrx
clc
adc zpc
sta zpc
lda #0
adc zpc+1
sta zpc+1
lda #<screen
sta zs
lda #>screen
sta zs+1
lda #<color
sta zc
lda #>color
sta zc+1
lda lines
sta countr
storlp ldy cols
inloop lda (zp),y
sta (zs),y
lda (zpc),y
sta (zc),y
dey
bpl inloop
clc
lda zp
adc width
sta zp
lda #0
adc zp+1
sta zp+1
clc
lda zs
adc #40
sta zs
clc
lda zpc
adc width
sta zpc
lda #0
adc zpc+1
sta zpc+1
clc
lda zc
adc #40
sta zc
bcc fdg
inc zs+1
inc zc+1
fdg dec countr
bpl storlp
rts
bigmap2
lda #<maptab
sta zp
lda #>maptab
sta zp+1
lda #<colortab
sta zpc
lda #>colortab
sta zpc+1
fixcol2 lda cornrx
clc
adc zp
sta zp
lda #0
adc zp+1
sta zp+1
lda cornrx
clc
adc zpc
sta zpc
lda #0
adc zpc+1
sta zpc+1
lda #<screen2
sta zs
lda #>screen2
sta zs+1
lda #<color
sta zc
lda #>color
sta zc+1
lda lines
sta countr
storlp2 ldy cols
inloop2 lda (zp),y
sta (zs),y
lda (zpc),y
sta (zc),y
dey
bpl inloop2
clc
lda zp
adc width
sta zp
lda #0
adc zp+1
sta zp+1
clc
lda zs
adc #40
sta zs
clc
lda zpc
adc width
sta zpc
lda #0
adc zpc+1
sta zpc+1
clc
lda zc
adc #40
sta zc
bcc fdg2
inc zs+1
inc zc+1
fdg2 dec countr
bpl storlp2
sale2 rts
left
ldx cornrx
cpx maxx
beq sale2
LDX screen_offset
DEX
STX screen_offset
CPX #$FF
BEQ continue
JMP end
continue
LDX #$07
STX screen_offset
jsr move_rows_left
end
LDA screen_control_register2
AND #$F8
ORA screen_offset
STA screen_control_register2
rts
move_rows_left
inc cornrx
jsr swap_bigmap
jsr swap_video
sale3 rts
screen_offset byte $07
right
ldx cornrx
beq sale3
LDX screen_offset_r
inx
STX screen_offset_r
CPX #8
Beq continuer
JMP endr
continuer
LDX #$00
STX screen_offset_r
jsr move_rows_right
endr
LDA screen_control_register2
AND #$F8
ORA screen_offset_r
STA screen_control_register2
@sal rts
move_rows_right
dec cornrx
jsr swap_bigmap
jsr swap_video
rts
screen_offset_r byte $00
swap_video
lda cp
beq pantalla1
bne pantalla2
rts
pantalla1
LDA $D018
AND #15
ORA #16 ;POSICIÓN PANTALLA DENTRO DEL BANCO1 $4400
STA $D018
lda #1
sta cp
rts
pantalla2
LDA $D018
AND #15
ORA #144 ;POSICIÓN PANTALLA DENTRO DEL BANCO1 $6400
STA $D018
lda #0
sta cp
rts
cp byte 0
swap_bigmap
lda bm
beq bm1
bne bm2
rts
bm1
jsr bigmap1
lda #1
sta bm
rts
bm2
jsr bigmap2
lda #0
sta bm
rts
bm byte 0
raster_wait ;espera línea raster
l LDA #$ff
CMP $D012
BNE l
BIT $d011
BMI l
rts
PANCHAR LDA 56578
ORA #3 ;PREPARAMOS PARA SELECCIONAR EL @@@
STA 56578
LDA 56576
AND #252
ORA #2 ; @@@ BANCO DE VIDEO 1 (16384)
STA 56576
; COMO MEMORIA PANTALLA SE QUEDA EN SU POSICIÓN POR DEFECTO, NO LA CAMBIAMOS
; LDA $D018
; AND #15
; ORA #16 ;POSICIÓN PANTALLA DENTRO DEL BANCO
; STA $D018
; SI QUISIERAMOS EL CURSOR
; LDA #68 ;CURSOR PANTALLA EN BANCO 1
; STA 648
LDA $D018
AND #240 ;ESTABLECEMOS EL MODO CARACTER
ORA #12 ;BUSCA CARACTERES A PARTIR DE 12288 + DIR BANCO 1
STA $D018
; LDA $D016
; ORA #16 ;MODO CARACTER MULTICOLOR
; STA $D016
RTS
pantalla
lda #11
sta $d020
sta $d021
lda #8
sta $d022
lda #10
sta $d023
rts
INT sei
lda #<n1
sta $0314
lda #>n1
sta $0315
; lda #$00
; jsr $1000 ;Initialize music
lda #$7f
sta $dc0d
sta $dd0d
lda #$01 ;IRQ speeder
sta $d01a
cli
RTS
N1 asl $d019 ; IRQ speeder again
lda $dc0d
sta $dd0d ; Stabilize CIA
; jsr $1003;Play the music
jmp $ea31 ;7e
width byte 160
height byte 22 ;25 normal total lineas pantalla vertical
lines byte 21;22-1
cols byte 39 ;40-1
cornrx byte 0
cornry byte 0
maxx byte 120 ;160-40 total mapa x menos pantalla (40 carac)
maxy byte 0 ;25-25 total mapa y menos pantalla (25 carac)
countr byte 0
countr2 byte 0
*=$7000 ;28672 ;CARACTERES EN BANCO 1 (12288 + 16384)
incbin "chars2.bin"
*=$a000
incbin"map.bin"
*=$b000
incbin"colormap.bin"
-
Varias ideas que te pueden ayudar:
-Pon música e interrupciones raster en la misma rutina de interrupción y coordínalas. Eso es mejor que esperar al raster, que tienes al procesador ocioso esperando el momento (raster_wait). De esta forma, coordinando ambas cosas, no pierdes tiempo. Si al entrar en la rutina de interrupción ves que hay que hacer el scroll de color y cambiar pantalla por buffer, pues lo haces. Si no, pues no....usando las variables que tienes mismamente lo podrías hacer
-Para hacer el scroll de color VE POR DETRÁS del raster...es decir, cuando el ráster esté pintando la segunda fila de tiles, empieza a mover el color de la primera fila....ganarás un tiempo enorme. Y justo al final del scroll de color, cambia el pointer de la pantalla. Lo más seguro es que se haga con el raster fuera de pantalla y no se note. Esto es ya es cuestión de AJUSTE FINO (o de renunciar a un fps de 60. Hasta 21 fps la percepción del scroll es suave).Por lo tanto, me desdigo del rollo anterior y sincroniza las interrupciones con el ráster entrando en la segunda fila de chars.
-Ve pintando el buffer con el frame siguiente mientras usas el scroll hardware. Por ejemplo, si pintas 1/3 de pantalla cada vez, lo tienes listo en 3 frames y luego el procesador está libre para otras cosas
-Investiga o intenta crear una rutina de movimiento de color/tiles más eficiente que una indirecta indexada...si vas ganando 1 ciclo en cada pixel, cada 4 pixels te sale uno de gratis. Por ejemplo, en vez de usar indirect indexed, puedes probar una absoluta que se vaya automodificando (y ganas 1 ciclo por cada operación de lectura o de escritura)....como vas a mover 1000 bytes, necesitas hacer 1000 operaciones de lectura y 1000 de escritura.....la diferencia es NOTABLE. Además es una rutina CRUCIAL. En un rato te pongo un ejemplo
-
Mira esta rutina, que es una rutina de esas que son bucles "desenrollados". Tómalo como un ejemplo, fijo que hay rutinas mucho mejores
La primera columa es la dirección de memoria en la que se aloja. La segunda columna los bytes que ocupa. La tercera columna es el tiempo que tarda (en ciclos de procesador). La cuarta no influye...es el número de línea
Cada par de LDA/STA es una línea, luego este bloque se repetirá 25 veces y ocupa 6 bytes. Entonces tienes una rutina de 25*6 + 2 + 6 = 158 bytes...es asumible en términos de espacio.
cada bloque de LDA/STA tarda unos 10 ciclos. por lo tanto 25 líneas tardarán 250 ciclos. Como la rutina se repite 38 veces (ldy #39 estaría mal), tarda en moverte los 1000 bytes de color = 38 * 250 = 9500 ciclos
-
Analicemos ahora la tuya, teniendo en cuenta sólo que movemos color:
En términos de espacio ocupa $947- $91D = $2A = 42 bytes....ahorro importante de espacio
Analicemos el tiempo:
el bloque $920-925 se repite 39 veces por línea. Una ejecución tarda 18 ciclos, luego una línea tarda 18*39 = 702. Como son 25 líneas de color, ese bloque tarda 25*702 = 17550 ciclos.
el otro bloque se repite 24 veces (1 por línea). Como el bloque tarda unos 44 ciclos aprox -> 44 *24 = 1056 ciclos.
Por lo tanto, en mover 1000 bytes tardas 1056 + 17550 = 18606
es decir, tardamos 18606 ciclos frente a 9500....es algo menos del doble de tiempo....creo que puede compensar si no andas PILLADÍSIMO de espacio
-
Ahora vamos a hacer un cálculo "poco fino".
El raster tarda en cada frame 1/60 segundos = 0,0167 segundos
Tu rutina inicial tarda en ejecutarse 18606 ciclos/1000000 ciclos/segundo = 0,0186 segundos (te pilla)
Con la rutina "Desenrollada" tardas 9500 ciclos/1000000 = 0,0095 segundos (te libras y tienes tiempo de sobra de meter la nueva columna de color por la derecha o por la izquierda)
Luego compensa sacrificar 158*2 = 316 bytes (158 en scroll left y 158 en scroll right)
O puede que no.....que andes pillado de memoria y prefieras sacrificar framerate...
-
Otra buena opción es coger la rutina "desenrollada" y probar a convertirla en una rutina Automodificable. Es decir, cada 38 repeticiones del bloque, sumas 40 a $801 y lo sobreescribes. Le restas uno y lo sobreescibes a $800 y vuelves a lanzar el blucle....así 25 veces
La rutina será algo más lenta (aún así más rápida que una indirect indexed, me atrevería a decir) pero ocupará MUCHO MENOS de los 158 bytes
...y antes de ejecutar la rutina, tienes que volver a poner $801 en la memoria $94B-$94C y 800 en $94E-$94F (para hacer eso pondrías etiquetas). Por ejemplo
source:
lda $801,y
target:
sta $800,y
el Low byte de $801 estaría en source+1($01) y el high byte en source+2($08) (ya que las instrucciones del 6510 son de 1 byte). Lo mismo para $800 (target+1($00) y target+2($08))
-
Y si desarrollas en PC...pues te aconsejo que aprendas a manejar el C64 debugger.....es ULTRAPOTENTE y puedes ver en directo todas estas cosas
Un artículo que habla de él y te da los links de descarga
https://programacion-retro-c64.blog/2022/08/07/c64-debugger/
Usándolo, te puedo decir que el raster te pilla en la tercera línea de tiles cada vez que haces scroll....por eso se ven esas cosas raras cuando mueves bytes
-
Otra cosa que no sé si sabes @Laddh!
Algo tan inocente como esto que pongo en la imagen...lo compilo y....MIRA EL TAMAÑO. Te lo digo porque lo he visto en tu main.prg, que vas metiendo sprtiteSheet, charset, etc, en distintos lugares con la etiqueta *=
entre el LDA #4 y el LDA #5, el programa llena todo de ceros....es decir tenemos un programa de 4 bytes útiles, y el resto de los 47.107 son ceros que van a la cinta/diskette y luego van a la memoria.
Si quieres cargar cosas diferentes en diferentes bloques sin llenar de ceros todo lo de enmedio, hay que hacer varios files en binario y un loader que los vaya cargando
-
Aquí se puede ver el archivo con la BURRADA en todo su esplendor: 47K de ceros (salvo 6 bytes)
Los dos primeros(01 08, recuadrados en morado) que es la dirección en donde va a meter el programa al cargar ($801), los dos segundos (a9, 04, que es LDA #$04).....luego un montón de ceros y los dos ultimos bytes, 47 K de ceros después (a9, 05, que es LDA #$5)
Así que OJO!!!
-
Estos programas tipo ICU64 y el retrodebuguwr y el C64Debuguer…. No me tiran en condiciones.
Además… me parecen muy complicados para entender lo que sucede.
A veces los empleo para ver donde se van cargando los bloques de memoria, de manera visual, pero en cuando empieza a ejecutarse el programa… ya es un lío para seguimos.
Habría que hacer un programa en YouTube de cómo usarlos y sacarles un poco de jugo.
-
Buuuffff! Que porrón de información..., tengo que releerme con tranquilidad todo el hilo y ver si lo puedo ir aplicando.
Gracias @SingletonJohn, de verdad, tengo entretenimiento para rato ;)
-
Ah! en cuanto a lo del espacio vacío entre una cosa y otra, no hay problema, se que lo voy a llenar!
-
Estos programas tipo ICU64 y el retrodebuguwr y el C64Debuguer…. No me tiran en condiciones.
Además… me parecen muy complicados para entender lo que sucede.
A veces los empleo para ver donde se van cargando los bloques de memoria, de manera visual, pero en cuando empieza a ejecutarse el programa… ya es un lío para seguimos.
Habría que hacer un programa en YouTube de cómo usarlos y sacarles un poco de jugo.
El C64Debugger lo conozco bien y es una PASADA. Pero hay que dedicarle tiempo. Coger el manual, cargar el debugger (a ser posible con programas hechos por ti o alguno sencillo) y ponerse a cacharrearlo
Ah! en cuanto a lo del espacio vacío entre una cosa y otra, no hay problema, se que lo voy a llenar!
:):):)