5. Repte 5. Sistemes

5.3. Arrays

Ja hem fet alguna cosa amb els arrays, així que més o menys ja teniu una idea de què són.

Tots del mateix tipus, això sí. El fet de fer servir arrays ens permetrà treballar amb diversos objectes alhora i modificar-los tots amb facilitat.

El llibre comença amb dos exemples: l’11-1 i l’11-2 que són una còpia de l’exemple 8-3 però creant dues figures iguals a l’11-1 i cinc a l’11-2. En aquest darrer exemple, ja es veu que comencem a tenir massa variables, per, al final, fer gairebé el mateix amb cadascuna d’aquestes. La solució passa per fer servir un array de cinc posicions en comptes de cinc variables.

I això és el que es fa en l’exemple 11-3.

En la pàgina 168 del llibre, se’ns explica què és un array i posa en relleu tres conceptes:

  • El nom de l’array, que és el nom de la variable que emmagatzema l’array.
  • El nombre d’elements. Un array està format per un conjunt d’elements. Per a referir-nos a cada element, farem servir el número de la posició on està.
  • El valor de cada element.

A l’hora de definir un array, el que farem és declarar una variable a què li «assignarem» un array buit o un array amb un contingut, com per exemple:

var x = [];
var y = ["cotxe", 40, "moto", 25, "camió", 60];
var z = [14,40,33,25,54,60];

A partir d’aquí, si ens cal guardar un valor a l’array farem això:

x[posició_a_modificar] = valor_a_guardar;

La posició_a_modificar sempre serà un nombre enter positiu i sempre començarem per 0.

Per a consultar un valor que tinguem emmagatzemat a l’array, ho farem d’aquesta manera:

console.log(x[posició_a_consultar]);

També podem consultar quants elements té l’array:

console.log(x.length);

Al final estem substituint x0, x1, x2, x3 per x[0], x[1], x[2], x[3] i ens podem preguntar què guanyem amb això. Amb un exemple es veu molt fàcil. Escrivim a la consola els valors de totes aquestes variables:

console.log(x0);
console.log(x1);
console.log(x2);
console.log(x3);
for (var i = 0; i <= 3; i++) {
 console.log(x[i]);
}

Potser amb 4 variables no es veu una gran diferència, però l’exemple 11-3 en fa servir 3000!

Els exemples 11-4, 11-5 i 11-6 són petits codis que ens permeten veure, a la pràctica, tot això que hem anat veient aquí.

Fem una ullada a l’exemple 11-7. El que fa es crear una variable de tipus array on emmagatzema, dins el setup(), tants valors aleatoris (entre 0 i 255) com la mida horitzontal del canvas (width).

Després al draw() dibuixa width línies verticals, del color emmagatzemat a la posició de l’array que toca. L’exercici no és gens complicat, així que l’hem modificat una mica per a donar-li més interès:

var gray = [];
function setup() {
 createCanvas(240, 120);
 for (var i = 0; i < width; i++) {
  gray[i] = random(0, 255);
 }
}
function draw() {
 background(204);
 for (var i = 0; i < gray.length; i++) {
  stroke(gray[i]);
  line(i, 0, i, height);
}
 stroke(0);         // Extra
 line(mouseX,0,mouseX,height); // Extra
}

Hem afegit dues línies extres que fan que dibuixi una línia negra a la posició on hi ha el ratolí. Com que guardem a l’array el color original de les línies, un cop el ratolí canvia de lloc, la línia recupera el color que ja tenia.

L’exemple 11-8 és força interessant, però alhora una mica complicat d’entendre. Per a poder entendre millor el que fa, hem creat un exemple semblant, però més senzill.

El que fa aquest exemple és dibuixar un cercle cada cop que fem un clic amb el ratolí. No té la funció draw() perquè només ho dibuixa quan fem un clic. Per tant, el que sí que tenim és la funció mouseClicked(). El que passa és que hem limitat a 10 el nombre de cercles que podrem tenir a la pantalla. Quan ja tenim 10 cercles a la pantalla i fem un clic amb el ratolí, s’esborra el més antic abans de pintar-ne un de nou. Així, podem anar pintant cercles, però sempre en tindrem 10.

La complicació d’aquest exemple rau en l’esborrat. No tenim una manera d’esborrar un element sense esborrar-ho tot (esborrar-ho tot sempre és pintar de nou el fons (background)). Per tant, esborrar un element implicarà esborrar-ho tot i pintar tots els elements menys el que volíem esborrar.

Tenim tres variables globals, dues, circX i circY ens guarden les posicions x i y de tots els cercles dibuixats. A cada cercle que dibuixem li assignarem una posició als arrays. I farem servir la variable pos per a saber a quina posició dels arrays guardarem el proper cercle que dibuixarem. També ens servirà per a decidir quin és el cercle que cal esborrar.

Per a esborrar el cercle que toca, fem servir la funció esborrar que, de fet, el que fa és esborrar tot el canvas i tornar a pintar tots els cercles menys el que toca esborrar.

Amb un senzill exemple ho veurem més clar. Suposem que ja tenim els 10 cercles pintats i que portem una estona fent clic amb el ratolí. Suposem que a la variable pos hi ha un 5. Què farem? Doncs esborrarem el canvas i pintarem tots els cercles menys el que està a la posició 5. Després pintarem un nou cercle i guardarem la seva posició al canvas (els valors d’x i y) a la posició pos dels arrays. Finalment, incrementarem el valor de la variable pos per tal que el proper cercle que pintem es guardi una posició més enllà i no esborrem el que acabem de pintar.

var circX = []; // Variables on guardarem les posicions
var circY = []; // x i y dels cercles que dibuixem.
var pos = 0;   // Cercle que estem dibuixant.
var mx = 10;   // Nombre màxim de cercles

function setup() {
  createCanvas(400, 400); // Creem el canvas
  background(220);   // Li posem un fons
  noStroke();     // No volem filet als cercles
  for (var i = 0; i < 10; i++){
    circX[i] = -100;
    circY[i] = -100;
} 
  fill(0);
}

function mouseClicked() { // Quan es fa clic amb el ratolí
 esborrar(pos, mx);       // Esborrem el cercle que toca
 circX[pos] = mouseX;     // Guardem la posició del ratolí
 circY[pos] = mouseY;
 ellipse(circX[pos],circY[pos],50,50); // Dibuixem el nou cercle
 pos++;                    // Incrementem la variable pos.
 if (pos === mx){          // Si pos val mx li donem el valor de
  pos = 0;                 // 0. Així controlem el nombre de
 }                         // cercles.
}

function esborrar(element, mx) {
  background(220);
  for (var i = 0; i < element; i++){ // Pintem de 0 a pos
    ellipse(circX[i],circY[i],50,50);
}
  for (i = element+1; i < mx; i++){ // Pintem de pos fins al final
    ellipse(circX[i],circY[i],50,50);
 }
}

Ara podem mirar l’exemple 11-8. Aquest exemple fa servir dos arrays (igual que hem fet amb el nostre exemple) per a guardar la informació de les posicions per on ha passat el cercle i, així, poder fer un rastre. Com que el cercle es dibuixa seguint el ratolí, aquí sí que es fa tot dins de la funció draw().

Fem una ullada a l’exemple:

var num = 60; // Mida del rastre. Si l’incrementem, el rastre serà
              // més llarg
var x = [];
var y = [];

function setup() {
  createCanvas(240, 120);
  noStroke();
           // Inicialitzem les dues taules posant 0 a totes
           // les posicions. És convenient posar sempre un valor
           // inicial a totes les variables que fem servir.
  for (var i = 0; i < num; i++) {
    x[i] = 0;
    y[i] = 0;
 }
}
function draw() {
  background(0); // Esborrem la pantalla per a tornar a dibuixar-ho
                 // tot de nou
      // Mou tots els valors de les variables a una posició més alta
      // Així manté l’històric dels llocs pels quals ha passat el
      // cercle.
  for (var i = num-1; i > 0; i--) {
    x[i] = x[i-1];
    y[i] = y[i-1];
}
// Guarda la posició actual del ratolí al primer element de les
// dues taules
x[0] = mouseX; // Set the first element
y[0] = mouseY; // Set the first element
// Dibuixa tots els cercles, tant el primer com els que fan el
// rastre. Va fent el color del cercle més fosc a mesura que
// la posició és més gran.
  for (var i = 0; i < num; i++) {
    fill(i * 4);
    ellipse(x[i], y[i], 40, 40);
 }
}

La pàgina 174 del llibre fa una explicació de com es van movent els valors per a poder fer el rastre.

Abans d’acabar, el llibre posa dos exemples més, el 11-9 i l’11-10, però fa servir objectes i és un tema que, ara mateix, només veurem una mica per sobre, així que no els farem servir a l’assignatura.