Funzioni setup() e draw()
Le funzioni
blocchi di istruzioni che possono essere eseguite più di una volta all'interno di un programma
possono avere parametri di ingresso e
restituire un valore in uscita
Definire una funzione
function nomeFunzione( param1, param2, ... )
{
istruzioni da eseguire
return risultato;
}
nome da utilizzare per far eseguire le istruzioni; deve avere le stesse caratteristiche dei nomi delle variabili.
nomi degli eventuali parametri da passare alla funzione; se non sono necessari le parentesi possono essere lasciate vuote ma sono sempre richieste.
restituisce il valore elaborato e interrompe l'esecuzione della funzione.
L'istruzione return può essere evitata se non è necessario restituire un valore o se la funzione non dev'essere interrotta in anticipo.
Chiamare una funzione
Le funzioni non vengono eseguite finché non vengono chiamate
var nomeVariabile = nomeFunzione( param1, ... );
variabile che riceverà il risultato delle istruzioni della funzione.
Le "istruzioni" viste finora (fill(), rect(), ecc.) sono in realtà funzioni che non restituiscono valori.
Funzioni setup() e draw()
function setup()
{
inizializzazioni
}
function draw()
{
eventuale aggiornamento dati e
istruzioni di disegno del fotogramma
}
istruzioni da eseguire una sola volta prima di iniziare a disegnare tutti i fotogrammi.
operazioni di aggiornamento ed elaborazione dei dati usati per disegnare.
istruzioni grafiche che disegnano il singolo fotogramma in base ai valori elaborati.
Disegno progressivo
function setup()
{
createCanvas( 200, 200 );
background( 200 );
}
function draw()
{
ellipse( random(width),random(height), 20,20 );
}
sfondo colorato una sola volta prima del disegno di tutti i fotogrammi.

Disegno "animato"
function setup()
{
createCanvas( 200, 200 );
}
function draw()
{
background( 200 );
ellipse( random(width),random(height), 20,20 );
}
sfondo colorato prima di disegnare ogni fotogramma.

Provare a colorare lo sfondo con un grigio quasi trasparente aggiungendo, ad esempio, il parametro 32 all'istruzione background().
Variabili condivise (globali)
var y;
function setup() {
y = 0;
background( 200 );
}
function draw() {
y = y+2;
var x = random( 48, 52 );
ellipse( x,y, 6,6 );
}
variabile globale: modificabile e utilizzabile in tutte le funzioni.
variabile locale: visibile all'interno del blocco (fra parentesi graffe) in cui viene definita.

Controllo del draw()
noLoop();
loop();
frameRate( fps );
interrompe la chiamata ciclica.
riprende la chiamata ciclica.
permette di impostare il numero di chiamate al secondo (frames per second).
Come impostazione predefinita il draw() dovrebbero essere eseguito 60 volte al secondo. Per verificare il numero effettivo di chiamate, si può utilizzare la funzione frameRate() senza parametri.
Controllo del draw(): esempio
var y;
function setup() {
y = 0;
background( 200 );
frameRate(20);
}
function draw() {
y = y+2;
var x = random( 48, 52 );
ellipse( x,y, 6,6 );
if (y > 80) {
noLoop();
}
}
abbassa il numero di chiamate del draw() a 20 fps.
se il valore di y è superiore a 80...
ferma le chiamate del draw(): il codice smetterà di disegnare altri cerchi.

Cinetismi di base
Scorrere del tempo: secondi
var angoloTacca = 0.10471975511965977; // TWO_PI / 60;
function draw() {
background(200);
var angolo = second() * angoloTacca;
translate( 50,50 );
rotate( angolo );
line( 0,0, 0,-50 );
}
al di fuori del setup() non è possibile usare le costanti di p5.js perché non sono ancora state definite.
restituisce il numero di secondi (da 0 a 59) reali.
la direzione della lancetta è sempre quella delle 12:00; la direzione giusta viene impostata attraverso l'istruzione rotate().

Processing permette di ottenere altre informazioni sull'ora e la data correnti [vedi sezione "IO" in "p5.js Reference"].
La variabile di sistema frameCount
function draw() {
background(205);
var y = frameCount - 1;
ellipse( 50,y, 10,10 );
}
la variabile frameCount è gestita da p5.js e contiene il numero di fotogramma corrente.
il primo valore di frameCount è 1; per partire da 0 è necessario sottrarre 1 al suo valore.

Uso di frameCount con l'operatore % (modulo)
function draw() {
background(205);
var y = (frameCount-1) % height;
ellipse( 50,y, 10,10 );
}
l'operatore % restituisce il resto della divisione e permette di ripartire da 0 ogni volta che frameCount-1 diventa un multiplo esatto di height.

Interpolazioni fra valori
Problema: ricavare e sincronizzare i valori intermedi di uno o più parametri, anche con intervalli diversi.

Soluzione: usare un valore di controllo, con decimali, che va da 0 (inizio interpolazione) a 1 (fine interpolazione).
Uso di una variabile di controllo delle interpolazioni
var t = 0; // variabile di controllo
var tVel = 0.05; // velocità d'interpolazione
function draw() {
istruzioni di disegno parametrizzato con t
t += tVel; // incrementa t
if (t > 1) { // interpolazione finita
t = 0; // ricomincia daccapo
}
}
stabilita la durata dell'interpolazione in fotogrammi (ad es. durataF) il valore si può ottenere con: 1.0 / durataF.
la variabile di controllo viene reimpostata a 0 ogni volta che supera 1; naturalmente l'if può contenere qualsiasi istruzione si voglia far eseguire alla fine dell'interpolazione, compreso l'azzeramento di tVel per interrompere la variazione ciclica.
Interpolazioni con la funzione lerp()
Usando lerp(start,stop,t) si possono ottenere i valori intermedi fra start e stop.
var t = 0;
var tVel = 0.05;
function setup() {
background( 200 );
}
function draw() {
var x = lerp( 0, 99, t );
var y = lerp( 30, 70, t );
ellipse( x,y, 20,20 );
t += tVel;
if (t > 1.0001) { t = 0; }
}
dovrebbe essere 1 ma JavaScript può dare qualche problema di precisione nelle operazioni con i valori decimali.

Interpolazioni su curve di Bézier
Usando la variabile t nella funzione bezierPoint() si possono ottenere le coordinate dei punti di una curva di Bézier.
var t = 0;
var tVel = 0.05;
function setup() {
background( 200 );
}
function draw() {
var x = bezierPoint( 15, 90, 10, 85, t );
var y = bezierPoint( 20, 25, 75, 80, t );
ellipse( x,y, 20,20 );
t += tVel;
if (t > 1.0001) { t = 0; }
}

Interpolazioni dei colori
var t = 0;
var tVel = 0.01;
var rosso;
var verde;
function setup() {
rosso = color(255,0,0);
verde = color(0,255,0);
}
function draw() {
var interpolato = lerpColor( rosso,verde, t );
background( interpolato );
t += tVel;
if (t > 1.0001) { t = 0; }
}
Usando la funzione lerpColor() si possono interpolare contemporaneamente i valori RGB di un colore iniziale (rosso) e uno finale (verde).

Interpolazioni oscillanti (avanti e indietro)
var t = 0;
var tVel = 0.01;
var rosso;
var verde;
function setup() {
rosso = color(255,0,0);
verde = color(0,255,0);
}
function draw() {
var interpolato = lerpColor( rosso,verde, t );
background( interpolato );
t += tVel;
if (t < 0 || t > 1.0001) {
tVel = -tVel;
t += tVel*2;
}
}
la velocità viene invertita se t esce dai limiti minimo e massimo; con tVel negativo l'interpolazione andrà da 1 a 0.
fa tornare indietro il valore di t in modo che rientri nei propri limiti senza assumere la posizione avuta prima di uscire.

Andamento delle interpolazioni
Andamento lineare

t sono proporzionaliAndamento non lineare

Attenuazioni nelle interpolazioni (easing)

Altri andamenti non lineari si possono trovare e provare su easings.net.
Andamenti elementari con bezierPoint()

Lo sketch può essere provato (usando i tasti freccia) su OpenProcessing.
Funzioni di easing
var t = 0;
var tVel = 0.01;
function draw() {
var y = elasticOut( 10, 80, t );
background(200);
ellipse( 50,y, 11,11 );
t += tVel;
if (t > 1.0001) { t = 0; }
}
function elasticOut( start, stop, t ) {
var ts=t*t;
var tc=ts*t;
return start+(stop-start)*(33*tc*ts + -106*ts*ts + 126*tc + -67*ts + 15*t);
}
viene chiamata una funzione che non fa parte di p5.js ma che è stata definita all'interno dello stesso sketch. La funzione è un riadattamento delle funzioni di Robert Penner.

Al momento non è disponibile una libreria ufficiale che gestisca automaticamente anche la variabile di controllo t. Nell'attesa si può iniziare a utilizzare la libreria p5.ijeoma.js.
Interattività (con la tastiera e il mouse)
Implementazione dell'interattività
P5.js gestisce automaticamente il rilevamento degli input mettendo a disposizione:
variabili di sistema con lo stato dei dispositivi di input
funzioni di sistema chiamate al verificarsi di un evento
function setup() {
uso variabili di sistema
}
function draw() {
uso variabili di sistema
}
function nomeEvento() {
uso variabili di sistema
}
i valori di input possono essere letti e usati direttamente.
i nomi delle funzioni sono solitamente composti dal mone della periferica e dall'evento avvenuto, ad esempio mousePressed().
Variabili di sistema della tastiera
function setup() {
textSize( 50 );
textAlign( CENTER );
}
function draw() {
background(200);
if (keyIsPressed) {
text( key, 50,60 );
}
}
è true se un tasto della tastiera risulta premuto.
contiene il codice del carattere premuto.

Funzioni di sistema della tastiera
var diametro = 20;
function draw() {
background( 200 );
ellipse( 50,50, diametro,diametro );
}
function keyPressed() {
if (keyCode == UP_ARROW) {
diametro += 2;
} else if (keyCode == DOWN_ARROW) {
diametro -= 2;
}
}
funzione chiamata da p5.js quando un tasto della tastiera viene premuto.
contiene il codice del tasto (non del carattere) premuto.

Variabili di sistema del mouse
function draw() {
background( 200 );
ellipse( mouseX,mouseY, 20,20 );
}
contengono le attuali coordinate del mouse.

Per far sparire il cursore del mouse è possibile definire la funzione setup() e inserirvi l'istruzione noCursor().
Funzioni di sistema del mouse
var colore = "white";
var posX = 50;
var posY = 50;
var raggio = 30;
function draw() {
background( 200 );
fill( colore );
ellipse( posX,posY, raggio*2,raggio*2 );
}
function mouseMoved() {
if (dist( mouseX,mouseY, posX,posY ) < raggio) {
colore = "yellow";
} else {
colore = "white";
}
}
se non è necessario lavorare sulle componenti cromatiche i colori possono essere impostati anche con uno dei nomi predefiniti.
funzione chiamata da p5.js ogni volta che il cursore del mouse cambia posizione.
un punto (mouseX,mouseY) si trova all'interno di un cerchio quando la sua distanza dal centro (posX,posY) è inferiore al raggio.

Interazioni temporali
Posizione precedente del mouse
function setup() {
createCanvas( 200,200 );
background( 200 );
}
function draw() {
if (mouseIsPressed) {
line( pmouseX,pmouseY, mouseX,mouseY );
}
}
è true se un tasto del mouse risulta premuto.
contengono le coordinate del mouse del fotogramma precedente.

Memorizzare le posizioni precedenti del mouse
Per ottenere le coordinate di più fotogrammi si possono usare array in cui far "slittare" gli elementi a ogni draw().

Per limitare il numero di elementi dell'array si può eliminare l'ultimo elemento ogni volta che viene superato un limite massimo.
Usare le posizioni precedenti del mouse
var posX = [];
var posY = [];
function draw()
{
background( 200 );
posX.unshift( mouseX );
posY.unshift( mouseY );
if (posX.length > 30) {
posX.pop();
posY.pop();
}
for (var i = posX.length-1; i >= 0; --i) {
var diam = 30-i; // diametro crescente
ellipse( posX[i],posY[i], diam,diam );
}
}
aggiungi le attuali coordinate del cursore del mouse in cima agli array.
elimina l'ultimo elemento di ogni array, solo se il loro numero supera i 30.
esegue un for dall'ultimo elemento (posX.length-1) al primo (0).

Dipingere con “pennelli” dinamici
function setup()
{
createCanvas( 400,400 );
background( 0 );
stroke( 255,64 );
}
function draw()
{
if (mouseIsPressed) {
translate( mouseX,mouseY );
rotate( frameCount/10.0 );
line( 0,0, 80,0 );
}
}
l'uso di un colore semitrasparente, in presenza di sovrapposizioni, permette di ottenere una maggiore profondità cromatica.
fa in modo che la linea venga disegnata a partire dalla posizione del cursore del mouse.
ruota di un angolo che aumenta a ogni fotogramma di 1/10 di pixel.

Disegnare testi
var phrase = "La poesia è una pittura che si muove e una musica che pensa. ";
var charIndex = 0; // indice del carattare corrente
var charX = 0; // posizione del carattere disegnato
var charY = 0;
function setup() {
createCanvas( 400, 300 );
stroke(255); // contorno caratteri
}
function draw() {
if (dist( charX,charY, mouseX,mouseY ) > 8) {
var char = phrase.charAt(charIndex);
text( char, mouseX,mouseY );
charIndex = (charIndex+1) % phrase.length;
charX = mouseX;
charY = mouseY;
}
}
verifica che la distanza fra l'ultimo carattere disegnato e il cursore del mouse sia superiore a 8 pixel.
ricava il carattere della frase alla posizione charIndex+1.
incrementa l'indice del carattere da visualizzare facendolo ricominciare da 0 ogni volta che raggiunge il valore massimo (phrase.length).

Provare a usare una breve frase palindroma, ad esempio "eppure eruppe", e verificare l'effetto sulla scrittura da destra a sinistra.
La frase iniziale è di Emile Deschamps