Aquí estamos de nuevo, todavía trasteando en ensamblador para tratar de que mi cerebro acabe de arrancar de una vez y me sea más fluido el programar, el tiempo que ha pasado desde que lo dejé, ha causado estragos
.
En esta ocasión he creado un programa que permite mover una nave en 16 direcciones diferentes manejándola con el JOY en port 2. Mi intención es usar esto en un futuro juego donde intentaré hacer que la nave tenga inercias al girar y se le aplique gravedad para alterar su trayectoria y así, hacer las cosas más difíciles en el juego (y en la programación XD ).
Utilizo interrupciones para mover la nave y así, regular su velocidad de desplazamiento sin bucles de freno que consuman ciclos inútilmente, pero las utilizo solo para activar algunas rutinas en el tiempo de ejecución fuera de las interrupciones para mover los gráficos.
Es decir, no consumo tiempo de proceso durante las interrupciones, si no durante el proceso normal con la ventaja de evitar flicks al mover gráficos ya que se da el permiso justo cuando ha terminado de dibujar la pantalla .
Hago uso de tablas para manejar todo el cotarro usando el puntero del sprite a mover para tomar todas las decisiones necesarias. Seguro que había otra manera más complicada de hacerlo, pero no di con ella
La creé y pulí durante los 4 días que duro RetroBarcelona, a ratos libres.
Las variables MovX0 y MovY0, son las que controlan la cantidad de veces a esperar antes de desplazar un eje o el otro para conseguir que se desplace en 16 direcciones diferentes .
DEjeX0 y DEjeY0 contienen la dirección hacia donde mover la nave. 0=nada, 1=positivo (incrementa eje) , 2=negativo (decrementa eje).
La barrita de color que aparece por debajo de la pantalla, en el marco inferior , indica el tiempo de ejecución de las rutinas dentro del tiempo de IRQ pero fuera del mismo , no sé si ha quedado claro con mi explicación anterior XD.
Como siempre, he intentado comentarlo todo lo que me ha sido posible , así que aquí os dejo el código. De seguro es muy mejorable, pero es una buena introducción a otra manera de hacer las cosas.
Aquí lo tenéis. Destripadlo, trastearlo, en fin, lo que os apetezca. También he hecho que se active o desactive el MSB del sprite0 para poder navegar por toda la pantalla sin problemas.
;CBM PRG STUDIO 3.8.0
;CONSTANTES UNIVERSALES
; $D000-$D010 SPRITE HORIZONTAL AND VERTICAL POSITION REGISTERS
SP0X = $D000 ; SPRITE 0 X POSITION
SP0Y = $D001 ; SPRITE 0 Y POSITION
SP1X = $D002 ; SPRITE 1 X POSITION
SP1Y = $D003 ; SPRITE 1 Y POSITION
SP2X = $D004 ; SPRITE 2 X POSITION
SP2Y = $D005 ; SPRITE 2 Y POSITION
SP3X = $D006 ; SPRITE 3 X POSITION
SP3Y = $D007 ; SPRITE 3 Y POSITION
SP4X = $D008 ; SPRITE 4 X POSITION
SP4Y = $D009 ; SPRITE 4 Y POSITION
SP5X = $D00A ; SPRITE 5 X POSITION
SP5Y = $D00B ; SPRITE 5 Y POSITION
SP6X = $D00C ; SPRITE 6 X POSITION
SP6Y = $D00D ; SPRITE 6 Y POSITION
SP7X = $D00E ; SPRITE 7 X POSITION
SP7Y = $D00F ; SPRITE 7 Y POSITION
MSIGX = $D010 ; MSB'S OF SPRITES 0-7 HORIZONTAL POSITIONS
; POINTER SPRITES
POINSP0 = $07F8 ; POINTER 2040 SPRITE O
POINSP1 = $07F9 ; POINTER 2041 SPRITE 1
POINSP2 = $07FA ; POINTER 2042 SPRITE 2
POINSP3 = $07FB ; POINTER 2043 SPRITE 3
POINSP4 = $07FC ; POINTER 2044 SPRITE 4
POINSP5 = $07FD ; POINTER 2045 SPRITE 5
POINSP6 = $07FE ; POINTER 2046 SPRITE 6
POINSP7 = $07FF ; POINTER 2047 SPRITE 7
; $D011-$D012 SCROLL & RASTER
SCROLY = $D011 ; VERTICAL FINE SCROLLING AND CONTROL REGISTER
RASTER = $D012 ; READ CURRENT RASTER SCAN LINE/WRITE LINE TO COMPARE
; FOR RASTER IRQ
SPENA = $D015 ; SPRITE ENABLE REGISTER
SCROLX = $D016 ; HORIZONTAL FINE SCROLLING AND CONTROL REGISTER
YXPAND = $D017 ; SPRITE VERTICAL EXPANSION REGISTER
VMCSB = $D018 ; VIC-II CHIP MEMORY CONTROL REGISTER
VICIRQ = $D019 ; VIC INTERRUPT FLAG REGISTER
IRQMSK = $D01A ; IRQ MASK REGISTER
SPBGPR = $D01B ; SPRITE TO FOREGROUND DISPLAY PRIORITY REGISTER
SPMC = $D01C ; SPRITE MULTICOLOR REGISTERS
XXPAND = $D01D ; SPRITE HORIZONTAL EXPANSION REGISTER
; $D01E-$D01F SPRITE COLLISION DETECTION REGISTERS
SPSPCL = $D01E ; SPRITE TO SPRITE COLLISION REGISTER
SPBGCL = $D01F ; SPRITE TO FOREGROUND COLLISION REGISTER
; $D020-$D026 VIC-II COLOR REGISTER
EXTCOL = $D020 ; BORDER COLOR REGISTER
BGCOL0 = $D021 ; BACKGROUND COLOR 0
SPMC0 = $D025 ; SPRITE MULTICOLOR 0
SPMC1 = $D026 ; SPRITE MULTICOLOR 1
; $D027-$D02E SPRITE COLOR REGISTERS
SP0COL = $D027 ; SPRITE 0 COLOR
SP1COL = $D028 ; SPRITE 1 COLOR
SP2COL = $D029 ; SPRITE 2 COLOR
SP3COL = $D02A ; SPRITE 3 COLOR
SP4COL = $D02B ; SPRITE 4 COLOR
SP5COL = $D02C ; SPRITE 5 COLOR
SP6COL = $D02D ; SPRITE 6 COLOR
SP7COL = $D02E ; SPRITE 7 COLOR
; $D02F-$D03F NOT CONNECTED
; $D040-$D3FF VIC-II REGISTER IMAGES
; $D419-$D41A GAME PADDLE INPUTS
; $D41D-$D41F NOT CONNECTED
; $D420-$D7FF SID REGISTER IMAGES
; $D800-$DBFF COLOR RAM
COLRAM = $D800
; $DC00-$DC0F CIA #1
CIAPRA = $DC00 ; DATA PORT REGISTER A
CIAPRB = $DC01 ; DATA PORT REGISTER B
CIDDRA = $DC02 ; DATA DIRECTION REGISTER A
CIDDRB = $DC03 ; DATA DIRECTION REGISTER B
CIASDR = $DC0C ; SERIAL DATA PORT
CIAICR = $DC0D ; INTERRUPT CONTROL REGISTER
CIACRA = $DC0E ; CONTROL REGISTER A
CIACRB = $DC0F ; CONTROL REGISTER B
; $DC10-$DCFF CIA #1 REGISTER IMAGES
; $DD00-$DD0F CIA #2
; $DD10-$DDFF CIA #2 REGISTER IMAGES
LECOL = $0286 ; LETTER COLOR
GETIN = $FFE4
;------------------------------------------------------------
; 10 SYS4096
*=$0801
BYTE $0B, $08, $0A, $00, $9E, $34, $30, $39, $36, $00, $00, $00
;------------------------------------------------------------
*=$1000
;Conectando y colocando sprite para pruebas
lda #1
sta SPENA
lda #192 ;$3800 ...#12288 $3000
sta POINSP0
lda #99
sta SP0X
sta SP0Y
lda #0 ;Fondo negro
sta $d021
lda #1 ;Multicolor ON sprite 1
sta SPMC
lda #1 ;Blanco
sta SP0COL
lda #2 ;Rojo
sta SPMC0
lda #6 ;Azul
sta SPMC1
;Activando interrupciones
sei
lda #%00011011 ;27 original. 26 no flickea.Hibyte del raster pero
sta $D011 ;si no es 27 aparecen "pelos" en los bordes pantalla.
lda #<irq
sta $0314
lda #>irq
sta $0315
lda #%00000001 ;#127 en el ejemplo. Basta con activar el timer A #1
sta $DC0D ;Registro control de la cia
lda #1
sta $D01A ;Registro mascara IRQ activada. IRQ ON.
lda #250 ;Altura del barrido
sta $d012
cli
jmp PREMAIN ;Pasamos al programa normal saltandonos la rutina de irq.
IRQ ;Programa ejecutado a cada interrupción.
lda $d019 ;Reset bandera irq
sta $d019 ;asi se desactiva la bandera y funcionan bien.
lda #1 ;Activando permiso de ejecucion fuera de pantalla (IRQ)
sta Permiso ;XD
jmp $EA81 ;Rutina interrupcion normal Leer teclado y demás.
;EA81 ;FEBC ;Saltar a restaurar a partir de la rutina NMI.
;------------------------------------------------------------
;RESERVA DE VARIABLES EN EL PROGRAMA.
;El programa empieza aquí.
PREMAIN lda #0
sta Dspr0 ;Pongo la nave en direccion hacia arriba (pruebas).
clc
adc #192
sta POINSP0 ;Cambio el puntero sprite.
jsr ResetEjeNaveX ;Iniciando valores X
jsr ResetEjeNavey ;Iniciando valores Y
;DESPLAZAMIENTO NAVE RESPETANDO IRQ.
MAIN
lda Permiso ;El raster esta a mas de 250?
bne sigue0 ;Si=1 activado. Salta a ejecutar las rutinas irq dentro del tiempo de programa normal.
jmp PASODEIRQ ;Si=0 desactivado. Me largo a ejecutar los programas fuera de las IRQ.
sigue0
lda #0 ;Desconecto el permiso de ejecución por IRQ
sta Permiso ;para evitar su ejecución constante. Si lo poneis a 1, vereis el programa a toda mecha XD.
inc $d020 ;Testigo de la rutina (Borrable)Cambia el color del marco para ver cuanto tiempo ocupan los procesos.
;Leer joy2
dec frenjoy ;Freno joystick. Solo leé una vez cada 3 IRQ.
bne paso3 ;No=0, paso de leer
lda #3 ;Una vez cada 3 IRQ. Reconectar el freno. A mayor cifra, mayor arco decribe la nave.
sta FrenJoy ;xx ciclos antes de leeeer joy2
lda CIAPRA ;Leer joy2
and #15 ;Solo movimiento der e izq.
cmp #07 ;Derecha.
bne paso1 ;No es derecha, paso a izq.
clc ;Borrar bandera de acarreo.
inc DSpr0
lda DSpr0 ;Comprobando si pasa limite 15. La animación va del 0 al 15
cmp #16
bne paso2 ;Si no lo sobrepasa, pasa XD.
lda #00 ;como si lo sobrepara, lo pone a 0
sta DSpr0 ;y lo almacena.
jmp paso2
paso1 clc
cmp #11 ;Izquierda.
bne paso3 ;No es izquierda?. Paso de todo.
dec DSpr0
lda DSpr0 ;Comprobando si pasa del limite <0 (255)
cmp #255
bne paso2
lda #15 ;Le doy el nuevo valor para mostrar el ciclo correcto.
sta DSpr0
paso2 jsr ResetEjeNaveX ;Como se ha "movido", inicializo de nuevo los valores de movimiento y dirección
jsr ResetEjeNavey ;de X e Y.
paso3 ;Se acabo joys
lda DSpr0 ;Cojo su nuevo valor y cambio el sprite.
clc
adc #192 ;Le sumo el valor de puntero del primer sprite de la animación.
sta POINSP0
;Mover eje X
lda MovX0Temp ;Ciclos a esperar para mover el eje X
beq PasoEjeX0 ;Sin decrementar la variable. 0=No mover.
dec MovX0Temp
bne PasoEjeX0 ;Si aún no es =0, paso de mover.
lda DEjeX0Temp ;Dirección hacia donde mover la nave.
beq PasoEjeX0 ;Si=0, no mueve este eje.
cmp #01 ;1=Incrementa eje. 0=Decrementa eje.
bne DecEjeX0
lda SP0X
clc ;Desactiva la bandera de acarreo antes de sumar.
adc #01
bcc paso4 ;Hay desbordamiento?
tax ;Si lo hay: Guardo el valor de la coordenada.
jsr msbx0 ;Salto a activar el MSB del sprite0
txa ;Recupero el valor de la coordenada.
paso4 sta SP0X ;y la pongo en el eje X
jsr ResetEjeNaveX ;Como se ha movido el eje, paso a reiniciar los valores de freno y dirección.
jmp PasoEjeX0 ;Saltar hasta la rutina de mover eje Y
DecEjeX0
lda SP0X
sec ;Para restar hay que activar la bandera de acarreo.
sbc #01
bcs paso5 ;Sigue activado el acarreo?. =Si.Pasando de tocar el MSB.
tax ;Guardo el valor de la coordenada.
jsr msbx0 ;Salto a desactivar el MSB.
txa
paso5
sta SP0X
jsr ResetEjeNaveX ;Como se ha movido el eje, paso a reiniciar los valores de freno y dirección.
PasoEjeX0
;Mover eje Y. Lo mismo que con X pero al no tener que activar/desactivar el MSB, uso INC o DEC.
lda MovY0Temp
beq PasoEjeY0 ;Sin decrementar la variable. 0=No mover.
dec MovY0Temp
bne PasoEjeY0 ;Si aún no es =0, paso de mover.
lda DEjeY0Temp
beq PasoEjeY0 ;Si=0, no mueve este eje.
cmp #01
bne DecEjeY0
inc SP0Y
jsr ResetEjeNaveY
jmp PasoEjeY0
DecEjeY0
dec SP0Y
jsr ResetEjeNavey
PasoEjeY0
dec $d020 ;Testigo de la rutina (Borrable). Este debe ejecutarse al terminar con las rutinas que usen IRQ.
PASODEIRQ ;Final rutinas que usen IRQ.
;A PARTIR DE AQUÍ, SOLO RUTINAS LIBRES QUE SE EJECUTEN EL 100% DE CICLOS.
nop
nop
nop
jmp MAIN
;SUBRUTINAS .
;Cargar direccion de la nave y almacenar valores de dirección y bucles espera en sus respectivas variables.
ResetEjeNaveX
clc
ldx DSpr0 ;Carga direccion actual de la nave.
lda MovX0,x ;cargo valor fijo segun direccion
sta MovX0Temp ;y la guardo en el control de freno movimiento temporal X.
lda DEjeX0,x ;Cargo si suma o resta
sta DEjeX0Temp ;y la guardo en el control de dirección X.
rts
ResetEjeNavey
clc
ldx DSpr0 ;Carga direccion actual de la nave
lda MovY0,x ;cargo valor fijo segun dirección
sta MovY0Temp ;y la guardo en el control de freno movimiento temporal Y.
lda DEjeY0,x ;Cargo si suma o resta
sta DEjeY0Temp ;y la guardo en el control de dirección Y.
rts
;Activar o desactivar MSB sprite0
msbx0 clc
lda MSIGX
eor #01 ;ON/OFF byte 1
sta MSIGX
rts
MovX0 byte $00,$02,$01,$01,$01,$01,$01,$02,$00,$02,$01,$01,$01,$01,$01,$02 ;bucles de espera antes de desplazar eje sprite0
MovY0 byte $01,$01,$01,$02,$00,$02,$01,$01,$01,$01,$01,$02,$00,$02,$01,$01 ;Idem
DEjeX0 byte $00,$01,$01,$01,$01,$01,$01,$01,$00,$02,$02,$02,$02,$02,$02,$02 ;Direccion ejes para saber si restar o sumar ese eje. 0=resta / 1=Suma / 255=nada
DEjeY0 byte $02,$02,$02,$02,$00,$01,$01,$01,$01,$01,$01,$01,$00,$02,$02,$02 ;Idem
MovX0Temp byte $00 ;Variable
MovY0Temp byte $00 ;Variable
DEjeX0Temp byte $00 ;Variable
DEjeY0Temp byte $00 ;Variable
DSpr0 byte $00 ;DireccionSprite0
FrenJoy byte $10 ;Freno lectura joystick
Permiso byte $00 ;Ejecutar o no rutinas por IRQ
;-------------------------------------------------------------------------------------------------------------------------------------
*=$3000 ;Los 16 sprites de la nave (0-15). sprites V2 #192-#203
;12288/64=192
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$08,$00,$00,$19,$00,$00,$0A,$00,$00,$36,$00,$00,$36,$00,$00,$3A,$00,$00,$EA,$80,$00,$F6,$80,$00,$D1,$80,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$04,$00,$00,$02,$00,$00,$0D,$40,$00,$36,$00,$00,$FA,$00,$00,$EA,$00,$00,$56,$00,$00,$06,$00,$00,$06,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$00,$02,$80,$00,$5D,$80,$00,$DD,$40,$00,$DB,$00,$00,$DA,$00,$00,$1A,$00,$00,$18,$00,$00,$08,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$E0,$40,$00,$EA,$80,$00,$6D,$80,$00,$1D,$40,$00,$1A,$00,$00,$68,$00,$00,$60,$00,$00,$C0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$C0,$00,$00,$E1,$00,$00,$69,$00,$00,$36,$80,$00,$36,$80,$00,$69,$00,$00,$E1,$00,$00,$C0,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$00,$00,$E0,$00,$00,$68,$40,$00,$6A,$40,$03,$6D,$80,$03,$6D,$80,$03,$AA,$80,$00,$01,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$18,$00,$00,$18,$00,$00,$1A,$00,$00,$5A,$40,$02,$FD,$00,$00,$BD,$80,$00,$2B,$80,$00,$02,$80,$00,$04,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02,$00,$00,$06,$00,$00,$16,$00,$00,$FA,$00,$00,$FA,$00,$00,$3D,$00,$00,$0D,$40,$00,$02,$00,$00,$04,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$D1,$80,$00,$F6,$80,$00,$EA,$80,$00,$3A,$00,$00,$36,$00,$00,$36,$00,$00,$08,$00,$00,$19,$00,$00,$08,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$34,$00,$00,$34,$00,$00,$39,$40,$00,$3A,$80,$00,$36,$80,$00,$36,$00,$00,$58,$00,$00,$20,$00,$00,$04,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$0D,$00,$00,$3D,$00,$00,$39,$00,$00,$29,$40,$00,$DA,$80,$00,$5A,$80,$00,$9A,$00,$00,$A0,$00,$00,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$03,$00,$00,$0E,$00,$00,$0D,$00,$00,$39,$00,$00,$69,$00,$00,$D9,$00,$03,$5A,$40,$02,$AA,$80,$00,$40,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$03,$00,$00,$4B,$00,$00,$69,$00,$02,$D8,$00,$02,$D8,$00,$00,$6D,$00,$00,$4F,$00,$00,$03,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$40,$00,$02,$AA,$80,$03,$5A,$40,$00,$D9,$00,$00,$69,$00,$00,$39,$00,$00,$0D,$00,$00,$0E,$00,$00,$03,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$10,$00,$00,$A0,$00,$00,$9A,$00,$00,$5A,$80,$00,$DA,$80,$00,$29,$40,$00,$39,$00,$00,$3D,$00,$00,$0D,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
BYTE $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$04,$00,$00,$20,$00,$00,$58,$00,$00,$36,$00,$00,$36,$80,$00,$3A,$80,$00,$39,$40,$00,$34,$00,$00,$34,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$81
*=$4000 ;Pantalla de pruebas
;Desde #1104 hasta #2023 ($0450 hasta $07E7)