3. Repte 3. Interaccions

3.2. Les funcions draw() i setup()

Ja hem comentat en reptes anteriors que el codi que posem a la funció setup() només s’executa un cop, mentre que el que posem a la funció draw() s’executa contínuament. Com explica el llibre, la funció draw() s’executa 60 cops per segon (més endavant veurem que podem modificar aquesta velocitat) i per a demostrar-ho ens proposa executar el codi de l’exemple 5-1:

function draw() {
  // Displays the frame count to the console
  print("I’m drawing");
  print(frameCount);
}

Sí, sense res més, sense la funció setup().

Aquest programa escriurà a la consola JavaScript la frase «I’m drawing» i el nombre de fotogrames que s’han executat. La variable frameCount, guarda el nombre de fotogrames que s’han visualitzat des del començament de l’execució del codi. Com hem vist, per defecte, es visualitzen 60 fotogrames per segon.

En aquesta captura de pantalla podeu veure com es va escrivint el text a la consola cada cop que s’executa la funció draw().

L’exemple 5-2 proposa una cosa semblant, però fent servir la funció setup() i la funció draw() per a comparar els resultats. Segur que sense executar el programa ja us feu una idea de què és el que passarà.

Al final d’aquest exemple ens explica els tres llocs on podem posar codi en un programa p5.js:

  1. Fora de setup() i draw() posarem les declaracions de variables.
  2. Dins de setup() posarem el codi que només s’hagi d’executar un cop.
  3. Dins de draw() posarem el codi que s’executa contínuament.

Com que la resta d’exemples del capítol 5 són força clars, us recomanem que els feu tots. A continuació, us fem uns breus aclariments de punts que pensem que poden generar algun dubte.

Per a provar aquests exemples, podeu feu servir l’editor de p5.js.

La posició del ratolí

Els exemples 5-4 i 5-5 són molt semblants. En tots dos casos a la funció setup() creem el canvas, definim el color (negre) i la transparència (102 sobre 255) amb la instrucció fill() i diem que no voldrem vores amb la instrucció noStroke(). L’única diferència entre els dos exemples és la crida a la funció background() al començament de la funció draw(). Aquesta funció torna a pintar tot el fons del color indicat, esborrant el que hi hagués abans.

En els dos exemples, a la funció draw() només hi tenim una instrucció:

ellipse(mouseX, mouseY, 9, 9);

Què significa això? Què són les variables mouseX i mouseY?

Bé, és fàcil de suposar que aquestes dues variables ens diuen quina és la posició del ratolí en el moment actual. Així, el codi de l’exemple dibuixa un cercle en la posició on hi ha el ratolí. Com que la funció draw() es repeteix 60 cops per segon, es dibuixen 60 cercles cada segon. I, així, si movem el ratolí a poc a poc, es dibuixarà una línia força negre i, en canvi, si el movem ràpid podem, fins i tot, deixar petits espais entre els cercles.

En l’exemple 5-4, tot el que es va dibuixant es queda al canvas, mentre que en l’exemple 5-5, cada cop es pinta el fons just abans de dibuixar el cercle. D’aquesta manera dona la sensació que el cercle es mou, tot i que el que estem fent és dibuixar-lo de nou cada cop.

En l’exemple 5-6, s’introdueixen les variables pmouseX i pmouseY. Aquestes variables ens diuen quina era la posició del ratolí en el fotograma anterior. Així, podem pintar una línia continua en comptes de només punts separats com fèiem en l’exemple anterior. Aquesta és la instrucció clau:

line(mouseX, mouseY, pmouseX, pmouseY);

Dibuixem una línia des de la posició actual del ratolí mouseX, mouseY, a la posició anterior del ratolí pmouseX, pmouseY. Podem dibuixar la línia al revés (de la posició anterior a l’actual)? Hi haurà alguna diferència? Proveu-ho.

L’exemple 5-7 és fàcil d’entendre, encara que inclou dues funcions noves: dist() i strokeWeight() Tot i que amb el context es pot saber bé el que fan, recordeu que al manual de referència de p5.js es pot trobar la informació completa d’aquestes instruccions.

L’exemple 5-8 és més complex, no solament pel que fa, sinó que també per les instruccions que fa servir. Recordeu que la instrucció x += y és equivalent a x = x + y.

El que pretén aquest exemple és mostrar una manera de fer que el cursor segueixi el ratolí lentament en comptes d’instantàniament com ho fa en els exemples que hem vist fins ara. De fet, tal com està fet, com més a prop està el ratolí, més lentament s’apropa el dibuix a aquest.

Revisem aquest exemple:

var x = 0;         // És la posició x on dibuixarem el cercle
var easing = 0.01; // Indica quant s’incrementa la velocitat
                   // segons com de lluny estigui el ratolí

function setup() {
  createCanvas(220, 120);
}

function draw() {
  var targetX = mouseX;        // Guardem la posició x del ratolí
  x += (targetX - x) * easing; // Aquesta és l’operació clau
                               // l’expliquem amb aquest codi

  ellipse(x, 40, 12, 12);
  print(targetX + " : " + x); // Escriu a la consola la posició
                              // x del ratolí i l’x on dibuixem
                              // el cercle
}

Comencem dibuixant el cercle en la posició x=0. Dins de la funció draw() guardem la posició x del ratolí i, per a decidir on dibuixarem el proper cercle, el que fem és calcular la diferència de posició entre el ratolí (targetX) i el darrer cercle que hem dibuixat (x) i la multipliquem per aquesta variable easing que farà que la distància sigui major com més gran sigui el valor d’aquesta variable.

Proveu l’exemple i proveu de canviar el valor de la variable easing. Mireu els valors que s’escriuen a la consola. També jugueu amb la mida del canvas. Potser, si el fem més llarg podem veure millor l’efecte (quin dels dos valors hem de modificar per a canviar l’amplada del canvas?).

En l’exemple 5-9 següent, a més velocitat major serà el cercle que es dibuixa.

La idea és la mateixa que la de l’exercici anterior i, fins i tot, pot resultar més clar. Però el codi és una mica més complicat. Què fan tantes variables?

Les variables x i y guarden el valor de fins on toca dibuixar la línia.

Les variables px i py guarden el valor de la posició anterior on es va dibuixar (si us fixeu, guarden els valors d’x i y just abans d’acabar la funció draw().

Les variables targetX i targetY es fan servir per a guardar la posició del ratolí en un moment donat. En realitat, l’ús de les variables targetX i targetY no és imprescindible i podem fer el mateix amb aquest codi una mica més simple:

var x = 0;
var y = 0;
var px = 0;
var py = 0;
var easing = 0.05;

function setup() {
      createCanvas(480, 480);
      stroke(0, 102);
}
function draw() {
     x += (mouseX - x) * easing;
     y += (mouseY - y) * easing;
     var weight = dist(x, y, px, py);
     strokeWeight(weight);
     line(x, y, px, py);
     py = y;
     px = x;
}

Ara, canvieu el valor que assignem a la variable easing, posant 0.5 en comptes de 0.05, i intenteu respondre aquesta pregunta:

Quins dos canvis es produeixen quan modifiquem la variable easing?