PongPong; 20160208

Veamos, esto lo tengo que resolver ya. Parece mentira que cosas tan tontas me ocupen tanto tiempo. Cómo codificar todo lo que quiero extraer de los enemigos en un sólo byte. Hagámoslo como se hacen las cosas de verdad, con un análisis de requisitos (siempre pienso en quesitos cuando escribo esta palabra):

  • Debe poder representar fácilmente el “enemigo no existe”. Por ejemplo, con el valor “0”.
  • Debe poder indicarse qué cells de sprite usará, de 0 a 15.
  • Los enemigos lineales deben poder o no disparar (tentativo).
  • Quiero fantys (sin colisión, FP), saltadores (FP), cuchillas, lineales, pezones (FP).

Estoy pensando que podría gastar 48 bytes en otro array “en_attrs” y rellenar este y en_t de la siguiente forma:

  • en_t -> AFCDXTTT
  • en_attrs -> XXXXSSSS

Donde:

  • A -> Activo. Siempre a 1, menos cuando el enemigo no existe (en ese caso, todo en_t == 0).
  • F -> Fixed Point. Inicializar valores al crear y actualizar al finalizar.
  • C -> Collision. Realizar colisión.
  • D -> Dispara.
  • TTT -> Tipo de rutina de movimiento
  • SSSS -> # de gráfico.

Creo que si lo estructuro así el tema irá sobre ruedas. Lo que tengo que ver es si no me voy a quedar sin memoria con los nuevos arrays que necesito (enf_x, enf_y, enf_vx, enf_vy, en_attrs son 96+96+96+96+48 = ¡¡432 bytes!!). Voy a crear los arrays antes de montar más historias a ver si me queda suficiente RAM. Si no tendré que inventarme algo:

pre-idea: hacer que enf_x, enf_y, enf_vx y enf_vy sean sólo arrays de 6 elementos y crear al vuelo cuando un enemigo de este tipo empiece a ser procesado (sea de los seis que están activos) – No sé si esto será viable tal y como está montada la gaita. Lo miraré y lo pensaré.

De hecho lo voy a mirar antes que nada porque si es viable es la mejor forma. Hay que ser conservadores con la memoria: puede que tenga esos 432 bytes, pero ¿no los necesitaré para otras cosas en el futuro?

~~~

No lo voy a poder enganchar directamente, pero está claro que siempre se actualizan 6 enemigos (pantalla actual de cam_pos y siguiente), y es tontería estar guardándolos todos. Aquí el problema radica, principalmente, en saber cuándo inicializar los valores de un enemigo y en saber cuándo queda este libre.

Hay que tener en cuenta que esto se va solapando. A medida que se avanza, si se pasa de n_pant a n_pant + 1, los tres primeros enemigos quedan libres y podrían ser usados por los nuevos enemigos de la pantalla que entra. La sección de enems_move que asigna sprites al vuelo (y hace que se actualicen) procesa de seis en seis, según la pantalla actual. ¿Cómo detectar un cambio? Más pensar, más pensar. Qué de pensar lleva esto, coñor.

Aunque luego está el tema de que un enemigo no se mueve SI NO SE VE. Con esto no había contado yo. Creo que tengo que modificar esto. Lo suyo es que, aunque no se vea, se mueva si está en el “radio de acción” (en la pantalla donde está la cámara o en la siguiente). Voy a darle una vuelta, porque a lo mejor ahí veo el quid.

En Sir Ababol el bucle de crear sprites y el bucle de mover enemigos están separados, y por eso va bien. Aquí los junté, pero creo que los junté demasiado. A lo mejor puedo hacerlo de otra manera… Veamos…

~~

Espérate porque creo que la mierda esta de los slots no se usa para nada – es que si es así, soy la banana más grande de la historia de Wichita…

Joder, creo que esto era porque cuando hice Sir Ababol no sabía controlar los sprites de la OAM de forma dinámica y lo tenía todo por putos slots… Joder, por eso se llama “en_slot” el array. Esto es más grande que Barcelona. Voy a cambiar algunas cosas.

~~~~

Joder, lo he quitado, he salvado toneladas de memoria, me he quitado ciclos de procesador, y he arreglado lo de que a veces no se mueven cuando deberían. La leche en polvo, esto es la puta hostia. Lo flipo conmigo. Vaya cagada, primosaurio. En serio. La leche.

Ahora a ver cómo resuelvo el tema de, esta vez sí, asignar dinámicamente los arrays de punto fijo a los enemigos que lo necesiten. Seguramente de una forma parecida a la que asignaba los “slots” para sprites que no estaba usando XD

A ver, que puede ser fácil. En rda tengo el número de pantalla, o sea, MSB (cam_pos). Imaginamos que guardo un on_pant con el valor “anterior” de MSB (cam_pos). Cuando estos valores sean diferentes, es que hemos cambiado de pantalla.

Teniendo en cuenta que al principio del juego MSB(cam_pos) es PAR, tenemos que al cambiar de pantalla MSB(cam_pos) sería IMPAR. Los tres enemigos al principio de los arrays tendrían que ser sustituidos por tres enemigos nuevos. Al siguiente cambio de pantalla, MSB(cam_pos) vuelve a ser PAR y los tres enemigos entrantes deberían escribirse en los tres slots ultimos.

Si ahora vamos a la izquierda, al cambia MSB (cam_pos) volvería a ser IMPAR … Nah, el PAR / IMPAR no me sirve. Tengo que considerar el desplazamiento a la izquierda y a la derecha.

Si recordamos “última mitad” que se introdujo… 0 (1ª) o 1 (2ª)

Al principio del juego la última mitad es la 1 -> tocaría la 0 si nos movemos a la derecha.
Seguimos avanzando -> tocaría la 1.
Pero si retrocedemos -> ¡La 1 de nuevo!

O sea, siendo last_half la ultima mitad, rda la posición actual (pantalla) y orda la posición anterior, tenemos que:

if (rda > orda) update (1 - last_half);
if (rda < orda) update (last_half);

Es un tanto complejo de ver, menos mal que llevo diarios. Creo que así puede funcionar y ahorraré bastante mandanga. Por supuesto lo más rápido sería tenerlos todos creados y tal, pero haciendo cuentas, ahora mismo los enemigos se llevan esta RAM:

en_t        48 bytes
en_attr     48 bytes
en_r        48 bytes
en_x        96 bytes
en_y        48 bytes
en_mx       48 bytes
en_my       48 bytes
en_slot     48 bytes

9 x 48 = 432 bytes. Es un pepino.

Además, así puedo crear los arrays en ZP, con lo que ahorro ciclos.

Esto va a costar. Voy a ello. Además, no podré probarlo hasta que meta un fanty o algo. Jodó, son demasiadas cosas que hacer. Vamos al lío.

~~

Creo que por ahora voy a pasar de los atributos y de las mierdas, y a hacerlo como siempre.

1 -> lineal
2 -> saw
3 -> buzzer
4 -> fanty
5 -> pezon
6 -> jumper

Si >= 4 -> fp; si >= 6 -> colision. Y a tomar por culo.

~~

Fanty metido. Tema de relleno de enemigos al vuelo solucionado. Cosas:

  • Me vuelve a renquear esto de vez en cuando, aunque no he establecido cuando. Seguramente alguno de los añadidos que he metido sea ya pasarse. Voy a mirar el tiempo de frame.
  • El fanty se para al borde de su pantalla, y esto queda muy raro. ¿Debería pasar de fantys? Es que hacen que el cambio de pantalla sea demasiado aparente.

Mirando el tiempo de frame, además de que, en general, lo veo todo más apretado, se nota como en cuanto aparece un fanty el tema cae en picado. ¿Cómo es posible que lo carguen tanto todo?

Voy a ver qué puedo modificar, aunque cada vez tengo más claro que va a tener que irse.

~~

Voy a tener que empezar a hacer cosas en frames alternos.

Cosa que podría alternar:

  • Colisión con los enemigos. No hace falta comprobar siempre. IMPAR
  • Imprimir puntuaciones. PAR
  • Comprobar si creamos enemigos nuevos. PAR

Por ahora va mejor con esto, pero tiene que haber más. Por ejemplo, el cambio de dirección de los fantys podría hacerse alterno, o sea, si (rdt & 1) == half_life. A la buchaca.

Esto ha solucionado algunas cosas, pero no todas. Vamos a tener que seguir mirando. Hay más cosas que puedo optimizar seguro, en todas las partes del motor.

Más optimizaciones hechas, pero sigue habiendo “picos” cuando pasan muchas cosas a la vez. Esto parece que no puedo evitarlo. Lo que sí voy a hacer es medio modificar famitone2, de forma que si una posición fija de RAM libre ($01bf, en mi configuración) vale <> 0, no actualiza los streams de SFX. Esto sólo vale un frame, la propia famitone2 volverá a poner a 0 la posición $01bf en cada ejecución. Esto me sirve para que cuando haya colisión y salte sonidos poner $01bf a 1 y que no salte esa parte del código en ese frame, ganando algo de tiempo. Tampoco se nota si está un frame retrasado.

~~~

Tras más mierdas de estas, he metido los pezones con éxito. Ahora voy a las sierras estas que van dándole vueltas a un tile.

~~

Increíble, han funcionado a la primera con tres jodidas lineas de código. Tres. Jodidas. Lineas. Bastante densas, eso sí:

delta = (en_my [rdt] ? (en_r [rdt] >> 1) : (((en_r [rdt] + 1) & 3) >> 1)) ? GYROSAW_V : -GYROSAW_V;
if (en_r [rdt] & 1) en_y [rdt] += delta; else en_rx += delta;
en_mx [rdt] = (en_mx [rdt] + GYROSAW_V) & 31; if (!en_mx [rdt]) en_r [rdt] = (en_r [rdt] + 1) & 3;

Luego pinté otra paleta y algunas pantallas de la segunda tira para ver si lo había hecho bien y cambiar de tira de mapa (en este juego, de nivel) funcionaba bien… Y coño que si funciona. ¡Es genial!

Cosas fáciles que debería pensar en meter:

  • Tiles resbalosos
  • Tiles conveyor

Y ahora se acabó el día.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s