Commodore manía
Commodore 64 => Desarrollo => Mensaje iniciado por: i03862 en Noviembre 27, 2018, 18:00:50
-
Hola a todos los commodorianos. Es mi primera vez en el foro y me gustaria que alguien me ayudara
para resolver un problemilla que me esta voviendo loco. He hecho un programa para sacar un scroll
horizontal pero no es estable (tiembla). He metido el codigo de control del scroll dentro de la
interrupcion y tambien por fuera (en el bucle principal) y sigo teniendo el mismo problema. Mando
el codigo para ver si alguna alma samaritana me puede echar un cable. Muchisimas gracias de
antemano
;*************************************************************
;* SCROLL FINO CONTROLADO POR JOYSTICK EN PUERTO 2
;*************************************************************
scrloc01 = 1384 ; ultima columna de la pantalla
scrloc02 = 1424
scrloc03 = 1464
scrloc04 = 1504
scrloc05 = 1544
scrloc06 = 1584
scrloc07 = 1624
scrloc08 = 1664
scrloc09 = 1704
scrloc10 = 1744
scrloc11 = 1784
scrloc12 = 1824
scrloc13 = 1864
scrloc14 = 1904
scrloc15 = 1944
scrloc16 = 1984
joy2 = 56320 ; Joystick puerto 2
xfine = $fb ; Numero de pixels a desplazar
column = $fc ; Puntero al siguiente dato a "pokear"
irqexit = $ea81 ; Rutina de interrupción del Kernal
;
!to "scroll.prg",cbm ; tipo de CPU ( C-64 )
;
*= $c000 ; Direccion de comienzo
;
init lda #$07 ; Inicializa variables
sta xfine
lda #$00
sta column
sei ; Desactiva interrupciones del sistema
lda #$00
sta $d020 ; Color de borde a negro
lda #147
jsr $ffd2 ; borra la pantalla
lda #$7f
sta $dc0d ; Desactiva teclados reloj, etc
lda #<irq1
ldx #>irq1
sta $314 ; Prepara la 1ª interrupcion IRQ
stx $315
ldy #$1b
sty $d011 ; Pone la primera linea raster
lda #$01
sta $d01a ; Activa eh tipo de interrupción (raster)
cli ; Activa interrupciones del sistema
;
; Main loop
;
hold jsr charplot ; Pokea los datos en pantalla
jmp hold ; bucle sin fin
;
; Custom IRQ routines
;
irq1 inc $d019 ; Reconoce interrupciones raster
lda #$00
sta $d012 ; 1º linea raster (comienzo de la zona de scroll)
lda #$01
sta $d021 ; Pone el color de la pantalla a blanco
lda #<irq2
ldx #>irq2
sta $314 ; Prepara la segunda interrupción raster
stx $315
;
lda xfine ; Codigo de scroll fino
sta $d016
lda joy2 ; Lee el joystick
and #15
cmp #$07 ; A la derecha?
beq scroll ; Si, hace el scroll
jmp irqexit ; No, salta al sistema
;
scroll lda column ; Chequea el final del los datos a "scrolizar"
cmp #$ff ; Limite alcanzado?
bne goscroll ; No, sigue haciendo el scroll
jmp irqexit ; Si, final del scroll
;
goscroll
lda xfine ; Lee el flag de desplazamiento fino
sec
sbc #$01 ; velocidad del scroll
and #$07 ; Este trozo solo hace eso : desplaza la información de
sta xfine ; pantalla 7 a 0 Pixels (scroll de derecha a izquierda)
jmp irqexit ;
;
irq2 inc $d019 ; Reconoce interrupciones rastree
lda #$60
sta $d012 ; 2º linea raster
lda #$08
sta $d016 ; Zona de pantalla fija (para títulos, puntos, récords, etc)
lda #$03
sta $d021 ; Pone el color de pantalla a azul claro
lda #<irq1
ldx #>irq1
sta $314 ; Vuelve a poner la 1º rutina IRQ
stx $315
jmp irqexit ; Sale al sistema
;
; Plot & scroll chars routine
;
charplot
lda xfine ; Comprueba la posición del scroll (Pixels)
beq endsec ; Ha llegado a 0? Entonces hace scroll completo de caracteres
jmp nomove
endsec ldx #$00 ; Scroll completo de caracteres
wrapmsg lda scrloc01+1,x
sta scrloc01,x
lda scrloc02+1,x
sta scrloc02,x
lda scrloc03+1,x
sta scrloc03,x
lda scrloc04+1,x
sta scrloc04,x
lda scrloc05+1,x
sta scrloc05,x
lda scrloc06+1,x
sta scrloc06,x
lda scrloc07+1,x
sta scrloc07,x
lda scrloc08+1,x
sta scrloc08,x
lda scrloc09+1,x
sta scrloc09,x
lda scrloc10+1,x
sta scrloc10,x
lda scrloc11+1,x
sta scrloc11,x
lda scrloc12+1,x
sta scrloc12,x
lda scrloc13+1,x
sta scrloc13,x
lda scrloc14+1,x
sta scrloc14,x
lda scrloc15+1,x
sta scrloc15,x
lda scrloc16+1,x
sta scrloc16,x
inx
cpx #$28
bne wrapmsg
ldy column
lda tab01,y ; Pone nueva información en la columna 40 (oculta)
sta scrloc01+39
lda tab01,y
sta scrloc02+39
lda tab01,y
sta scrloc03+39
lda tab01,y
sta scrloc04+39
lda tab01,y
sta scrloc05+39
lda tab01,y
sta scrloc06+39
lda tab01,y
sta scrloc07+39
lda tab01,y
sta scrloc08+39
lda tab01,y
sta scrloc09+39
lda tab01,y
sta scrloc10+39
lda tab01,y
sta scrloc11+39
lda tab01,y
sta scrloc12+39
lda tab01,y
sta scrloc13+39
lda tab01,y
sta scrloc14+39
lda tab01,y
sta scrloc15+39
lda tab01,y
sta scrloc16+39
inc column
lda #$07
sta xfine
nomove rts
;
; Datos gráficos para el scroll
;
tab01 !byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
!byte 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60
!byte 61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88
!byte 89,90,91,82,83,84,85,86,87,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112
!byte 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133
!byte 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154
!byte 155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175
!byte 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196
!byte 197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217
!byte 218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238
!byte 239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,32,0,0,0,0
-
Yo lo que veo es que haces el scroll de caracteres cuando el registro del scroll fino está a 0 y no sé si eso te funciona en absoluto a la que sueltas el joystick y se queda en 0, pero en todo caso tendrias que hacer el scroll de caracteres cuando pasa de 0 a 7.
Una opcion sería hacerlo en el momento añadiendo dos lineas en goscroll:
goscroll
lda xfine ; Lee el flag de desplazamiento fino
sec
sbc #$01 ; velocidad del scroll
and #$07 ; Este trozo solo hace eso : desplaza la información de
sta xfine ; pantalla 7 a 0 Pixels (scroll de derecha a izquierda)
-> bcs @noschar ; si no paso de 0 a 7 no scroll de caracteres
-> jsr endsec ; ahora charplot empieza en endsec
@noschar jmp irqexit
Otra opcion es que utilices una variable que haga de bandera y entonces puedes llamar a charplot cuando te de la gana. Como estas modificando todas las lineas de la pantalla en paralelo lo mejor seria hacer los cambios cuando el raster deja el area visible, sera la linea 250 aunque no se exactamente.
goscroll
lda xfine ; Lee el flag de desplazamiento fino
ldx #1
sec
sbc #$01 ; velocidad del scroll
and #$07 ; Este trozo solo hace eso : desplaza la información de
sta xfine ; pantalla 7 a 0 Pixels (scroll de derecha a izquierda)
-> bcs @noschar ; si no paso de 0 a 7 no scroll de caracteres
-> dex
->@noschar stx bandera
jmp irqexit
y luego en charplot
charplot
-> lda bandera ; Comprueba la posición del scroll (Pixels)
beq endsec ; Ha llegado a 0? Entonces hace scroll completo de caracteres
jmp nomove
-> endsec dec bandera
ldx #$00 ; Scroll completo de caracteres
wrapmsg lda scrloc01+1,x
...
-
Yo hace poco he aprendido a mover scroll suave a toda la pantalla gracias a Laddh, no he revisado tu listado ya que todavia estoy pichón en el tema, a mi alguna vez me ha hecho lo que tu cuentas.
Un primer consejo es anular (no eliminar) posibles rutinas que afecten al scroll, de esta forma puedes localizar donde esta el problema en el caso de que alguna rutina (que no sea del scroll) le afecte.
Yo por ejemplo no utilizo las interrupciones para el scroll, las utilizo solo para la musica, no se si utilizas raster en el Mainloop, haciendo lo que te digo yo me di cuenta que el Raster me producía temblores en el scroll, anunlandole no me temblaba, también podría ser que alguno de los acumuladores del scroll se te sobrecarge al ser utilizado por rutinas externas.
Cuanto mas recargas un programa de rutinas es mas probable que te lo haga y necesites utilizar los acumuladores X o Y,...prueba la rutina por si sola sin rutinas externas del tipo (comportamiento de enemigos, marcador, rutinas motores, etc), con todo eso aislado el scroll te deberia de ir correcto, si no es así puede que tengas algun error en la rutina.
Como te digo, aisla rutinas externas hasta que veas cual le afecta y empieza por ahí, a ver si Laddh te puede ayudar, yo si no dieras con el problema te puedo pasar la rutina que utilizo yo.
Saludos.
-
Yo casi aseguraría que el problema está en que estás dibujando caracteres por delante y por detrás del raster.
Las variables scrloc01....16, las estás usando para intentar pintar en toda la pantalla a la vez, incrementando solo x.
Eso hace que estés poniendo caracteres en muchas "y" distintas, tanto si ha pasado el raster por allí, como si no.
Es decir, para x=0, dibujas en srcloc01,x .Suponte que en ese momento el raster está exactamente en esa posición.
Empiezas a dibujar en srcloc02,x , luego en 03,x.. Esas posiciones están más abajo.Sin embargo, el raster sigue pintando la fila donde está srcloc01.
Posiblemente, cuando incrementas x, y vuelves a srcloc01,x , el raster, de las 8 lineas que tiene que pintar para esa fila, le ha dado tiempo a pintar 2 o 3.
Y ahora actualizas esa fila, que está a medio dibujar por el raster, y vuelves a ir hacia abajp.
Cuando vuelves a pintar en todos los srcloc0X, y vuelves al 01, el raster ya ha pasado por ahi.Esa linea no te va a dar problemas ya (aunque no es la correcta), sino que vas a alcanzar el raster una línea más abajo (en 02)
Y eso es por lo que sale el patrón en diagonal. El raster viaja de izquierda a derecha, y tú estás pintando de arriba a abajo.
En el código que subí en este post (https://commodoremania.com/foro/index.php/topic,1787.msg32679.html#msg32679), aún no uso scroll fino, porque buscaba velocidad pintando un mapa de tiles (ahora busco tiempo para implementar metatiles). Ese código se basa en dibujar siempre por detrás del raster, y no tiene parpadeos, sin usar doble buffer.
Pero, para no "adelantar" al raster, si en la parte de arriba de la pantalla (40 caracteres), hay 10 tiles, pinto la primera fila de los 10 tiles, luego la segunda fila de los 10...Si pintara el primer tile completo, luego el segundo, etc, estaría pintando por delante y por detrás del raster.
De todas formas, ten en cuenta que ese modelo de pintado, aunque "cómodo" (sólo hay que actualizar x), cuando pongas un mapa real, muy posiblemente no lo puedas usar.
-
Saludos Dashiad, hace poco me di cuenta que tenia un mensaje privado del Foro tuyo, perdona no haberte contestado antes, es que soy un desastre con este tipo de mensajes de todos los portales, por eso disculpa.
Como habras leido ya voy moviendo un scroll y siempre me acuerdo de tí, tengo ganas de verte para enseñartelo, recuerda la promesa que tenemos,...jajaja,ja,ja
Un abrazo!
-
Muchas gracias a todos por la rapida respuesta. Si, la rutina en si no esta nada optimizada. La primera version
de este codigo tenia la rutina de scroll fino y el dibujo de caracteres dentro de la misma interrupcion y era
logico que temblara (demasiado que procesar para el raster) pero cuando saque la rutina de dibujo fuera,
me sorprendio tener casi el mismo resultado. He leido con atencion la respuesta de Dashiad y creo que se
por donde van los tiros. De todas formas, estoy implementando una nueva rutina de "ploteo" de caracteres,
creo que menos intensiva de calcular, y que me va a permitir tener un scroll continuo en cualquier direccion,
(bueno eso espero ;)). En cuanto tenga algo factible, la publico por aqui.. Y, otra vez, gracias por vuestra
ayuda..
-
Otra cosa mas, Por cierto Rulas, he visto tus videos en YouTube sobre tus logros con esta maravillosa
maquina. Ojala yo pueda ir por el mismo camino. Yo tambien vivo en Madrid. Una cosa que podriamos
hacer es apuntarnos (los que podamos o queramos) a una quedada para intercambiar ideas, experiencias
sobre el desarrollo de programas para nuestro querido C64 (o el Amiga del cual soy tambien forofo!).
Seria interesante ver y compartir los desarrollos sobre todo de juegos.
-
Yo vivo en Madrid, y me apunto a cualquier quedada sobre programación del C64!! Cuando lo hacemos?
-
Dashiad : Genial, yo ahora estoy de trabajo hasta arriba pero en unos dias tengo vacaciones asi que ya nos
ponemos en contacto a traves de este foro. Por cierto, he leido por ahi que se pueden mandar mensajes
en privado. Lo digo por el tema de darnos el whatsapp para contactar que publicamente, no me gusta
mucho la idea. Bueno, ya lo vamos preparando. Otra cosa, lo prometido es deuda. En mi mensaje anterior
dije de mandaros una rutina para hacer scroll (de caracteres)un poco mas optimizada que la anterior,a ver que os parece. Bueno, ahi va...
charsrcl
ldy column
ldx #0
fill lda line0,y
sta 1024,x
lda line0,y
sta 1064,x
lda line0,y
sta 1104,x
lda line0,y
sta 1144,x
lda line0,y
sta 1184,x
lda line0,y
sta 1224,x
lda line0,y
sta 1264,x
lda line0,y
sta 1304,x
lda line0,y
sta 1344,x
lda line0,y
sta 1384,x
lda line0,y
sta 1424,x
lda line0,y
sta 1464,x
lda line0,y
sta 1504,x
lda line0,y
sta 1544,x
lda line0,y
sta 1584,x
lda line0,y
sta 1624,x
lda line0,y
sta 1664,x
lda line0,y
sta 1704,x
iny
inx
cpx #40 ; Limite de 40 columnas ?
bne fill
rts
;
; Datos
;
column !byte 0 ; numero de columna a pintar en pantalla
;
line0 !byte 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,22,24,25
!byte 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47
!byte 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69
!byte 70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91
!byte 92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109
!byte 110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125
!byte 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141
!byte 142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,156
!byte 158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173
!byte 174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189
!byte 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205
!byte 206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221
!byte 222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237
!byte 238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253
!byte 254,255,0,0,0,0,0,0,0,0,0,0
La cosa esta en que si incrementas el valor de "column" el scroll es de derecha a izquierda
y si lo dercrementas, el scroll es al reves..
Tengo que probarla insertandola en un scroll fino a ver que tal va. Tengo por ahi una
rutina de raster estable que tiene muy buena pinta. Vamos a ver como va la cosa..
Os cuento en breve....
-
Por lo que veo, es una variación de las rutinas de limpiado de pantalla.
Pero mientras no controles donde está el raster, y dónde pintas, lo normal va a ser que te parpadee.
Estás fijando el mapa a una lista de bytes sobre la que vas iterando.Sin embargo, un juego que tenga scroll, muy posiblemente vaya a requerir un mapa más complejo.En cuanto se complica la forma en la que está el mapa en memoria, el desenrrollar bucles empieza a no ser tan sencillo...
Ahora mismo, tienes una indirección (usando x), sobre la memoria de pantalla, y una indirección (usando y), sobre el mapa. El mapa es "procedural", ya que se "genera" a través de código (el registro y hace overflow y comienza otra vez desde cero).
Si lo que tienes es un mapa real en memoria, incluso si está 100% descomprimido, ( o sea, tienes el mapa entero, carácter a caracter, en memoria), no vas a poder pintarlo así. Y aquí es donde empiezan a sumarse ciclos al código.
Lo normal es que tengas un mapa basado en tiles de 4x4, 5x5 u 8x8...Y, si tienes metatiles (grupos de 4x4 tiles), el mapa está guardado como secuencias de metatiles, que hay que resolver a sus tiles, que hay que resolver a los caracteres, y entonces pintar en pantalla. Y es aqui donde empiezas a perder ciclos de reloj, sobre todo si también tienes que pintar la memoria de color.
-
Pasadas las Navidades, abrimos un Hilo y organizamos una quedada de Coders, que siempre se aprenden cosas y pasamos un raro pipa.
-
Yo este finde voy a la Feria del Juguete antiguo en Delicias, el museo del ferrocarril,..el finde que viene me voy a la Feria nacional del Scalextric, Foroslot y luego ya nos metemos en navidades, por eso ahora estoy un poco liado de actividades.
Lo dicho, pasadas las navidades organizamos una quedada, aunque solo sea tu y yo, ojala se apunte mas gente interesada en aprender y lanzarse a programar.
-
RULAS, por mi de acuerdo lo de la quedada. Mejor despues de las Navidades, Dashiad me mando un mensaje diciendo que tambien estaba de acuerdo. En enero vamos concretando el tema. ¡Perfecto!
DASHIAD, ¡Uff..me estoy perdiendo! Alla, a finales de los 80, hice algunas cosillas con scrolling fino y no
utilizaba tiles ni double-buffer pero, despues de tantos años ni me acuerdo como lo hice. No llego a
comprender el significado de los tiles y de como usarlos (despues de tanto tiempo me siento un poco
"pardillo" en esto). Creo que utilizaba un mapa (parecido a los que se crean en el C64prg_Studio o sea
sequencias de caracteres organizados en filas y con un ancho de mapa de 256 columnas, es decir:
linea 1 AGRTRTG5BCDEDEFRDFRFFGGGHHHHJJ...............JJKJJ
linea 2 GLREYHLRTYREKDFKDFKREMGFMTYYUU...............JUJU
linea ..........
linea 15 GFREREGRTHTYJYTJTYJTYUJTYJTYJYTJKK..............UTYJJ
Cada letra en mayusculas es un caracter modificado y entonces leia secuencialmente dichas lineas
y las pintaba en pantalla. Como viste en el 1º listado, el control del registro de scroll lo hacia dentre
de la rutina de interrupcion y el "ploteo" de caracteres lo hacia fuera, en el bucle principal. Por
supuesto, todo esto te lo estoy contando arañando lo mas que puedo del baul de mis recuerdos ;)
por eso todo lo que me estas contando me suena un poco a chino.
Si alguien pudiera pasarme algun codigo, por pequeño que sea, me ayudaria mucho a comprender todo
este tema. ¡O por lo menos algun sitio en internet que pudiera sacar algo claro!. yo he estado buscando
y lo unico que he visto son los "rants" de Cadaver pero es demasiado complicado para mi
!Os lo agradeceria en el alma.. ??? ???.!
-
Que casualidad que yo ayer estuve trasteando en intentar crear una rutina para creacion de tiles, pero no di con tesultado optimos, la verdad es que el tema que dices es interesante y no lo he experimentado, incluso fuera del prgestudio seria factible simplemente con la rutina que te muestra un texto en pantalla simplemente en vez de entrecomillando el texto, poniendo el valor Hexa del char fuera de comillas,...tengo que experimentarlo (a ver si tengo tiempo que estoy super liado)
En relación a hacer una juntada de Coders, me alegra mucho que te apuntes, e incluso podría hacer que alguien mas se apunte, como Blackhole (muchos ya le conoceis y cracker reconocido), lo podriamos organizar al estilo de las reuniones que hacia con Retro Game Systems, la celebramos en mi casa, monto tres C64 reales y un PC para que trasteemos todos agusto, lo ideal seria hacerlo un Domingo por la mañana, comemos de menu aqui al lado y quien quiera continuamos un rato por la tarde.
El tema de organizar reuniones se me da bien, recientemente organice un nuevo Torneo de Scalextric (de los mios) en el lugar donde hariamos la reunion de C64, aqui podeis ver los tinglados que organizo, en la seccion de notas estan las fichas de los diferentes Torneos.
https://www.facebook.com/Torneos-Scalextric-561265877652972/ (https://www.facebook.com/Torneos-Scalextric-561265877652972/)
La reunion la podiamos hacer en mi casa en Valdebebas (a 7 minutos de Plaza Castilla), quien no tenga coche que se vaya a Plaza Castillai en metro y le recojo yo con el coche,..lo organizamos pasadas las Navidades,..ya abrire un Hilo.
-
Buenas a todos!
He estado leyendo el tema del scroll. Hace tiempo estuve liado con ello, el problema que tenía es que no iba lo suficientemente rápido y opte por un scroll a lo 'bestia' que es el que esta implementado en Sky Diving...
Pero me desvío del tema. He estado revisando 'viejos' códigos de scroll a través del VIC y he visto que lo hago es mover los caracteres con los registros del VIC, mientras en la una pantalla 'oculta' muevo en dos veces los bloques de datos para que cuando termine el movimiento por hardware se haga el swap entre pantallas. Todo ello sincronozándolo con el raster de la pantalla.
Espero que os sirva como idea.
Por cierto Rulas, nos vimos en el ultimo RetroMadrid pero apenas pudimos hablar... Lo siento :( a ver si quedamos delante de unas cervecitas (al menos invito a la primera ronda :D) y hablamos de codificación.
Salu2 a todos!!!
-
Sobre los tiles, lógicamente, depende del tipo de juego que quieras hacer, pero si va a usar scroll, entiendo que quieres que el mapa tenga unas cuantas pantallas.
Si el mapa se mantiene en memoria como tú indicas (lo que yo llamo "descomprimido"), 32 pantallas ocuparían 32Kb (a 1Kb por pantalla, por simplificar, independientemente de marcadores y todo eso).
Si haces un matamarcianos, 32 pantallas te darian para, digamos, 4 fases de 8 pantallas de largo...Lo cual, si se adapta al juego que quieres hacer, pues te puede valer.
En la memoria de mapa, lo que se guarda es el indice del caracter a pintar.
Pero si hacemos grupos de 4x4 caracteres (tiles):
AAAA BBBB
AAAA BBBB
AAAA BBBB
AAAA BBBB
El mapa ahora se almacena como una secuencia de tiles.
En la memoria de mapa, no se guardan caracteres, sino el ìndice de tile.
Cada tile ocupa 16 bytes. Supongamos que se permiten 256 tiles distintos. En total, tenemos 4096 bytes, por lo que nos quedan ahora 28Kb de los 32Kb que hemos reservado para mapa.
Una pantalla, que es de 40x25 (por simplificar, 40x24), requiere entonces 10*6 tiles, 60 bytes, para almacenarse. Y en los 28Kb que nos quedan, podemos guardar 28*1024/60 pantallas, o sea, 477 pantallas.
Hemos pasado de 32, a 477.
Pero supongamos que hacemos metatiles, en grupos de 4x4 tiles. En el mapa, lo que tenemos ahora, son indices a metatiles, los cuales tienen indices a tiles, los cuales tienen indices a caracteres.
Seguimos teniendo 256 tiles, lo que son 256*16 bytes , 4096 bytes.
Permitimos 256 meta-tiles, lo que son otros 256*16 bytes, otros 4096 bytes.
Ahora, de los 32Kb, hay 24 Kb de mapa : (32Kbs - 4Kbs de tiles - 4Kbs de metatiles).
Cada metatile son 16x16 caracteres = 256 caracteres, por lo que 1 pantalla entera, se guarda en 4 metatiles, lo que son 4 bytes. Con 24Kb disponibles para mapa...Puedes tener 6144 pantallas. Aproximadamente, sería un mapa de 80x80 pantallas.
Lógicamente, los metatiles suponen muchisima repetición. A lo alto, una pantalla es sólo 1 metatile y medio (24 caracteres). Ese tamaño de mapa, es para un juego de rol, o algo parecido, donde las ciudades se harian con metatiles especificos, y el resto (bosques, rios, etc), con repeticiones de tiles gigantes
O se pueden hacer metatiles de 2x2 tiles, (8x8 caracteres), que no provoca tanta repetición, y todavía da para un mapa de 40x40 pantallas.
Lo que hemos fijado es la memoria (32Kb). Si lo que fijamos es el tamaño del mapa, usar metatiles o tiles siempre va a ocupar mucha menos memoria.
Pero, lógicamente, todo esto complica (mucho) las rutinas de pintado.
Usando mapa descomprimido, con scroll fino, la posición de la esquina superior izquierda de la pantalla es :
- x de mapa, y de mapa --> da un caracter
- x de scroll fino, y de scroll fino.
Si metes tiles, la posición de la esquina superior izquierda de pantalla es:
- x de mapa, y de mapa --> da un tile
- x de tile, y de tile ---> da un caracter
- x de scroll fino, y de scroll fino.
Si metes metatiles, la posición de la esquina superior izquierda, es:
- x de mapa, y de mapa --> da un metatile
- x de metatile, y de metatile --> da un tile
- x de tile, y de tile --> da un caracter
- x de scroll fino, y de scroll fino.
Y a eso es a lo que llamo añadir indirecciones, que hay que resolver al pintar el mapa. De los 3 registros, uno (X) lo vas a necesitar para la memoria de caracteres...Tienes sólo el Y para resolver los pasos de mapa a tile, de tile a caracter, etc.
Lo "normal" es meter tiles, de 2x2, de 4x4 o de 5x5...Los metatiles son para mapas muy bestias..
Más tarde subo mi código para mapas con tiles de 4x4...El código se complica "un poco".
-
Ok, muchisimas gracias Dashiad, a ver si teniendo algo real puedo empezar a experimentar un poco. Si no
recuerdo mal, en los 80 los mapas que hacia (o niveles les llamaba yo) eran de 7 pantallas. Espacio que
podia meter en una sequencia de bytes de la forma que te dije en el ultimo mensaje. Por lo que veo, la
tecnica de "tiles" parece mucho mas eficiente en cuando a uso de RAM asi que con lo que puedas subir
tendre algo para terminar de comprender esta tecnica. Y de nuevo gracias por tus explicaciones
-
Aqui va el código.
Está hecho con el C64 Studio, aunque el mapa de tiles tiene formato del CBM Prg Studio.
El asm de entrada es "main.asm".
Puedes activar o desactivar que pinte la memoria de color, cambiando la primera linea de config.asm (drawColor=1)
Al ejecutarlo, la zona de pantalla con fondo blanco indica qué parte del raster se ha consumido para pintar el mapa.
Es un mapa de tiles 4x4, pintando en pantalla 40x20 caracteres (5 lineas inferiores para marcador).En charmap.asm está la definición de caracteres, tiles, y mapa (el mapa ahora mismo no tiene sentido...)
Pero creo que va a ser muy criptico entender qué hace, a base de mirar el código..Yo mismo he tenido que reescribirlo un par de veces porque ni yo mismo, pasado un tiempo, lo entendía...Está muy optimizado, y yo ya casi me he quedado sin ideas sobre dónde conseguir 1 ciclo más..
(Por cierto, que esta versión que subo aquí, con respecto a la que puse anteriormente, ha corregido un caso en el que el pintado tardaba más de 1 frame)
Ahora escribo un post sobre pintado de mapas con tiles, donde más o menos se vean los fundamentos, y así se pueda entender mejor el código.
-
Como ejemplo:
- Tiles de 4x4
- Memoria de mapa comienza en $1000
- Memoria de tiles comienza en $2000
Supongamos que el mapa es de 20x10 tiles. O sea, ocupa 200 bytes, y en caracteres, 160x80 caracteres.
Esos 200 bytes están incializados a:
0,1,2,3,4,5......200
Los tiles van a ser:
@@@@ AAAA BBBB CCCC
@@@@ AAAA BBBB CCCC
@@@@ AAAA BBBB CCCC
@@@@ AAAA BBBB CCCC
y asi, hasta el caracter 200. Cada posicion de mapa tiene un tile distinto.
Se dejan las ultimas 5 lineas para marcador.
Si pintamos la coordenada 0,0 de mapa (con el 0,0 arriba a la izquierda), los tiles a pintar van a ser los de la primera imagen (no sé como ponerla inline...)
El primer tile es el 0...y debajo de él , está el tile 20
Aquí, el mapa está alineado con los tiles: hay 10 tiles en horizontal, 5 en vertical (50 tiles en total)
Pero qué ocurre si nos movemos en diagonal hacia abajo? Ocurre lo que pasa en la segunda imagen: el mapa no está alineado con los tiles, y queda una zona donde entran nuevos tiles. El resultado es que hay 11 tiles en horizontal, y 6 en vertical (66 tiles en total)
Si llamamos MAPX y MAPY , a las coordenadas X e Y en el mapa, esas coordenadas nos dan 1 tile.
Si llamamos MAPTILEX y MAPTILEY a las coordenadas en X e Y del tile que está arriba a la izquierda, eso nos da un offset dentro del tile.
En la imagen 2, tendríamos un MAPX=0, MAPY=0, MAPTILEX=1, MAPTILEY=1
(En este ejemplo, MAPX va de 0 a 19, MAPY de 0 a 9, MAPTILEX de 0 a 3 y MAPTILEY de 0 a 3)
Mirando la imagen 2, verás que todos los tiles que hay en el borde, están afectados por MAPTILEX , MAPTILEY, o ambos.
Eso significa que, en una implementación simple, el bucle de pintado ya empieza a tener unas cuantas comprobaciones que hacer...
Pero eso no es el mayor problema.
Lo "natural" sería pintar primero el tile 0, luego el tile 1, tile 2, tile 3....
El tile 0 comienza en $2000.
Según la imagen 2, hay que copiar:
$2000+4+1 ($2005)-->$0400
($2006) --> $0401
($2007) --> $0402
Ahora llegamos a la siguente fila del tile.Como el primer caracter no se ve, por el scroll, el puntero a la memoria de tiles, hay que incrementarlo en 2, y el puntero a la memoria de pantalla, en 37 (40 - 3)
($2009) --> $0428
($200A) --> $0429
($200B) --> $042A
De nuevo, en la siguiente fila del tile 0:
($200D) ---> $0450
...
Una vez pintado el primer tile, habría que calcular la posición en pantalla del comienzo del tile 1, y repetir
Si empiezas a pensar cuántas condiciones, comprobaciones, sumas y multiplicaciones (sólo para ir al comienzo de un tile en memoria, hay que multiplicar por 16, o sea, resultado de 2 bytes) vas a necesitar para pintar todo el mapa, verás que se empieza a poner complicado...
-
Buff, aquí se está volcando mucho material para estudiar, por desgracia ahora no tengo tiempo, si ya tenía los findes ocupados con Ferias de juguete antiguo y scalextric se me suma que el 21 me voy una semana a Alemania, osea que me pondre cuando pasen las navidades,..por cierto, aparte estoy de claustro con un nuevo proyecto con un genero que nunca he practicado...un juego de estrategia.
A lo tonto ya somos unos cuantos para una Reunion de Coders:
- Dashiad
- i03862
- Darro99
- Blackhole
- R. International
Motivo mas que suficiente para celebrarla.
Ese dia aprovechare por mi parte, para mostraros mi Scroll en Xain2 que me ha quedado muy resulton, indudablemente quiero clases de Scroll y creación de Tiles, como os he dicho si quereis lo hecemos en mi casa y monto un MiniRetromadrid, con Maquinas a tutiplen al estilo de las reuniones del GUA en casa de Rafa, lo hablamos....
-
Muchas gracias chicos, ya empiezo a ver claro el final del tunel... En esto momentos estoy resolviendo
un pequeño problemilla familiar sin importancia pero que requiere de mi atencion. Pero, a partir de
este lunes (3/12) me meto a saco con el codigo que me ha pasado Dashiad. Y todo lo que vaya sacando
en claro lo ire publicando para saber vuestra opinion.. :) :)
¡Muchisimas gracias y seguir asi..Estamos en contacto..!
-
Por cierto, hablando de otra cosa, he publicado un mensaje en la seccion de "general" en este foro para
comentaros la experiencia que he tenido con otros foros. Si os apetece, echarla un vistado y me decis
que opinais al respecto. El titulo es "Mi experiencia forera"
¡Gracias y hasta muuy pronto...!
-
Yo hecho mucho en falta un "centro de experimentación", un sitio donde en lugar de sacar " " juegos " " entre 4 comillas, se pudieran depurar mecánicas y físicas, que es lo que yo noto que más se necesita en C64... Tenéis la oportunidad de eso, de sacar cosas entre todos muy interesantes!
-
Sigo por donde lo dejé..
A partir de la segunda imagen, el algoritmo debería ser:
- Por cada fila del mapa en pantalla: (5 o 6)
- Por cada tile de la fila en pantalla: (10 o 11)
- Por cada fila del tile: (entre 4 y 1)
- Por cada caracter de la fila (entre 4 y 1)
- Dibujar el caracter en la posición de pantalla correspondiente. (1)
Eso son 4 bucles anidados, y, enmedio, hay muchos punteros a calcular, variables que mantener, y condiciones que comprobar (bordes).
El objetivo tiene que ser, simplificar en lo posible ese bucle.Todo lo que haya dentro, va a impactar exponencialmente el tiempo de pintado. Lo ideal es dejarlo en bucle muy simple, parecido al que mostraba i03862 en su ejemplo.
En el código de i03862 , a partir de ciertos puntos fijos en la pantalla, indexando con X, se muestra un caracter de una lista, indexada por Y.
En el caso de los tiles, la idea es exactamente la misma.
Los puntos en pantalla a "fijar", son las posiciones donde empieza cada tile.En la imagen 1, los puntos de pantalla, serían:
1024 --> comienzo del tile 0
1028 --> comienzo del tile 1
....
1184 --> comienzo del tile 20
Esos son los puntos de "destino".Los puntos de "fuente", están en la memoria de tiles:
$2000 --> comienzo del tile 0
$2010 --> comienzo del tile 1
....
$2140 --> comienzo del tile 20
Entonces, lo que sería ideal sería un código del tipo:
LDA $2000,X ; Leemos del tile 0
STA 1024,Y ; Escribimos en la posicion de pantalla donde va a estar el tile 0
LDA $2010,X ; Leemos del tile 1
STA 1028,Y ; Escribimos en la posicion de pantalla donde va a estar el tile 1
...
X se debe incrementar hasta que llegue a 16. Cada 4 incrementos de X, Y se debe incrementar en 36, para pasar a la linea inferior de la pantalla.
Así, estamos pintando más de 1 tile a la vez. Mi código dibuja una fila completa de tiles (10 u 11) en el bucle.Por lo que el bucle se ejecuta tantas veces como filas de tiles hay (5 o 6).
Y de esta forma tenemos un bucle muy simple, que es la idea inicial.
Para llegar a ese tipo de bucle, sólo tenemos que precalcular los puntos de inicio en pantalla, los puntos de inicio de los tiles, y almacenar estos punteros SOBRE el propio bucle (modificando el código), antes de saltar a él.
Pero esto supone que el mapa está 100% alineado...Qué ocurre si no lo está?
Lo que se me ocurrió, es aplicar un par de ideas.
El problema del alineamiento se trata diferente en X y en Y.
Primero, cómo tratar el problema en Y
Lo que no quería, era convertir la primera y ultima linea, en casos "especiales", que me llevaran a introducir comprobaciones dentro del bucle.
Se hace "al revés".
Mirando la imagen 2 del post anterior, para el tile 0, mi código calcula una posición de pantalla de (1024-40-1) = 983. Es decir, va a generar un código del tipo:
LDA $2000,X
STA 983, Y
Y lo que va a hacer, es cambiar el offset inicial, haciendo que cuando entra por primera vez en el bucle, X se ha cargado con un 6, e Y con un 41, por lo que empieza a pintar en la posición correcta.
Que la primera linea se dibuje así, viene muy bien.Los punteros de pantalla a la fila siguiente, se calculan sumando 160 (4*40) a los punteros de la fila anterior.Si la primera fila no se calculara así, no se podría simplemente sumar para calcular los siguientes.Sería un caso especial, y eso significa condiciones que gastan ciclos.
Eso gestiona el offset en Y. Ahora toca gestionar el offset en X
Si el offset en X es 1, como en la imagen 2, lo que significa es que si estamos pintando la posición 0,4,8 o 12 del tile, hay que pintar en el ULTIMO tile. Y en el resto de los casos, pintar en el primero.
Esto se hace, de nuevo, almacenando el offset en X , SOBRE el programa.Después de cada dibujar cada linea de caracteres, y cuando se suma 36 al registro Y para pintar en la siguiente linea, además, se suma 4 a esa posición del programa donde se almacena el offset.
Es decir, al pintar una fila de tiles, se van a dibujar 4 lineas de caracteres.Al dibujar la primera linea, en el caso de la imagen 2, la condición que existe en el programa, es:
dbucle CPX #$00 ; Este 00, será sobreescrito por el offset en X, en este caso , '1' : CPX #$01
BCS tilecp0 ; Si es igual o mayor, se dibuja el tile 0
tilecp10 LDA PT_CURTILELO,Y ; Si no, se dibuja el tile 10.
STA $0400,X
JMP tilecp1 ; Y se salta al tile 1
tilecp0 LDA PT_CURTILELO,Y ; Dibujado del tile 0
STA $0400,X
tilecp1 LDA PT_CURTILELO,Y
STA $0400,X
En este trozo de código, que es parte del bucle principal,se ve que las posiciones de origen y destino de todos los tiles, son las mismas.. porque en realidad, cuando se vaya a ejecutar el bucle, se habrán sobreescrito con los punteros precalculados.
Cuando se termina de dibujar una linea completa de caracteres, se suma 36 a X, para pasar a la siguiente linea, y se incrementa en 4 el contenido de dbucle+1, con lo que el CMP se hará sobre '5'.
Y esto explica más o menos en qué consiste el nucleo del código. El resto es principalmente precálculo de los punteros.
-
Bueno Dashiad, lo prometido es deuda... Sobre lo de dar mas libertad de movimientos al
personaje principal te cuento algo que hice en el Amiga y que puede resultarte.
Yo hice algo parecido a lo que tu buscas añadiendo al control del scroll un par de "flags". Un "flag" para
detectar el principio del mapa y otro para cuando llegas al final del mismo. Pseudograficamente seria asi :
(lo hago asi de "chapuza" porque me ha sido imposible subir un grafico, ¡me daba error!)
TAMAÑO DE LA PANTALLA DEL C-64 (PIXELS)
0 160 320
_____________________________________________________________________
| | |
|-----------------------------------------------------------------------------------------------|
| |
| DATOS DEL MAPA....... DATOS DEL MAPA ................... |
| |
| "" "" "" "" "" "" |
| O |
| "" "" "" | "" "" "" |
| /\ |
|____________________________________________________________________|
| SPRITE |
LIMITE MIN XPOS = 40 ------------------------------------- LIMITE MAX XPOS (230)
La forma que hice en su momento (creo recordar) era dar libre movimiento al personaje (que
aqui asumo que es un sprite) hasta que llegara a los limites (en este ejemplo min posx=40 y
max posx=230. Por supuesto los flags estan "reseteados" (por asi decirlo) al principio.
Cuando se llegaba a esos limites activaba el flag correspondiente (de "0 a 1" por ejemplo). La
rutina de scroll, antes que nada, chequeaba dicho flag. Si estaba a "1" (activo) saltaba al final
de la rutina, es decir, no efectuaba el scroll correspondiente. En ese momento, el joystick
(o teclado) pasaria a controlar el desplazamiento del personaje.En caso de que estuviera a "0"
ejecutaba el scroll sin problemas. Codigo ejemplo para tope minimo (x) del mapa:
Scroll_left Lda lefttop_flag ; Chequea the flag de limite minimo del map (mapx=0)
bne noScroll_left ; Esta a 1? entonces no hacer mas scroll.
jsr do_ScrollLeft ; Hacer scroll
noScroll_left rts ; Salir
Naturalmente, ese mismo flag (u otro que definas) puede controlar que el sprite se desplace
o se quede quieto (en ese momento exacto, el desplazamiento corresponderia a las rutinas
que efectuan el scroll.
Otro efecto de los valores que he puesto en el ejemplo es que como el sprite principal nunca
llega a 255 no tienes que preocuparte por controlar el X-MSB ($d010). Ademas creo que topes
maximos de 40 y 230 que tiene el ejemplo son bastante holgados para dar una gran libertad
de desplazamientos al personaje..
No se si esto te puede servir para lo que quieres hacer. Ya te dije que lo hice en el Amiga que
obviamente tiene un manejo de graficos muy diferente pero creo que la escencia es la misma.
En fin, cuentame que te parece la idea...