Seguimos con la segunda parte de las “recargas de combustible”. En la primer parte vimos como implementar un generador de números aleatorios, algo que es trivial en cualquier lenguaje de programación, pero en ensamblador es un pequeño dolor de cabeza.
En esta segunda parte vamos a ver el código para que cada cierto intervalo de tiempo caiga un tanque de combustible desde el cielo, que puede ser tomado por cualquiera de los jugadores o destruido a tiros, para que no la agarre nadie.
Vamos a hacer, como en anteriores ocasiones, una máquina de estados, la cual tendrá 5 ‘status’ (status0 – status4). Esta máquina utilizará las siguientes variables/posiciones de memoria (que definiremos convenientemente en vars.asm):
; direcciones de fuel, sprite 4
sprcolorfuel = $d02b
sprpointfuel = $07fc
sprxfuel = $d008
spryfuel = $d009
FUEL = $10 ; 16, constante sprite 4 (00010000)
cantFUEL = 10 ; cantidad de combustible de cada fuel
statusFuel = $c0a0
fuelCounter = $c0a1
;255 mas grande el valor, mas tiempo tarda en aparecer
delayEntreFuels = 32
Para que haya mas claridad en la explicación primero voy a hacer un “resumen” de la maquina de estados, y luego voy a desglosar cada parte.
@status0
decrementa el contador 'fuelCounter', cuando llega a 0 pasa a status1
@status1
inicializa el 'fuel' (obtiene posicion x aleatoria, posiciona en y, etc
@status2
caida libre hasta que llega al piso
@status3
espera en el piso, hasta que alguien lo agarre o lo destruyan
@status4
apaga el sprite, reinicia contadores, cambia a status0
Status 0
Aqui solamente esperamos un cierto tiempo, para ello decrementamos un contador ‘fuelCounter‘, con la particularidad que lo haremos cada 64 frames (para ello usaremos un ‘generador de ticks’ que previamente usamos en otra parte). Cuando llegue a 0 pasamos a status1
@status0
; si statusFuel == 0 sigue, si no pasa al siguiente
ldx statusFuel
cpx #0
bne @status1
; Si hay un tick64 entonces decremento en 1 el fuelCounter
lda tick64
cmp #0
bne @decrementFuelCounter
jmp @exitFuel
@decrementFuelCounter
dec fuelCounter
; Si el fuelCounter llego a 0 cambio a status1
beq @setStatus1
jmp @exitFuel
@setStatus1
ldx #1
stx statusFuel
Status 1
Cuando el fuelCounter llega a 0 cambiamos de status, e inicializamos el tanque de combustible. Para ello activo el sprite 4, pongo en 0 la posición y, borro el bit8 (ya que puede haber quedado seteado de un tanque anterior), obtengo un numero aleatorio y le sumo 48, para centrarlo un poco. Esto es porque nuestro generador tira números de 0 a 255, pero nuestra pantalla tiene 320 px de ancho.
Para no complicar demasiado todo, y considerando que de 0 a 24 y de 320 en adelante el tanque no se mostraría en pantalla, decidí simplemente restringirlo a un área centrada de la pantalla, de 255 pixels, que abarca la posición entre 48 y 303.
Luego que inicializé todo paso a status2.
@status1
ldx statusFuel
cpx #1
bne @status2
; Pongo posicion y en 0
ldy #0
sty spryfuel
; activo sprite 4
lda spractive
ora #FUEL
sta spractive
; posicion x fuel (random entre 48 y 303)
; borro el bit8 del sprxfuel (por si quedo seteado anteriormente)
lda sprxBit8
and #%11101111
sta sprxBit8
; obtengo un numero del generador random
jsr randomGenerator
clc
lda random
; lo centro un poco
adc #48
sta sprxfuel
; si tengo carry, entonces voy a tener que setear Bit8
bcs @setBit8
jmp @setStatus2
@setBit8
lda sprxBit8
ora #%00010000
sta sprxBit8
@setStatus2
; finalmente paso a status2
ldx #2
stx statusFuel
Status 2
Aqui comienza la caída libre, incrementando la posición y del sprite cada cuatro frames (usamos el mismo tick4 que previamente definimos para la gravedad de los jetpacks). Una vez que llega al piso pasamos a status3
@status2
ldx statusFuel
cpx #2
bne @status3
; incremento cada 4 frames
lda tick4
cmp #0
bne @incrementFuel_y
jmp @exitFuel
@incrementFuel_y
inc spryfuel
ldy spryfuel
; si llego al piso (un poquito mas, ya que es mas corto el sprite)
cpy #floorPosition + 3
beq @setStatus3
jmp @exitFuel
@setStatus3
ldx #3
stx statusFuel
Status 3
Este status no hace nada, ni me molesto en poner codigo, el sprite se queda en el piso hasta que, por detección de colisiones, lo agarre alguien o lo destruyan de un tiro.
Status 4
A este status se llega desde la detección de colisiones (que lo explicaré en la próxima entrega). Básicamente reinicializa el contador fuelCounter, apaga el sprite y pone el status en 0, para que comience nuevamente todo.
@status4
;reinicializa statusFuel a 0
ldx #0
stx statusFuel
; inicializa fuelCounter con el valor de delayEntreFuels
ldx #delayEntreFuels
stx fuelCounter
; apago sprite 4
lda spractive
and #255 - FUEL
sta spractive
Y no me tengo que olvidar de inicializar algunas de las variables previamente definidas, en initVars.asm
ldx #0
stx statusFuel
ldx #delayEntreFuels
stx fuelCounter
Y con esto ya estamos…
En la próxima entrega vamos a finalizar esta parte de las recargas, vamos a editar el detectCollision.asm para que detecte cuando un jugador agarra el combustible, o cuando lo destruyen.
Como siempre, el codigo completo lo pueden bajar desde el repositorio:
https://github.com/moonorongo/jp_wars.git
Hasta la próxima!


