Flapper Boriel: "Scroll" a 4px y animación del sprite

2026-05-16 por juntelart

En esta entrada cuento qué ha cambiado en la rama feat-4px-scroll-and-sprite-animation respecto a la versión anterior del port. En resumen:

  • Scroll fino a 4px por frame en lugar del desplazamiento al carácter.
  • Animación del sprite del pájaro (frames alternos) para aportar fluidez.
  • Ajustes en el pipeline de render para evitar tearing: cálculo previo en screenBuffer y un único memcopy al final del frame.
  • Revisión de colisión para funcionar correctamente con el scroll de 4px.

Motivación

El problema con la versión anterior era que el desplazamiento iba a saltos de un carácter entero (columnas de 8×8 píxeles), lo que hacía el movimiento horizontal bastante brusco. Quería algo más suave sin tocar la geometría del juego, y pasar a 4px por frame fue la solución.

Implementación técnica (resumen)

  • Scroll a 4px:

  • El scroll horizontal suave se consigue alternando los atributos tanto de las columnas de tubería como del suelo entre valores normales (ATTR_PIPE, ATTR_SKY, etc.) y valores especiales (ATTR_FIRST_HALF y ATTR_LAST_HALF) en frames pares e impares (worldCol Mod 2).

  • El patrón de píxeles halfTile (mitad izquierda del carácter encendida) permite que, al combinarse con estos atributos, cada carácter se pinte visualmente partido: la mitad izquierda con un color (ink/paper) y la derecha con otro.
  • Así, tanto las tuberías como el suelo parecen avanzar 4px cada frame, aunque la memoria de atributos sigue siendo de 32 columnas. No se duplica la resolución lógica ni se hace un desplazamiento por píxel real.
  • Fragmento clave del código (src/draw.bas):
  If worldCol Mod 2 = 1 Then
    attrFront = ATTR_FIRST_HALF
    attrBack = ATTR_LAST_HALF
  Else
    attrFront = ATTR_PIPE
    attrBack = ATTR_SKY
  End If
  ...
  bufferPipeColumn(leadingCol, gap, attrFront)
  bufferPipeColumn(trailingCol, gap, attrBack)
  • Animación del sprite:

  • El sprite del pájaro ahora tiene 3 frames en src/spriteset.bas. El juego alterna el índice del frame cada N frames (por ejemplo, cada 6 frames) para dar sensación de aleteo.

  • Código de animación:

  Sub drawBird()
      ' Calculate yo-yo animation frame (0, 1, 2, 1) changing every 2 ticks
      Dim animIdx As Ubyte = (worldCol / 2) Mod 4
      If animIdx = 3 Then animIdx = 1

      ' Draw pixels based on animation frame
      If animIdx = 0 Then
          putChars(birdX, Int(birdYPos), 2, 2, @sprite0(0))
      ElseIf animIdx = 1 Then
          putChars(birdX, Int(birdYPos), 2, 2, @sprite1(0))
      Else
          putChars(birdX, Int(birdYPos), 2, 2, @sprite2(0))
      End If

      ' Paint bird with Yellow Ink (6) and Blue Paper (1) -> 14
      paint(birdX, Int(birdYPos), 2, 2, 14)
  End Sub

Compatibilidad con colisión y lógica existente

Al introducir el scroll a 4px, el pájaro puede quedarse durante varios frames a caballo entre dos columnas de atributos, lo que rompía las colisiones. Para arreglarlo sin complicar demasiado el código:

  • La comprobación de colisión ahora usa coordenadas de juego (geométricas): se calcula si el rectángulo del pájaro intersecta la geometría de una tubería, en lugar de leer atributos redondeados a la columna. Así se evitan falsos positivos/negativos en la fase intermedia del scroll.

  • Seguimos comprobando solo la tubería frontal (la que puede estar en contacto), pero con posiciones y anchuras/gaps en píxeles.

Rendimiento y timing

Me preocupaba que estos cambios afectasen la tasa de frames, pero por suerte no ha sido así. El coste extra del scroll a 4px y la animación del sprite es mínimo comparado con hacer múltiples escrituras directas a la RAM de atributos. La estrategia sigue siendo la misma: calcular el screenBuffer completo antes del waitretrace y hacer un único memcopy durante la ventana de retrace para evitar el tearing.

Qué notarán los jugadores

  • El mundo se mueve más suave: 4px por frame en lugar de saltos de carácter.
  • El pájaro aletea con un sprite animado.
  • Las colisiones son más precisas gracias a la comprobación geométrica en píxeles.

Enlaces


Volver a publicaciones