4. Bucles i aleatorietat

4.5. Aleatorietat

Els dissenys que fins ara som capaços de crear amb el nostre codi són una mica estàtics, estan molt constrets pels valors que definim. No obstant això, podem dotar els nostres dissenys d’una mica més de «vida» introduint-los una certa aleatorietat. L’ús de l’aleatorietat és constant en projectes de computació creativa per dotar de més «naturalitat» i fer més orgànics els nostres dissenys. La naturalesa és un gran exemple d’aleatorietat: si prenem per exemple els núvols, encara que tots comparteixen característiques similars, mai veurem dos núvols idèntics. Aquesta organicitat serem capaços de simular-la utilitzant alguns mètodes de P5.

En P5.js disposem del mètode random() per generar valors aleatoris que podrem utilitzar als nostres sketches. Vegem com ho podem utilitzar:

function setup(){
    createCanvas(400, 400);
}

function draw() {
    let randomValue = random(0, 255);
    background(randomValue);
}

Si executem el codi anterior, podrem veure com el color de fons del nostre sketch varia ràpidament prenent diferents valors dins d’una escala de grisos. Analitzem el codi per veure què és el que està passant exactament. En el setup() creem el nostre canvas amb unes dimensions de 400 × 400 px; fins aquí res de nou. Dins del draw() estem creant una variable anomenada randomValue a la qual assignem un valor que ve definit pel mètode random, al qual estem passant dos paràmetres. Aquests dos paràmetres defineixen el rang de valors entre els quals el mètode random «tria». En el nostre cas, hem definit els valors 0 i 255, per la qual cosa random cada vegada que s’executi retornarà (com quan creàvem una funció amb return) un valor entre 0 i 255. Posteriorment, utilitzem aquest valor que random ha retornat i que hem emmagatzemat a la variable randomValue per establir el color del nostre fons. Com que són valors entre 0 i 255, el nostre fons canviarà entre diferents valors de gris.

Ara bé, per què canvia constantment el valor del color? Si recordem temes anteriors, el draw() s’executa constantment en bucle a una velocitat de 60 fotogrames (frames) per segon. Per això, el mètode random s’estarà executant contínuament i retornant un valor diferent cada vegada. Normalment, voldrem que el nostre sketch s’executi a 60 frames per segon, però en alguns casos podem alentir i fins i tot aturar per complet la velocitat d’actualització, la qual cosa ens pot resultar útil a l’hora de crear sketches «estàtics» o per poder apreciar detalls del que fa el nostre codi que a 60 FPS se’ns escapin.

Per alterar la velocitat d’actualització dels nostres sketches, podem usar el mètode frameRate():

function setup(){
    createCanvas(400, 400);
    frameRate(2);
}

function draw() {
    let randomValue = random(0, 255);
    background(randomValue);
}

Com a paràmetre, a frameRate() li passem el nombre de fotogrames per segon al qual volem que s’executi el nostre sketch. A l’exemple anterior, li hem donat una velocitat de 2 fotogrames per segon, per la qual cosa ara el nostre color de fons canviarà dues vegades cada segon en lloc d’estar canviant 60 vegades per segon.

Si volem aturar per complet l’actualització i que el codi que tenim al draw() s’executi una única vegada, ho podem fer amb noLoop():

function setup(){
    createCanvas(400, 400);
    noLoop();
}

function draw() {
    let randomValue = random(0, 255);
    background(randomValue);
}

El mètode noLoop() no necessita paràmetres i el que fa és que limita l’execució del draw() a una única vegada. D’aquesta manera, no veurem cap canvi i, si volem que el mètode random() ens retorni un nou valor i que conseqüentment el fons canviï de color, haurem d’executar de nou el nostre sketch.

Una vegada fet aquest incís per explicar com podem alterar l’execució del nostre sketch mitjançant frameRate() i noLoop(), tornem a l’aleatorietat amb el mètode random(). En els exemples anteriors hem utilitzat dos paràmetres per definir el rang de valors que el mètode ens retornarà, però el podem usar també d’altres maneres:

// Sense paràmetres
// Valors entre 0 i 1
let value = random();

// Amb dos paràmetres
// Valores entre 0 y el valor del parámetro
let value = random(255);

// Con dos parámetros
// Valors entre el primer i el segon paràmetre
let value = random(100, 200);

Si usem la consola per imprimir algun d’aquests valors, ens adonarem d’una peculiaritat: els valors que ens retorna random() són sempre valors decimals. Això pot ser un fet desitjable o no segons el cas, per la qual cosa vegem com podem transformar els nombres decimals en enters usant les funcions int(), round(), floor() i ceil():

let value = 14.6604;

// int() es queda amb la part sencera del valor
let intValue = int(value);
// intValue valdrà 14

// round() arrodoneix a l’enter més proper
let roundValue = round(value);
// roundValue valdrà 15

// floor() arrodoneix cap avall
let floorValue = floor(value);
// floorValue valdrà 14

// ceil() arrodoneix cap amunt
let ceilValue = ceil(value);
// ceilValue valdrà 15

La combinació de l’aleatorietat amb els bucles ens pot resultar de bastant profit. Amb els bucles tenim la capacitat de repetir un motiu múltiples vegades pel nostre canvas, mentre que amb l’aleatorietat podem dotar cadascun d’aquests elements d’una certa variació per fer que els nostres dissenys siguin més dinàmics.

Posem com a exemple el patró senzill que creguem mitjançant bucles imbricats. Si abans de dibuixar cada cercle creem una variable a la qual assignem un valor aleatori i utilitzem aquesta variable per establir el diàmetre del cercle, tindrem un patró amb un espaiat regular però la mida de cada element serà diferent.

Figura 51. Aleatorietat dins de bucles for
Font: elaboració pròpia.
A l’exemple de la figura 51 hem usat un random(10, separation) perquè els cercles tinguin un diàmetre aleatori d’entre 10 px i la separació entre cada cercle, perquè d’aquesta manera no se superposin. Al setup() hem inclòs també un noLoop(), perquè el draw() s’executi una única vegada i no tinguem valors aleatoris 60 vegades per segon.

Podem aplicar els valors aleatoris als paràmetres de dibuix que vulguem. Podríem, per exemple, recuperar l’exemple del patró d’ulls perquè el color de l’iris de cada ull vagi canviant cada vegada que dibuixem un ull nou. Per a això, podríem usar tres valors aleatoris per definir un color en RGB, però d’aquesta manera no tindríem massa control sobre el resultat final, i serien colors molt dispars entre si. Una manera de tenir més control sobre el color final és usant colorMode() per canviar la manera de color de RGB a HSB (to, saturació, brillantor). Així, podríem establir un to fix i variar la brillantor i la saturació o introduir una petita variació en el to també:

Figura 52. Aleatorietat en el color
Font: elaboració pròpia.

Per defecte, la manera de color HSB accepta valors que van de 0 a 360 per al to i de 0 a 100 per a la saturació i la brillantor. A l’exemple de la figura 52 hem modificat una mica la funció eye(), ja que ara el color no ve donat per un paràmetre extern, sinó que el definim dins de la pròpia funció usant random() amb diferents rangs per tenir lleugeres variacions de color a l’iris.