4.5. Aleatoriedad
Los diseños que hasta ahora somos capaces de crear con nuestro código son algo estáticos, están muy constreñidos por los valores que definimos. Sin embargo, podemos dotar a nuestros diseños de algo más de «vida» introduciéndoles cierta aleatoriedad. El uso de la aleatoriedad es constante en proyectos de computación creativa para dotar de mayor «naturalidad» y hacer más orgánicos nuestros diseños. La naturaleza es un gran ejemplo de aleatoriedad: si tomamos por ejemplo las nubes, aunque todas comparten características similares, nunca veremos dos nubes idénticas. Esta organicidad seremos capaces de simularla utilizando algunos métodos de P5.
En P5.js disponemos del método random() para generar valores aleatorios que podremos utilizar en nuestros sketches. Veamos cómo lo podemos utilizar:
function setup(){ createCanvas(400, 400); } function draw() { let randomValue = random(0, 255); background(randomValue); }
Si ejecutamos el código anterior, podremos ver cómo el color de fondo de nuestro sketch varía rápidamente tomando diferentes valores dentro de una escala de grises. Analicemos el código para ver qué es lo que está ocurriendo exactamente. En el setup() creamos nuestro canvas con unas dimensiones de 400 × 400 px; hasta aquí nada nuevo. Dentro del draw() estamos creando una variable llamada randomValue a la que le asignamos un valor que viene definido por el método random, al que le estamos pasando dos parámetros. Estos dos parámetros definen el rango de valores entre los que el método random «elige». En nuestro caso, hemos definido los valores 0 y 255, por lo que random cada vez que se ejecute devolverá (como cuando creábamos una función con return) un valor entre 0 y 255. Posteriormente, utilizamos este valor que random ha devuelto y que hemos almacenado en la variable randomValue para establecer el color de nuestro fondo. Al ser valores entre 0 y 255, nuestro fondo cambiará entre distintos valores de gris.
Ahora bien, ¿por qué cambia constantemente el valor del color? Si recordamos de temas anteriores, el draw() se ejecuta constantemente en bucle a una velocidad de 60 fotogramas (frames) por segundo. Por ello, el método random se estará ejecutando continuamente y devolviendo un valor distinto cada vez. Normalmente, querremos que nuestro sketch se ejecute a 60 frames por segundo, pero en algunos casos podemos ralentizar e incluso parar por completo la velocidad de refresco, lo que nos puede resultar útil a la hora de crear sketches «estáticos» o para poder apreciar detalles de lo que realiza nuestro código que a 60 FPS se nos escapen.
Para alterar la velocidad de refresco de nuestros sketches, podemos usar el método frameRate():
function setup(){ createCanvas(400, 400); frameRate(2); } function draw() { let randomValue = random(0, 255); background(randomValue); }
Como parámetro a frameRate() le pasamos el número de fotogramas por segundo al que queremos que se ejecute nuestro sketch. En el ejemplo anterior le hemos dado una velocidad de 2 fotogramas por segundo, por lo que ahora nuestro color de fondo cambiará dos veces cada segundo en lugar de estar cambiando 60 veces por segundo.
Si queremos parar por completo el refresco y que el código que tenemos en el draw() se ejecute una única vez, lo podemos hacer con noLoop():
function setup(){ createCanvas(400, 400); noLoop(); } function draw() { let randomValue = random(0, 255); background(randomValue); }
El método noLoop() no precisa de parámetros y lo que hace es que limita la ejecución del draw() a una única vez. De esta manera, no veremos cambio alguno y si queremos que el método random() nos devuelva un nuevo valor y que consecuentemente el fondo cambie de color, deberemos ejecutar de nuevo nuestro sketch.
Una vez hecho este inciso para explicar cómo podemos alterar la ejecución de nuestro sketch mediante frameRate() y noLoop(), regresemos a la aleatoriedad con el método random(). En los ejemplos anteriores hemos utilizado dos parámetros para definir el rango de valores que el método nos va a devolver, pero podemos usarlo también de otros modos:
// Sin parámetros // Valores entre 0 y 1 let value = random(); // Con un parámetro // Valores entre 0 y el valor del parámetro let value = random(255); // Con dos parámetros // Valores entre el primer y el segundo parámetro let value = random(100, 200);
Si usamos la consola para imprimir alguno de estos valores, nos daremos cuenta de una peculiaridad: los valores que nos devuelve random() son siempre valores decimales. Esto puede ser algo deseable o no según el caso, por lo que veamos cómo podemos transformar los números decimales en enteros usando las funciones int(), round(), floor() y ceil():
let value = 14.6604; // int() se queda con la parte entera del valor let intValue = int(value); // intValue valdrá 14 // round() redondea al entero más cercano let roundValue = round(value); // roundValue valdrá 15 // floor() redondea hacia abajo let floorValue = floor(value); // floorValue valdrá 14 // ceil() redondea hacia arriba let ceilValue = ceil(value); // ceilValue valdrá 15
La combinación de la aleatoriedad con los bucles nos puede resultar de bastante provecho. Con los bucles tenemos la capacidad de repetir un motivo múltiples veces por nuestro canvas, mientras que con la aleatoriedad podemos dotar a cada uno de estos elementos de cierta variación para hacer que nuestros diseños sean más dinámicos.
Pongamos como ejemplo el patrón sencillo que creamos mediante bucles anidados. Si antes de dibujar cada círculo creamos una variable a la que asignamos un valor aleatorio y utilizamos esa variable para establecer el diámetro del círculo, tendremos un patrón con un espaciado regular pero el tamaño de cada elemento será distinto.
Fuente: elaboración propia.
Podemos aplicar los valores aleatorios a los parámetros de dibujo que queramos. Podríamos por ejemplo recuperar el ejemplo del patrón de ojos para que el color del iris de cada ojo vaya cambiando cada vez que dibujemos un ojo nuevo. Para ello, podríamos usar tres valores aleatorios para definir un color en RGB, pero de esta manera no tendríamos demasiado control sobre el resultado final, y serían colores muy dispares entre sí. Una manera de tener mayor control sobre el color final es usando colorMode() para cambiar el modo de color de RGB a HSB (tono, saturación, brillo). Así, podríamos establecer un tono fijo y variar el brillo y la saturación o introducir una pequeña variación en el tono también:

Fuente: elaboración propia.
Por defecto, el modo de color HSB acepta valores que van de 0 a 360 para el tono y de 0 a 100 para la saturación y el brillo. En el ejemplo de la figura 52 hemos modificado un poco la función eye(), ya que ahora el color no viene dado por un parámetro externo, sino que lo definimos dentro de la propia función usando random() con distintos rangos para tener ligeras variaciones de color en el iris.