Tema 6

Operacions amb formes

Aprèn a combinar formes simples per construir figures complexes. Crea els teus propis "blocs de construcció" amb funcions, i organitza el codi amb push() i pop().

De formes simples a estructures complexes

Fins ara hem dibuixat formes independents: un cercle, un rectangle, un triangle. Però qualsevol objecte real es compon de múltiples peces. Per exemple, una cara té ulls, nas i boca. Un cotxe té carrosseria, rodes i finestres.

El repte és agrupar formes per crear entitats amb significat. Això es pot fer directament dibuixant diverses formes al draw(), però aviat veurem tècniques per organitzar millor el codi.

// Cara completa feta de formes simples
fill(255,220,200); ellipse(100,100,120,120); // cap
fill(255); ellipse(75,85,25,25); ellipse(125,85,25,25); // blanc dels ulls
fill(0); ellipse(75,85,10,10); ellipse(125,85,10,10); // pupil·les
fill(255,100,100); arc(100,120,40,25,0,PI); // boca somrient

De moment tot està barrejat al draw(). Si volem dibuixar diverses cares, hauríem de repetir el codi... tret que fem servir funcions.

Funcions personalitzades: els teus propis blocs

Una funció és un bloc de codi amb nom que podem cridar (invocar) tantes vegades com vulguem. Podem crear funcions que dibuixin un objecte complet, passant paràmetres com la posició o la mida.

Exemple: creem la funció dibuixaCara(x, y) per dibuixar una cara a la posició que vulguem.

function setup() {
  createCanvas(300, 200);
  background(240);
}

function draw() {
  dibuixaCara(90, 100);
  dibuixaCara(210, 100);
}

// Funció que dibuixa una cara a (x,y)
function dibuixaCara(x, y) {
  fill(255,220,200); ellipse(x, y, 80, 80);
  fill(255); ellipse(x-15, y-10, 18, 18); ellipse(x+15, y-10, 18, 18);
  fill(0); ellipse(x-15, y-10, 8, 8); ellipse(x+15, y-10, 8, 8);
  fill(255,100,100); arc(x, y+15, 30, 18, 0, PI);
}

Avantatge: Ara podem dibuixar cares a qualsevol lloc sense repetir codi. Si volem canviar el disseny, només ho fem un cop.

Paràmetres: fent les funcions més flexibles

Podem passar més paràmetres a les nostres funcions, com la mida, el color o qualsevol altra propietat. Així una mateixa funció pot generar molta varietat.

// Funció que dibuixa una flor amb paràmetres de posició, mida i color
function dibuixaFlor(x, y, mida, col) {
  fill(col); noStroke();
  for (let i = 0; i < 6; i++) {
    let angle = map(i, 0, 6, 0, TWO_PI);
    let px = x + cos(angle) * mida * 0.6;
    let py = y + sin(angle) * mida * 0.6;
    ellipse(px, py, mida * 0.5, mida * 0.5);
  }
  fill(255, 255, 0);
  ellipse(x, y, mida * 0.4, mida * 0.4);
}

push() i pop(): dibuixar en capes

Quan fem servir funcions per dibuixar objectes, sovint volem canviar temporalment propietats (colors, gruixos, o més endavant transformacions) sense afectar la resta del dibuix. push() desa l'estat actual i pop() el restaura.

S'introdueixen aquí perquè són essencials per a funcions netes, tot i que les transformacions fortes les veurem al Tema 7.

function dibuixaCasa(x, y, escala, col) {
  push();                  // guardem estat (colors, transformacions...)
  translate(x, y);         // movem origen a (x,y)
  scale(escala);           // escalem (Tema 7 en detall)
  fill(col); noStroke();
  rect(-25, 0, 50, 40);   // cos de la casa
  triangle(-30, 0, 0, -25, 30, 0); // teulada
  fill(120,80,60); rect(-8, -15, 16, 25); // porta
  fill(200,230,255); rect(10, -30, 12, 12); // finestra
  pop();                   // restablim estat original
}

Sense push()/pop(), els canvis de translate() i scale() s'acumularien i descol·locarien la segona casa.

Composar escenes amb funcions

Un cop tenim funcions per a objectes individuals (cara, casa, arbre, cotxe...), podem combinar-les per crear escenes completes amb molt poc codi.

function draw() {
  background(135,206,235); // cel
  fill(100,180,100); rect(0,160,width,40); // terra
  fill(255,255,0); ellipse(320,40,40,40); // sol

  dibuixaCasa(50, 150, 0.8, color(255,220,180));
  dibuixaCasa(130, 150, 1, color(255,200,200));
  dibuixaCasa(230, 150, 0.6, color(200,220,255));
  dibuixaCasa(300, 150, 0.9, color(255,240,200));
}

Exemples creatius pas a pas

Bosc modular

Creem una funció arbre(x, y, h) i la cridem moltes vegades amb paràmetres aleatoris.

function arbre(x, y, h) {
  push(); translate(x, y);
  fill(120,80,50); rect(-4, 0, 8, -h);
  fill(30,150,70);
  ellipse(0, -h, h*0.5, h*0.6);
  ellipse(-8, -h-10, h*0.4, h*0.5);
  ellipse(8, -h-10, h*0.4, h*0.5);
  pop();
}

Skyline urbà

Funció edifici(x, ample, alt) per construir una ciutat amb varietat d'edificis.

function edifici(x, ample, alcada) {
  let y = height - alcada;
  push(); noStroke();
  fill(60,60,100); rect(x, y, ample, alcada);
  for (let wy = y+10; wy < height; wy += 15) {
    for (let wx = x+5; wx < x+ample-5; wx += 10) {
      fill(255,255,200, random(100,255));
      rect(wx, wy, 5, 5);
    }
  }
  pop();
}

Pensar modularment: el poder de les funcions

Quan descomposem un dibuix complex en funcions més petites, estem aplicant el principi de modularitat. Això fa que el codi sigui:

  • Més llegible: cada funció té un nom descriptiu.
  • Reutilitzable: podem fer servir la mateixa funció en múltiples projectes.
  • Fàcil de modificar: si volem canviar el disseny d'un element, només toquem la seva funció.
  • Escalable: podem combinar funcions per crear escenes cada cop més riques.
Consell d'artista-programador: Crea una "biblioteca" personal d'objectes reutilitzables (arbres, cases, estrelles, ones...) al llarg del curs. En el projecte final et seran molt útils!

Exercicis per practicar

  1. Dissenya una funció cotxe(x, y, colorCarrosseria) amb almenys 6 formes (carrosseria, rodes, finestres, llums).
  2. Crea una funció ninotDeNeu(x, y, mida) amb tres cercles superposats i petits detalls (ulls, nas de pastanaga, barret).
  3. Utilitza push() i pop() per dibuixar 5 estrelles de mar de colors i mides diferents repartides per la platja.
  4. Escriu una funció vaixell(x, y) que dibuixi un veler. Després crida-la diverses vegades per crear una regata.
  5. Repte: Dissenya un "monstre" personalitzable amb paràmetres: nombre d'ulls, color del cos, mida de les dents i posició. Fes-ne una família de 3 monstres diferents.

Reflexió artística

L'art no és només el resultat final, sinó també l'arquitectura del procés creatiu. Quan dissenyes una funció per dibuixar un objecte, estàs prenent decisions sobre què és essencial i què és accessori, sobre com es relacionen les parts amb el tot. Aquesta manera de pensar –descomposar, parametritzar, recombinar– és la base del pensament computacional aplicat a l'art. Et permetrà crear obres cada cop més ambicioses sense perdre't en la complexitat. Les funcions són els teus pinzells personalitzats: dissenya'ls amb cura i el teu estil brillarà en cada traç.

Mini-projecte del Tema 6

Crea una "Escena modular interactiva" amb les següents condicions:

  • Defineix almenys 3 funcions personalitzades que dibuixin objectes diferents (casa, arbre, vehicle, persona, núvol, animal...).
  • Cada funció ha de tenir almenys 3 paràmetres (posició, mida, color...).
  • Utilitza push() i pop() a dins de cada funció per aïllar canvis d'estil o transformacions.
  • Compon una escena completa (paisatge, ciutat, fons marí, espai exterior...) al draw() cridant les funcions múltiples vegades.
  • Opcional: fes que un dels paràmetres depengui del ratolí (mouseX o mouseY) per afegir interactivitat.

Comparteix la teva escena modular i les funcions que has creat. Explica com has decidit descomposar els elements i quins paràmetres has triat.