Generación procedimental de entornos en terminal: anatomía de un cielo estrellado en BASH.


Generación procedimental de entornos en terminal: anatomía de un cielo estrellado en BASH.

Análisis del script de presentación ASCII de los videos de Entropía binaria para 2026. 

Cuando nos enfrentamos al desafío de crear videojuegos o animaciones en la terminal utilizando BASH, uno de los primeros obstáculos es dar profundidad a la escena. Un fondo negro plano puede resultar aburrido y bidimensional, mientras que un fondo dinámico o vistoso siempre aporta vida y contexto. En el script analizado, la solución para crear una atmósfera espacial es la implementación de un sistema de partículas estáticas simulando un campo de estrellas. A diferencia de dibujar un simple archivo de texto como fondo, este método genera las estrellas matemáticamente, lo que significa que cada vez que ejecutamos el programa, el cielo es único. Para lograr esto, no podemos simplemente imprimir caracteres al azar en un bucle infinito; necesitamos persistencia de datos.

El primer concepto a asimilar es que, en una animación en donde la pantalla se refresca constantemente (se borra y se redibuja), las estrellas no pueden cambiar de lugar en cada fotograma. Si generáramos coordenadas aleatorias dentro del bucle de dibujo, el fondo parecería estática de televisión. Por lo tanto, el paso fundamental ocurre antes de que empiece el juego, en la fase de inicialización. El script utiliza lo que llamamos matrices paralelas ("arrays" paralelos). En lugar de tener un "objeto estrella", BASH nos permite crear varias listas: una para la posición X, otra para la posición Y, una tercera para el carácter que representa la estrella y una última para su color. De este modo, el índice 0 de todos los arrays define las propiedades de la primera estrella, el índice 1 las de la segunda, y así sucesivamente hasta llegar al número total definido en la variable num_estrellas.

Para distribuir estos puntos luminosos, necesitamos conocer los límites de nuestro lienzo (terminal). El script hace uso del comando tput para obtener dinámicamente el ancho (cols) y el alto (lines) de la terminal actual. Dentro de un bucle for, utilizamos la variable interna $RANDOM combinada con el operador módulo (%) sobre estas dimensiones. Esto nos devuelve un número entre 0 y el tamaño de la pantalla, garantizando que ninguna estrella se genere fuera del área visible. Es aquí en donde entra en juego la variedad visual. Un cielo realista no se compone solo de puntos idénticos. El código define dos matrices (arrays) de caracteres: uno de chars_comunes (como puntos y comas) y otro de chars_raros (como asteriscos o círculos). Mediante una probabilidad simple, definida en prob_estrella_rara, el script decide si la estrella actual será un simple punto de luz distante o un cuerpo celeste más brillante, asignándole además un color aleatorio de una paleta ANSI predefinida.

Una vez que tenemos los datos almacenados en memoria, el desafío técnico se desplaza al motor de renderizado, específicamente dentro de la función dibujar_escena. Aquí es donde la optimización se vuelve crítica. BASH no es, en principio, un lenguaje rápido para dibujar gráficos, por lo tanto, dibujar cientos de elementos innecesarios podría llegar a causar parpadeos. El script implementa una técnica de "enmascaramiento" o "culling" muy interesante. Antes de agregar una estrella al búfer de dibujo, verifica si sus coordenadas caen dentro del rectángulo que ocupa el planeta (o el logo que no se ve al principio, porque está posicionado por detrás del planeta Tierra). Si la coordenada X e Y de la estrella están dentro de los límites del objeto principal (offset_x y offset_y), el script ejecuta un continue y salta esa iteración. Esto evita que se dibujen estrellas por encima del planeta, creando la ilusión de que el cuerpo celeste está en primer plano y las estrellas en el fondo, sin necesidad de complicados cálculos de capas Z (profundidad).

Finalmente, la materialización de todo este cálculo matemático en la pantalla se realiza mediante códigos de escape ANSI. No se utiliza el comando echo línea por línea, ya que esto generaría un proceso demasiado lento. En su lugar, se construye una variable gigante llamada buffer. Para cada estrella válida, se concatena una secuencia de escape que mueve el cursor directamente a la posición deseada (\e[Y;XH), establece el color, imprime el caracter y resetea el color. Al final del ciclo de dibujo, se imprime todo el búfer de una sola vez. Este enfoque está basado en que en la programación de terminal, el control preciso del cursor y la gestión eficiente de cadenas de caracteres y del tiempo de dibujado en pantalla son las herramientas que transforman simples datos numéricos en un universo visualmente atractivo. BASH posee límites inexplorados e infravalorados en cuanto a sus capacidades de dibujo.

Disección del código: implementación práctica del campo estelar.

Para comprender verdaderamente cómo funciona el sistema, no hay nada mejor que aislar este mecanismo del resto del juego. A continuación se presenta el código fuente extraído directamente del script original, limpio de cualquier lógica ajena al cielo estrellado (como el Pacman o el planeta), pero manteniendo intacta la matemática y la sintaxis que generan las estrellas. Este fragmento es totalmente funcional: puedes copiarlo, guardarlo (por ejemplo) como "estrellas.sh", darle permisos de ejecución y verás el mismo fondo estelar que en el juego.


#!/bin/bash

# CONFIGURACIÓN.
num_estrellas=100
prob_estrella_rara=10
c_reset="\e[0m"

# DEFINICIÓN DE CARACTERES Y COLORES.
chars_comunes=("." "·" "," "°")
chars_raros=("*" "+" "o" "O" "ø" "●")
colores_estrellas=("\e[34m" "\e[36m" "\e[33m" "\e[37m" "\e[31m" "\e[90m")

# DECLARACIÓN DE MATRICES PARALELAS (ARRAYS PARALELOS).
declare -a estrellas_x estrellas_y estrellas_char estrellas_color

# FUNCIÓN DE INICIALIZACIÓN (lógica exacta del script original).
iniciar_estrellas() {
    local ancho_term=$(tput cols)
    local alto_term=$(tput lines)

    for ((i=0;i<num_estrellas;i++));do
        # Posición aleatoria.
        estrellas_x[i]=$((RANDOM % ancho_term))
        estrellas_y[i]=$((RANDOM % alto_term))

        # Elegir caracter (común vs raro).
        if [[ $((RANDOM % prob_estrella_rara)) -eq 0 ]];then
            # Estrella rara.
            local idx=$((RANDOM % ${#chars_raros[@]}))
            estrellas_char[i]="${chars_raros[$idx]}"
        else
            # Estrella común (punto, coma, etc).
            local idx=$((RANDOM % ${#chars_comunes[@]}))
            estrellas_char[i]="${chars_comunes[$idx]}"
        fi

        # Elegir color aleatorio.
        local c_idx=$((RANDOM % ${#colores_estrellas[@]}))
        estrellas_color[i]="${colores_estrellas[$c_idx]}"
    done
}

# PREPARACIÓN DE PANTALLA.
tput civis;clear

# EJECUCIÓN.
iniciar_estrellas

# RENDERIZADO (extraído del bucle de dibujo principal).
buffer=""
for ((s=0; s<num_estrellas; s++));do
    sx=${estrellas_x[s]}
    sy=${estrellas_y[s]}
    
    # Agregar al búfer de dibujo.
    buffer+="\e[${sy};${sx}H${estrellas_color[s]}${estrellas_char[s]}${c_reset}"
done 

echo -ne "$buffer"

# FINALIZAR (esperar tecla para salir y restaurar cursor).
read -n 1 -s
tput cnorm;clear

 

Explicación línea por línea.

El script comienza con el clásico #!/bin/bash, indicando al sistema qué intérprete usar. Inmediatamente después, se definen las variables de control: num_estrellas=100 establece la cantidad de partículas y prob_estrella_rara=10 dicta que hay una probabilidad de 1 entre 10 de que aparezca una estrella especial. c_reset es simplemente el código de escape para limpiar el color al final de cada impresión.

A continuación, vemos la definición de los "activos" gráficos. chars_comunes y chars_raros son listas (matrices, arrays) que contienen los "glifos" (símbolos visuales de caracteres) que veremos en pantalla. colores_estrellas almacena los códigos ANSI para azul, cian, amarillo, blanco, rojo y gris. Luego, declare -a inicializa cuatro matrices (arrays) vacías (estrellas_x, estrellas_y, etc.). Estos serán nuestros contenedores de datos, los cuales es de buen proceder declararlos explícitamente cuando se trabaja con estructuras indizadas en BASH, para evitar comportamientos inesperados.

Entramos en la función iniciar_estrellas. Las dos primeras líneas dentro de la función usan tput cols y tput lines. Esto es dinámico: pregunta al sistema el tamaño actual de la ventana en el momento de la ejecución. Luego inicia un bucle for que se repetirá 100 veces (el valor de num_estrellas).

Dentro del bucle, estrellas_x[i]=$((RANDOM % ancho_term)) genera la coordenada horizontal. Al usar el módulo (%) sobre el ancho de la terminal, obtenemos un valor que siempre caerá dentro de la pantalla. Lo mismo ocurre con la coordenada "Y". El bloque if siguiente decide el aspecto: genera un número al azar entre 0 y 9. De ser 0 (probabilidad del 10%), entra en el bloque de estrellas raras, elige un índice aleatorio basado en la longitud de la matriz ${#chars_raros[@]} y asigna ese carácter a estrellas_char[i]. Si no es 0, hace lo mismo pero con la matriz de caracteres comunes. Finalmente, se selecciona un color al azar de la lista de colores disponibles.

Al salir de la función, encontramos tput civis;clear. civis oculta el cursor parpadeante (esencial para que se vea estético) y clear limpia la pantalla. Llamamos a la función iniciar_estrellas para llenar las matrices con datos.

El bloque final es el motor de renderizado. Creamos una variable vacía llamada buffer. Recorremos nuevamente los 100 glifos (las 100 estrellas) con un bucle. Extraemos las coordenadas X e Y guardadas en memoria. La línea clave es buffer+="\e[${sy};${sx}H...". Aquí estamos concatenando una cadena de texto que contiene una instrucción para mover el cursor a la posición Y, X guardada, luego aplica el color guardado, imprime el caracter guardado y resetea el color.

Finalmente, echo -ne "$buffer" vuelca toda esa información acumulada en la pantalla de un solo golpe. El comando read -n 1 -s (el cual se puede escribir también, por ejemplo, "read -sn1") pausa el script esperando que pulses una tecla, y tput cnorm restaura el cursor a modo visible antes de salir para no dejar a la terminal sin su cursor.

0 Comentarios:

Publicar un comentario

Flag Counter Visitas previas a la existencia de este contador: 3433

Artículos aleatorios

    Páginas: