Joan Soler-Adillon || Tutorial de Processing
Despatx 52.803 (Campus de la comunicació, UPF) || 93 542 1238
----------------------------------------------------------------
----------------------------------------------------------------
TUTORIAL DE PROCESSING || Secció 8: Matrius (arrays)
1. Matrius
2. Matrius i bucles
3. Exemples
Una matriu és una llista de valors. És un contenidor de múltiples variables, de tal o qual tipus de dades, als quals ens referim per la seva posició dins d'aquesta llista.
Un cop hem vist bucles, condicionals, i variables, molt fàcilment un es pot trobar en una situació on es comencen a crear múltiples variables que tenen a veure entre elles. Per exemple, si en els nostres exemples de la pilota volem tenir-ne més d'una, hem de fer alguna cosa com posX1, posX2, posX3, etc.
Doncs amb això les matrius ens poden ajudar.Podem tenir un sol contenidor de posicions: posicionsX, p.e., on pot haver-hi els valors que faci falta.
La cosa va així:
//creem una matriu d'enters anomenat llistaPosicions: int[] llistaPosicions = { 14, 94, 120, 80 };
Anem per parts: int[] indica que declarem una matriu del tipus de dades int, res més. És a dir, una llista d'enters. "llistaPosicions" és el nom que li donem a la matriu, i els números que van entre claus i separats per comes en són els valors.
Per a accedir a un d'aquests valors, si amb una variable normal ens n'hi ha prou amb el seu nom, en un array necessitem el nom de l'array i l'índex (la posició de l'element en qüestió dins l'array). Atenció: el primer element d'un array està sempre en la posició zero!. Així
es refereix al tercer valor dins la matriu. En l'exemple anterior, 120. Es pot comprobar amb el codi que segueix:
//creem una matriu d'enters anomenat llistaPosicions: int[] llistaPosicions = { 14, 94, 120, 80 }; //i n'imprimim un parell de valores a la consola: println(llistaPosicions[0]); println(llistaPosicions[3]);
Així doncs, una matriu no es res més (ni menys) que un conjunt de variables, que podem utilizar como a tals:
//creem una matriu d'enters anomenat llistaPosicions int[] llistaPosicions = { 14, 94, 120, 80 }; size(200,200); // i dibuixem quatre elipses segons l'array: ellipse(llistaPosicions[0], 100,25,25); ellipse(llistaPosicions[1], 100,25,25); ellipse(llistaPosicions[2], 100,25,25); ellipse(llistaPosicions[3], 100,25,25);
Tambié és útil saber que per a canviar un valor en una matriu. Es realitza una assignació com amb qualsevol variable:
int[] llistaPosicions = { 14, 94, 120, 80 }; // passen coses... //i canviem: llistaPosicions [0] = 99; println llistaPosicions[0]);
En la secció d'exemples es pot veure altra manera de declarar una matriu, que consisteix a especificar la mida de la mateixa però no els valors del que conté:
Llavors, a cadascuna de les posicions de la matriu que hem creat li podem assignar un valor tal com ho fem amb les variables normals (cosa que, de fet, pot fer-se també per a després canviar els valors, igual que en el cas de crear la matriu tal com hem vist en el primer exemple):
Per arrays grans, aquest sistema resulta ser molt més eficient en la majoria de casos.
2.- Matrius i bucles
Allí on el potencial de les matrius s'aprofita millor, és en la seva combinació amb els bucles. De fet, és bastant lògic que si tenim una estructura que pot guardar diverses variables indexades, i altra que ens permet iterar una mateixa acció en diferents elements, les utilitzem conjuntament.
Si no, només cal mirar l'últim exemple de la secció anterior, on el fet d'estar utilitzant una matriu no ens redueix per res la quantitat de codi que cal escriure. Seria exactament el mateix si utilitzéssim quatre variables. En canvi, si combinem la matriu amb un bucle, podem fer una cosa així:
int[] llistaPosicions = { 14, 94, 120, 80 }; size(200,200); // i dibuixem les elipses via bucle: for(int i=0; i<4; i++){ ellipse(llistaPosicions[i], 100,25,25); }
El resultat gràfic és exactament el mateix, però aquí, gràcies a utilitzar llistaPosicions[i] dins el bucle, estem aprofitant les iteracions del bucle per a afectar tots els elements de l'array. Quatre en aquest cas, però que poden ser moltíssims més.
int[] llistaPosicions = { 14, 25, 39, 64, 94, 109, 122, 150, 170, 178, 190 }; size(200,200); // i dibuixem les elipses via bucle: for(int i=0; i<11; i++){ ellipse(llistaPosicions[i], 100,25,25); }
Però, què passa quan tenim ja molts elements? Contar-los pot arribar a ser un xic tediós, i, sobre tot, ineficient si canviem en algun moment la quantitat de valors que li donem a l'array en la declaració.
Per dolucionar-ho, podem susbstituir en l'exemple anterior la línia de declaració del for loop per:
for(int i=0; i<llistaPosicions.length; i++){
Així utilitzem una variable que Processing ja calcula per a nosaltres: array.length que, com el seu nom indica, correspon a la quantitat d'elements presents en la matriu (array) en qüestió.
Atenció: array.length ens indica el nombre d'elements en la matriu, però l'índex d'aquests elements comença per 0, així que de fet array[array.length] no existeix! D'aquí que en la condició li diem al bucle que s'executi quan "i" és MENOR a llistaPosicions.length.
Finalment, aprofitant el random per a ser més eficients, podem fer el que segueix:
float[] llistaPosicions = new float[13]; size(200,200); // creem aleatoriament totes les posicions: for(int i=0; i<13; i++){ llistaPosicions[i] = random(0,200); } // i dibuixem les elipses via bucle: for(int i=0; i<13; i++){ ellipse(llistaPosicions[i], 100,25,25); }
3.- Exemples
Hem vist en el punt 1 que es poden declarar variables sense assignar-les-hi valors immediatament. Això, per exemple, ho podem utilitzar per a... sorpresa! Un exemple de pilotetes!
Amb això dins el SETUP:
for(int i = 0; i<numeroBolas; i++){
posicionsX[i] = width/2;
posicionsY[i] = height/2;
velocitatsX[i] = random(2,6);
velocitatsY[i] = random(2,6);
}
Iniciem una sèrie de posicions en l'eix X i Y en el punt mig de la finestra, i unes velocitats X i Y entre 2 i 6. Les quatre matrius amb els quals treballem aquí són de floats.
Un cop fet això, i sense canviar gairebé res del codi de l'exemple amb una sola pilota, podem multiplicar els elements que afectem. Així, dintre del DRAW:
//iniciem un bucle per tal que realitzi l'acció per tots els
//elements de la matriu
for(int i = 0; i<numeroBoles; i++){
//actualitzem les posicions
posicionsX[i] += velocitatsX[i];
posicionsY[i] += velocitatsY[i];
//comprobem límits X
if((posicionsX[i]<0)||(posicionsX[i]>width)){
velocitatsX[i] = -velocitatsX[i];
}
//comprobem límits Y
if((posicionsY[i]<0)||(posicionsY[i]>height)){
velocitatsY[i] = -velocitatsY[i];
}
}
//acabat el procés, creem un altre bucle
//on dibuixarem les elipses
for(int i = 0; i<numeroBoles; i++){
ellipse(posicionsX[i],posicionsY[i],sz,sz);
}
L'exemple complet de les multiboles és aquí:
Source code: arraybball
Tambié podem afegir colors, i finsi i tot un "reset" utilitzant una funció de sistema: el mousePressed:
void mousePressed(){ //reinicialitzem les velocitats: for(int i = 0; i<numeroBolas; i++){ velocidadesX[i] = random(2,10); velocidadesY[i] = random(2,10); } }
Recordeu que MousePressed es una funció que cal colocar fora del setup i del draw, ja que s'executa independentment d'aquests dos processos.
Podeu mirar colorMode() per entendre com s'utilitza en l'exemple que segueix el color a l'exemple següent:
Source code: arraybballcolors
Un darrer exemple, un pèl més complex, però que serveix per introduir l'ús de text:
Source code: texttext
---------------------------------------------------------------------------------------