Getting Started with Processing

105
Getting Started with Processing Casey Reas e Ben Fry

Transcript of Getting Started with Processing

GettingStartedwithProcessing

Casey Reas e Ben Fry

Getting Started With Processing Casey Reas – Ben Fry

Apprendi la programmazione al computer nel modo più semplice con Processing, un semplice linguaggio che ti permette di usare codice per creare disegni, animazioni, e grafiche interattive.Solitamente i corsi di programmazione iniziano con la teoria, ma questo libro ti permette di saltare direttamente alla creazione di progetti creativi e divertenti.È l'ideale per chiunque voglia imparare la programmazione, e sarà utile come semplice introduzione alla grafica per coloro che hanno già abilità programmative.

Scritto dai fondatori di Processing, questo libro ti accompagna attraverso il processo di apprendimento un passo alla volta per aiutarti ad afferrare i concetti chiave della programmazione.Entra a far parte delle migliaia di hobbisti, studenti e professionisti che hanno scoperto questa piattaforma di educazione libera e gratuita.

>>impara velocemente le basi della programmazione, dalle variabili agli oggetti.>>comprendi i concetti chiave della computer graphic>>conosci l'ambiente di sviluppo di Processing>>Crea grafiche interattive con progetti semplici da seguire>>Usa il prototipo di piattaforma open-source Arduino per controllare la grafica di Processing

Casey Reas è professore al dipartimento di Design Media Arts alla UCLA ed è laureato al MIT media laboratory. Il software di Reas è stato presentato in numerose mostre solistiche e di gruppo negli Stati Uniti, in Europa e in Asia.

Ben Fry è designer, programmatore e autore con sede a Cambridge,nel Massachussetts,ed ha ricevuto la sua laurea di dottorato dal MIT Media Laboratory. Ha lavorato con Casey Reas allo sviluppo di Processing,che ha vinto un Golden Nica dal Prix Ars Electronica nel 2005.

Elogi Anticipati per Getting Started with Processing

“Creare un programma per il computer che sia così semplice da accendere e scrivere una o due righe di codice per poter dire “ciao”. Ora possiede un manuale di circa 500 pagine e un'intera comunità. Questo piccolo libro di Ben e Casey ti permette di disegnare attraverso il computer linee, triangoli e cerchi in pochi minuti.Hanno reso possibile la creazione di programmi al computer in modo umano , e questo non è cosa da poco”.

– John Maeda. Presidente della Rhode Island School of Design

“Getting Started with Processing non è soltanto un modo chiaro di introdurre le basi della programmazione – è divertente! Può sembrare quasi un testo per progredire nell'attività programmativa. Potrai anche decidere di comprarlo anche se non sei mai stato interessato alla programmazione, perchè presto lo diventerai!” .

– Mark Allen Fondatore e Direttore del Machine Project

“Questo è un eccellente inizio per coloro che vogliono affondare i loro passi nella programmazione grafica . Il suo metodo dell' imparare facendo è stato pensato in particolar modo per gli artisti e i designer che molto spesso sono posti al di fuori dai primi approcci alla teoria tradizionale. Il prezzo del libro ed il fatto che l'ambiente di Processing è open source, ne fanno un'ottima scelta per gli studenti”.

-Gillian Crampton SmithFondazione Venezia Professor of Design, IUAV University of Venice

“Processing ha cambiato radicalmente il modo di insegnare programmazione ed è uno dei maggiori fattori del successo di Arduino”.

– Massimo BanziCofondatore di Arduino

“Casey Reas e Ben Fry si sono battuti per l'entusiasmante energia della programmazione creativa in Getting Started in Processing, una guida pratica per creare disegni e grafiche interattive basate sul codice. Reas e Fry sono chiari e diretti ma come artisti non sono spaventati dall'essere un po' eccentrici e fuori dalle righe. Questo è quello che rende potente il loro unico metodo di insegnamento .

– Holly Willis– Direttore della Academic Programs, Institute for

Multimedia Literacy, School of Cinematic Arts, USC

Prefazione

Abbiamo creato Processing per rendere più facile la programmazione di grafica interattiva.Eravamo frustrati da quanto fosse difficoltoso lo scrivere questo tipo di software con i linguaggi di programmazione che usavamo di solito ( C++ e Java ) e ci siamo ispirati alla semplicità che era propria dei linguaggi della nostra infanzia ( Logo e BASIC ) . La nostra principale fonte di ispirazione è Design By Numbers (DBN), un linguaggio creato dal nostro consulente di ricerca, John Maeda, che al momento stiamo sostenendo ed insegnando.

Processing nacque nella primavera del 2001, come una sessione di brainstorming su un foglio di carta. Il nostro obiettivo era trovare un modo di fare sketch o prototipi sulla tipologia di software a cui stavamo lavorando, il quale era quasi sempre a pieno schermo ed interattivo.Eravamo in cerca di un modo migliore per collaudare facilmente le nostre idee con il codice, piuttosto che parlarne solamente o spenderci troppo tempo programmandolo in C++ .Un altro nostro obiettivo era quello di creare un linguaggio per insegnare a studenti di arte e design come programmare e per dare agli studenti più tecnici un modo semplice per lavorare con la grafica.Questa combinazione è un punto di partenza positivo dal modo di programmare insegnato di solito.Noi iniziamo con il focalizzarci sulla grafica e l'interazione piuttosto che sulle strutture dati e l'output di testo della console.

Processing ha vissuto una lunga infanzia; Era un software in fase alpha dall'agosto 2002 fino all'aprile 2005, e poi in beta pubblico fino al novembre del 2008.Durante questo lasso di tempo, fu usato continuamente nelle classi di studenti e da migliaia di persone in tutto il mondo.Il linguaggio,l'ambiente software, e la pedagogia intorno al progetto furono revisionati in continuazione in questi anni. Molte delle nostre decisioni originali sul linguaggio furono rinforzate e molte cambiate. Sviluppammo un sistema di estensione del software chiamato librerie , che ha permesso alle persone di espandere Processing in direzioni impreviste e sorprendenti.(Ci sono ora più di 100 librerie.)Il 29 novembre 2008 lanciammo la versione 1.0 del software.Dopo sette anni di lavoro, il lancio della 1.0 significa stabilità per il linguaggio.

Ora, nove anni dopo le sue origini, Processing è cresciuto al di là dei suoi obiettivi iniziali, e noi abbiamo imparato come può essere utile in altri contesti.Di conseguenza questo libro è scritto per un nuovo pubblico – programmatori occasionali, hobbisti, e chiunque voglia esplorare cosa Processing può fare senza sentirsi perduto nei dettagli di un enorme manuale. Questo libro è solo il punto d'inizio.

Mentre noi (Casey e Ben) siamo stati la guida della nave di Processing attraverso le acque negli ultimi nove anni, non si può non riconoscere che Processing è la fatica di una comunità.Dallo scrivere librerie che estendono il software al pubblicare online codice e aiutare altri nell'apprendimento, la comunità di persone che utilizzano Processing lo ha spinto molto lontano dal suo concetto iniziale. Senza questo sforzo di gruppo, Processing non potrebbe essere ciò che è oggi.

COME QUESTO LIBRO È ORGANIZZATO

I capitoli in questo libro sono organizzati come segue:

>>Capitolo 1, “Hello” . Conosci Processing>>Capitolo 2, “Iniziare a scrivere codice” . Crea il tuo primo programma di Processing>>Capitolo 3, “Disegnare” Definisci e disegna semplici forme>>Capitolo 4 , “Variabili” Immagazzina,modifica e riutilizza i dati>>Capitolo 5, “Risposta” Controlla ed influenza i programmi con il mouse e la tastiera>>Capitolo 6, “Media” Carica e visualizza media, incluse immagini, font e file vettoriali.>>Capitolo 7, “Movimento” Muovi e crea coreografie con le forme>>Capitolo 8, “Funzioni” Costruisci nuovi moduli di codice>>Capitolo 9, “Oggetti” Crea moduli di codice che combinano variabili e funzioni.>>Capitolo 10, “Arrays” Semplifica il lavoro con liste di variabili.>>Capitolo 11, “Estendere” Apprendi le funzionalità 3D, l'esportazione di immagini, e la lettura di

dati con la scheda Arduino.

Per chi è questo libro

Questo libro è scritto per le persone che desiderano un'introduzione semplice e concisa alla programmazione, per chi vuole creare immagini e semplici programmi interattivi.É per coloro che vogliono una spinta per comprendere le migliaia di esempi gratuiti di codice di Processing e il materiale dei riferimenti disponibile online. Getting Started with Processing non è un manuale di programmazione;Come il titolo suggerisce ti permetterà di avere un punto di partenza.È per adolescenti,hobbisti, nonni, e chiunque altro sia tra di loro.

Convenzioni usate in questo libro

In questo libro sono usate le seguenti convenzioni tipografiche:

>> Corsivo: usato per indicare nuovi termini e nomi di file, così come all'interno di paragrafi è usato per riferirsi ad elementi del programma così come ai nomi di funzioni e variabili, tipologie di dati, e parole chiave.>> constant width (carattere monospaziato): usato per elenchi di programma.

NOTA: questo tipo di paragrafo indica una nota generica

Usare gli Esempi di Codice

Questo libro è qui per aiutarti a fare il tuo lavoro. In generale, puoi usare il codice in questo libro nei tuoi programmi e nella tua documentazione. Non hai bisogno di contattarci per il permesso a meno che non stai riproducendo una quantità significativa di codice.Ad esempio, scrivere un programma che usa molte parti di codice da questo libro non richiede un permesso. Vendere o distribuire un CD-ROM di esempi dai libri O'Reilly richiede un permesso.Rispondere ad una domanda citando questo libro e e gli esempi di codice non richiede un permesso.Incorporare un ammontare significativo di codice esemplificativo da questo libro nella documentazione del tuo prodotto richiede un permesso.

Apprezziamo, ma non richiediamo, un'attribuzione. Un'attribuzione solitamente include il titolo,

l'autore, l'editore e l'ISBN. Ad esempio “Getting Started with Processing, by Casey Reas and Ben Fry. Copyright 2010 Casey Reas and Ben Fry, 978-1-449-37980-3”

Se senti che il tuo utilizzo del codice esemplificativo va oltre l'uso corretto o il permesso dato in questo libro, sentiti libero di contattarci a [email protected] .

Come contattarci

Prego indirizzare commenti e domande riguardanti questo libro all'editore:

O'Reilly Media , Inc.1005 Gravenstein Highway NorthSebastopol, CA 95472800-998-9938 ( in the United States or Canada)707829-0515 ( international or local )707-829-0104 ( fax)

Abbiamo una pagina web per questo libro, dove elenchiamo errata corrige, esempi, e ogni informazione addizionale. Puoi accedere a questa pagina a:

>> http://oreilly.com/catalog/0636920000570

Per commentare o chiedere su questioni tecniche riguardo questo libro, mandare una email a:

>> [email protected]

Per ulteriori informazioni riguardanti il nostro libro, le conferenze, i Resource Centers, e la rete O'Reilly, visita il nostro sito web a:

>> http://oreilly.com

Riconoscimenti

Ringraziamo Brian Jepson per la sua grande energia, sostegno ed intuito.Nancy Kotary, Rachel monaghan, e Sumita Mukherji che con pazienza hanno portato il libro alla linea di arrivo.

Tom Sgouros per avere fatto un'accurata edizione del libro e David Humphrey per aver fornito una recensione tecnica.

Non possiamo immaginare questo libro senza Getting Started with Arduino ( O'Reilly) di Massimo Banzi. L'eccellente libro di Massimo è stato il nostro prototipo.

Un piccolo gruppo di individui ha, per anni, contribuito a portare tempo essenziale ed energia a Processing. Ringraziamo Florian Jenett per il suo web hacking e le eccellenti abilità di designer,Andreas Schlegel per aver creato le infrastrutture per la costruzione e la documentazione delle librerie, e Dan Shiffman per aver scritto straordinari esempi e gestito i tutorial on-line.

Nel corso del tempo, molti altri hanno contribuito allo stesso software di Processing, tra loro Karsten Schmidt, Eric Jordan, and Jonathan Feinberg.Il lavoro di PhiLho, Cedric e antiplastik,amministratori del forum Discourse, è stato cruciale per tenere aperto il dibattito.

Siamo stupiti dall'incredibile lavoro degli individui che scrivono librerie e condividono il loro lavoro con la comunità. Grazie a tutti! Una annotazione speciale è riservata per le librerie GLGraphics e GSVideo di Andres Colubri, la libreria del suono Minim di Damien Di Fede e per gli estesi ed ispiratori toxiclibs.

La release 1.0 di Processing è stata supportata dall'università di Miami e dalle Oblong Industries.L'Armstrong Institute for Interactive Media Studies all'università di Miami ha fondato l'Oxford Project, una serie di workshop per lo sviluppo di Processing.Questi workshop sono stati resi possibili grazie al duro lavoro di Ira Greenberg. Questi incontri di quattro giorni ad Oxford, in Ohio e Pittsburgh,Pennsylvania, hanno abilitato il lancio di Processing 1.0 nel Novembre 2008 .Le Oblong Industries hanno finanziato Ben Fry per sviluppare Processing nell'estate del 2008.Ciò fu essenziale per la release.

Questo libro nasce dalle lezioni di Processing alla UCLA. Chandler McWilliams è stato determinante nella definizione di queste classi. Casey ringrazia gli studenti universitari del dipartimento di Design Media Arts alla UCLA per la loro energia ed entusiasmo. I suoi assistenti sono stati grandi collaboratori nel definire come Processing andava insegnato.Complimenti a Tatsuya Saito, John Houck, Tyler Adams, Aaron Siegel, Casey Alt, Andres Colubri, Michael Kontopoulos, David Elliott, Christo Allegra, Pete Hawkes, e Lauren McCarthy.

Open Processing è nato come luogo dove condividere il codice open-source di Processing.Ringraziamo Sinan Ascioglu per questa incredibile risorsa comunitaria.

Processing.js è un eccitante futuro per Processing ed il Web.Ulteriori ringraziamenti sono per John Resig, Al MacDonald, David Humphrey, e il Seneca College's Centre for Development of Open Technology ( CDOT ), Robert O'Rourke , e la Mozilla Foundation.

Attraverso la fondazione della Æsthetics and Computation Group (1996-2002) e il MIT Media Lab ,John Maeda ha reso tutto questo possibile.

1/Hello

Processing è stato creato per scrivere software per la creazione di immagini,animazioni ed interazioni. L'idea è di scrivere una singola riga di codice, e di far apparire un cerchio sullo schermo. Aggiungere ancora poche linee di codice , ed il cerchio segue il mouse.Un'altra riga di codice, ed il cerchio cambia colore quando il mouse viene premuto.Noi chiamiamo questo sketching (abbozzare) con il codice.Scrivi una riga, poi ne aggiungi un'altra, e poi un'altra ancora,un'altra e così via.Il risultato è che il programma viene creato un pezzo alla volta.I corsi di programmazione di solito si focalizzano prima sulla struttura e sulla teoria.Ogni cosa che sia visiva -un'interfaccia,un'animazione- è considerata un dessert da gustare solo dopo aver finito le verdure, di solito dopo diverse settimane di studio di algoritmi e metodi.Attraverso gli anni abbiamo osservato molti amici provare a seguire corsi e ritirarsi dopo la prima lezione o dopo una lunga, frustrante notte dopo la prima scadenza di compiti.La curiosità iniziale che hanno avuto riguardo al lavoro al computer andava perduta perché non hanno saputo trovare una connessione tra quello che imparavano inizialmente e ciò che volevano creare.

Processing offre una via per apprendere la programmazione attraverso la creazione di grafiche interattive. Esistono diversi modi di insegnare il codice, ma gli studenti spesso trovano incoraggiamento e motivazione immediata in un responso visivo.La capacità di Processing di fornire questo feedback ne ha fatto un modo popolare di approcciare alla programmazione, e la sua enfasi nelle immagini , nello sketching e nella comunità verrà presentata tra poche pagine.

Schizzare e creare Prototipi

Schizzare è un modo di pensare ; è giocoso e rapido.L'obiettivo di base è l'esplorazione di diverse idee in uno stretto spazio di tempo.Nel nostro lavoro personale, di solito partiamo a schizzare su carta e poi trasferiamo il risultato nel

codice. Le idee per animazioni e interazioni sono di solito abbozzate come degli storyboard con annotazioni. Dopo aver fatto diversi bozzetti del software, le idee migliori sono selezionate e combinate in prototipi (Figura 1-1). E' un processo ciclico di creazione, analisi e miglioramento che si muove avanti e indietro tra la carta e lo schermo.

Flessibilità

Come una cintura degli attrezzi del software, Processing è composto di molteplici strumenti che lavorano assieme in combinazioni differenti. Come risultato, può essere usato per rapidi “hacks” o per ricerche approfondite. Poiché un programma di Processing può avere sia la lunghezza di una riga che di diverse migliaia, c'è spazio per crescita e variazione . Più di 100 librerie estendono ulteriormente Processing in domini come suono, computer vision e digital fabrication (Figura 1-2).

Giganti

L'umanità ha creato immagini con i computer dal 1960, e c'è molto da imparare da questo percorso (Figura 1-3). Nella vita, noi tutti siamo sulle spalle di giganti, e i titani per Processing includono pensatori cha vanno dal design, alla computer grafica, all'arte, all'architettura, alla statistica, e a tutto il resto. Dai un'occhiata allo Sketchpad (1963) di Ivan Sutherland, al Dynabook (1968) di Alan Kay, ed ai molti artisti caratterizzati in Artist and Computer di Ruth Leavitt (Harmony Books,1976).Gli archivi della ACM SIGGRAPH offrono uno sguardo affascinante della storia della grafica e del software.

Albero di Famiglia

Come i linguaggi umani, i linguaggi di programmazione appartengono a famiglie correlate. Processing è un dialetto di un linguaggio di programmazione chiamato Java;La sintassi del linguaggio è pressoché identica , ma Processing aggiunge funzioni personalizzate correlate alla grafica e all'interazione (Figure 1-4).Gli elementi grafici di Processing sono relazionati a PostScript (una fondazione di PDF) e OpenGL (una specificazione della grafica 3D). A causa di queste funzioni condivise, imparare ad usare Processing è un primo passo per programmare in altri linguaggi e usare strumenti software differenti.

Partecipa

Migliaia di persone usano Processing ogni giorno. Come loro, puoi scaricare Processing senza alcun costo. Hai anche l'opzione di modificare il codice di Processing per soddisfare le tue necessità.Processing è un progetto FLOSS (cioè, free/libre/open source software), e nello spirito della comunità, ti incoraggiamo a partecipare attraverso la condivisione di progetti e conoscenza online aProcessing.org e ai principali siti di social network che ospitano i contenuti di Processing ( Figura 1-5). Questi siti hanno un link al sito web Processing.org.

2/Iniziare a scrivere codice

Per ottenere il massimo da questo libro, hai bisogno qualcosa in più che leggere solamente le parole. Hai bisogno di fare esperimenti e di fare pratica . Non puoi imparare a scrivere codice solo leggendo su di esso – hai bisogno di crearlo.Per iniziare, scarica Processing e crea il tuo primo sketch.

Comincia con il visitare http://processing.org/download e selezionare la versione per Mac, Windows o Linux, a seconda della macchina che possiedi. L'installazione su qualsiasi macchina è semplice:

>> Su Windows hai un file .zip. Fai doppio click su di esso e trascina la cartella in una posizione all'interno del tuo hard disk. Potrebbe essere la cartella Programmi o semplicemente il desktop, ma la cosa importante è che la cartella processing dev'essere estratta dal file .zip. A questo punto fai doppio click su processing.exe per iniziare.

>> La versione per Mac OS X è un file disk image (.dmg). Trascina l'icona di Processing nella cartella Applications. Se stai usando la macchina di qualcun altro e non puoi modificare la cartella Applications, basta trascinare l'applicazione sul desktop. A questo punto fai doppio click sull'icona di Processing per iniziare .

>> La versione per Linux è un file .tar.gz , il quale dovrebbe essere familiare alla maggior parte degli utenti Linux. Scarica il file nella tua home directory ,quindi apri una terminal window , e digita:

tar xvfz processing-xxxx.tgz

(Sostituisci xxxx con il nome rimanente del file, il quale è il numero della versione.) Questo creerà una cartella chiamata processing-1.0 o qualcosa di simile . Poi passa a questa directory:

cd processing-xxxx

ed eseguilo:

./processing

Con ogni probabilità,la finestra principale di Processing sarà ora visibile ( Figura 2-1).Il setup di ognuno è differente, quindi se il programma non riesce a partire, oppure sei bloccato per qualche altro motivo, visita la pagina di risoluzione problemi per possibili soluzioni:http://wiki.processing.org/index.php/troubleshooting .

Il tuo Primo Programma

Adesso stai eseguendo il Processing Development Environment ( o PDE).Non c'è granché su di esso; l'area più grande è l'editor di testo , e nella parte superiore si trova una fila di pulsanti; questa è la barra degli strumenti (toolbar). Sotto l'editor si trova l'area dei messaggi e sotto ancora la Console. L'Area Messaggi è utilizzata per messaggi ad una riga , e la Console per dettagli più tecnici.

Esempio 2-1: Disegna un' ellisse

Nell'editor, digita quanto segue:

ellipse ( 50,50,80,80 );

Questa linea di codice significa “ disegna un'ellisse, con centro 50 pixel a partire da sinistra e 50 pixel a partire dall'alto, con una larghezza ed un'altezza di 80 pixel.”Clicca sul pulsante Esegui (Run) , che appare così:

Se hai digitato ogni cosa correttamente, vedrai l'immagine dell'ellisse qui sopra.Se non hai digitato correttamente, l'area messaggi diventerà rossa e reclamerà un errore.Se ciò accade, assicurati di aver copiato il codice di esempio correttamente: i numeri dovrebbero esser contenuti tra le parentesi e tra di loro dovrebbero avere le virgole, e la riga dovrebbe finire con un punto e virgola.

Una delle cose più difficili di iniziare a programmare è il bisogno di essere molto specifici con la sintassi. Il software di Processing spesso non è abbastanza furbo da capire cosa vuoi dire, e potrebbe essere leggermente puntiglioso riguardo il posizionamento della punteggiatura.Acquisterai maneggevolezza con un pò di pratica.

Di seguito passeremo ad uno sketch leggermente più stimolante.

Esempio 2-2: Creare Cerchi

Cancella il testo dell'ultimo esempio, e prova questo:

void setup(){size(480,120);smooth();

}

void draw(){if (mousePressed){

fill(0);} else {fill(255);

}ellipse(mouseX,mouseY,80,80);}

Questo programma crea una finestra larga 480 pixel e alta 120 pixel, poi comincia a disegnare cerchi bianchi alla posizione del mouse. Quando il pulsante del mouse è premuto, il colore del cerchio cambia e diventa nero. Approfondiremo in seguito nel dettaglio riguardo gli elementi di questo programma.Per adesso ,esegui il codice, muovi il mouse, e clicca per provarlo.

Visualizzare

Finora abbiamo trattato solo il pulsante Esegui, anche se probabilmente hai già indovinato a cosa serve il pulsante Stop situato a fianco.

Se non vuoi usarlo, puoi sempre utilizzare il menu sketch, il quale rivela la scorciatoia Ctrl-R (o Cmd-R per il Mac) per Esegui. Al di sotto di Esegui nel menu sketch si trova Present, che libera il resto dello schermo per mostrare solamente il tuo sketch:

Puoi anche usare Present dalla Toolbar tenendo premuto il tasto Shift mentre premi il pulsante Run.

Salvare

Il prossimo comando fondamentale è Salva. È la freccia che da verso il basso sulla barra degli strumenti:

Puoi anche trovarla sotto il menu File. Come impostazione predefinita, i tuoi programmi sono salvati nello “sketchbook”, che è la cartella che li raccoglie per un facile accesso.Cliccando il pulsante Open sulla toolbar ( la freccia che punta in alto) apparirà una lista di tutti gli sketch nel tuo sketchbook, oltre ad una lista di esempi che sono installati nel software di Processing:

È sempre una buona idea salvare spesso i tuoi sketch. Quando provi soluzioni diverse, tienile salvate con nomi differenti , così che puoi sempre tornare indietro ad una versione precedente.Ciò è particolarmente utile se qualcosa non va. Puoi anche vedere dove lo sketch è collocato sul disco, con Show Sketch Folder nel menu.

Puoi anche creare un nuovo sketch premendo il pulsante New sulla barra degli strumenti:

Questo prenderà il posto dello sketch nella finestra corrente con uno vuoto.Tenendo premuto Shift mentre si preme il pulsante New verrà creato un nuovo sketch nella sua propria finestra , così come selezionando File → New. Il pulsante Open funziona allo stesso modo.

Condividi

Un altro punto importante di Processing è la condivisione del tuo lavoro. Il pulsante Export sulla

toolbar:

raccoglierà il tuo codice in un'unica cartella intitolata applet che può essere caricata su un server web (Figura 2-2). Dopo l'esportazione ,la cartella applet si aprirà sul tuo desktop.Il file PDE è il file sorgente, il file JAR è il programma, il file HTML è la pagina web, e il file GIF è visualizzato sul browser web mentre il programma è in caricamento. Fare doppio click sul file index.html lancerà il browser e mostrerà il tuo sketch nella pagina web che ha creato.

NOTA : la cartella applet viene cancellata e ricreata ogni volta che userai il comando Esporta, quindi assicurati di spostare la tua cartella da qualche altra parte prima di fare un qualsiasi cambiamento al file HTML o qualsiasi altra cosa al suo interno.

Puoi anche trovare Export ,insieme a suo fratello Export to Application, sotto al menu File.Export to Application crea un'applicazione a tua scelta per Mac, Windows, e/o Linux.Questo è un modo semplice di fare versioni autonome e doppio-cliccabili dei tuoi progetti (Figure 2-3).

Tenere premuto Shift mentre premi il pulsante Export sulla toolbar è un altro modo di usare Export to Application.

Esempi e Riferimenti

Imparare come programmare con Processing comporta l'esplorazione di una gran quantità di codice:eseguire,modificare, manomettere e migliorare il codice fino a quando non si è trasformato in qualcosa di nuovo. Tenendo questo a mente, il download del software di Processing include dozzine di esempi che dimostrano le differenti caratteristiche del software.Per aprire un esempio, seleziona Examples dal menu File o clicca l'icona Open nel file PDE.Gli esempi sono raggruppati in categorie basate sulle loro funzioni, come Form, Motion, and Image.Trova un argomento interessante nella lista e prova un esempio.

Se vedi una parte del programma con cui non hai familiarità che è colorata di arancione (questo significa che è una parte di Processing) , seleziona il suo nome , e clicca su “Find in Reference” dal menu Help. Puoi anche cliccare con il tasto destro sul testo (o Ctrl-click per il Mac) e scegliere Find in Reference dal menu che è apparso.Questo aprirà i riferimenti riguardanti l'elemento del codice selezionato nel tuo browser. I riferimenti sono disponibili inoltre online all'indirizzo http://www.processing.org/reference/.

Le Reference di Processing spiegano ogni elemento del codice con una descrizione ed esempi.I programmi di riferimento sono molto più brevi (solitamente quattro o cinque righe) e più semplici dei lunghi codici trovati nella cartella Examples. Raccomandiamo di tenere aperte le Reference mentre stai leggendo questo libro e mentre stai programmando. Possono essere navigate per argomento o in ordine alfabetico; solitamente la cosa più veloce da fare è una text search nella finestra del browser.

Le Reference sono state scritte con in mente il principiante; Speriamo che siano chiari e comprensibili. Siamo grati alle molte persone che hanno individuato gli errori durante gli anni e che li hanno riportati. Se pensi di poter migliorare la voce di una Reference o hai trovato un errore , prego permettici di conoscerlo cliccando sul link in cima ad ogni pagina delle Reference.

3/Disegnare

Prima di tutto, disegnare sullo schermo di un computer è come lavorare su carta millimetrata.Si inizia con un'accurata procedura tecnica, ma come vengono introdotti nuovi concetti, il disegnare semplici forme con il software si espande nell'animazione e nell'interazione.Prima di fare questo salto, abbiamo bisogno di partire dall'inizio.Lo schermo di un computer è una griglia di elementi luminosi chiamati pixel. Ogni pixel ha una posizione all'interno della griglia definita dalle proprie coordinate. In Processing, la coordinata X è la distanza dal bordo sinistro della finestra di visualizzazione e la coordinata Y è la distanza dal bordo superiore. Scriviamo le coordinate di un pixel in questo modo : (x,y).Quindi,se lo schermo è di 200x200 pixel, quello in alto a sinistra è (0,0), il centro si trova a (100,100), ed in basso a destra è (199,199). Questi numeri potrebbero sembrare confusi; perchè andiamo da 0 a 199 invece di andare da 1 a 200? La risposta è che nel codice, di solito iniziamo il conteggio da 0 poiché è più facile per i calcoli che ci troveremo ad affrontare più tardi.

La finestra di visualizzazione (Display Windows) e le immagini all'interno di essa sono create attraverso elementi di codice chiamati funzioni. Le funzioni sono i blocchi di costruzione base di un programma di Processing. Il comportamento di una funzione è definita dai suoi parametri. Ad esempio, quasi ogni programma di Processing ha una funzione size( ) per fissare l'altezza e la larghezza della finestra di visualizzazione. (se il tuo programma non ha una funzione size( ), la dimensione è stabilita a 100x100 pixel.)

Esempio 3-1: Disegnare una finestra

La funzione size( ) ha due parametri : il primo stabilisce la larghezza della finestra e il secondo stabilisce l'altezza. Per disegnare una finestra che sia larga 800 pixel e alta 600 , scrivi:

size (800, 600);

Esegui questa linea di codice per vedere il risultato. Inserisci valori differenti per vedere le possibilità. Prova numeri molto piccoli e numeri grandi quanto il tuo schermo.

Esempio 3-2: Disegnare un Punto

Per definire il colore di un singolo pixel nella finestra di visualizzazione, usiamo la funzione point( ). Ha due parametri che definiscono la posizione : la coordinata X seguita dalla coordinata Y.Per disegnare una piccola finestra ed un punto al centro dello schermo, con le coordinate (240,60),digita:

size(480,120);point(240,60);

Prova a scrivere un programma che inserisca un punto ad ogni angolo della finestra di visualizzazione ed una al centro. Prova ad inserire i punti fianco a fianco per creare linee orizzontali, verticali e diagonali.

Forme Base

Processing include un gruppo di funzioni per disegnare forme base ( vedi la Figura 3-1). Le forme semplici come le linee possono essere combinate per creare forme più complesse come una foglia o un viso.

Per disegnare una singola linea, abbiamo bisogno di quattro parametri : due per la posizione di partenza e due per il punto finale.

Esempio 3-3: Disegnare una Linea

Per disegnare una linea tra le coordinate (20,50) e (420,110), prova :

size (480, 120);line (20, 50, 420, 110);

Esempio 3-4: Disegnare Forme Base

Seguendo questo modello, un triangolo richiede sei parametri e un quadrilatero ne richiede otto (un paio per ogni punto):

size (480, 120)quad ( 158, 55, 199, 14, 392, 66, 351, 107 );triangle ( 347, 54, 392, 9, 392, 66 );triangle ( 158, 55, 290, 91, 290, 112 );

Esempio 3-5: Disegnare un Rettangolo

Rettangoli ed ellissi sono entrambi definiti con quattro parametri: il primo e il secondo sono per le coordinate X e Y dei punti di ancoraggi, il terzo per l'altezza e il quarto per la larghezza .

Per creare un rettangolo alle coordinate ( 180, 60) con una largezza di 220 pixel e un' altezza di 40, usa la funzione rect( ) in questo modo:

size (480, 120);rect (180, 60, 220, 40);

Esempio 3-6: Disegnare una Ellisse

Le coordinate X e Y per un rettangolo sono l'angolo in alto a sinistra , ma per una ellissi sono il centro della forma . In questo esempio, nota che la coordinata Y per la prima ellisse è situata fuori dalla finestra. Gli oggetti possono essere disegnati parzialmente ( o interamente ) fuori dalla finestra senza causare un errore:

size ( 480, 120 );ellipse ( 278, -100, 400, 400);ellipse ( 120, 100, 110, 110);ellipse ( 412, 60, 18, 18);

Processing non ha funzioni separate per creare quadrati e cerchi. Per fare queste forme, usa gli stessi valori dei parametri di altezza e larghezza per ellipse( ) e rect( ) .

Esempio 3-7: Disegnare una Parte di una Ellisse

La funzione arc( ) disegna una parte di una ellisse:

size( 480, 120);arc (90,60,80,80,0,HALF_PI);arc (190,60,80,80,0,PI+HALF_PI);arc (290,60,80,80,PI,TWO_PI+HALF_PI);arc (390,60,80,80,QUARTER_PI,PI+QUARTER_PI);

Il primo e il secondo parametro indicano la posizione, il terzo e il quarto indicano l'altezza e la larghezza. Il quinto parametro indica l'angolo da dove far partire l'arco, e il sesto indica l'angolo dove fermarlo. Gli angoli sono indicati in radianti invece che in gradi. I radianti sono misurazioni di angoli basati sul valore del PI ( 3.14159 ).La figura 3-2 mostra come i due sono in relazione. Come si vede da questo esempio i quattro valori dei radianti sono usati così frequentemente da prendere dei nomi speciali come parte integrante di Processing. I valori PI, QUARTER_PI, HALF_PI, e TWO_PI possono essere usati per riprendere i valori in radianti di 180° , 45°, 90°, e 360° .

Esempio 3-8: Disegnare in Gradi

Se tu preferisci usare delle misurazioni in gradi, puoi convertirli in radianti con la funzione radians( ) .Questa funzione prende un angolo in gradi e lo trasforma nel corrispondente valore in radianti.L'esempio seguente è lo stesso dell'esempio 3-7, ma questo usa la funzione radians( ) per definire il valore di inizio e di fine in gradi:

size ( 480,120 );

arc ( 90, 60, 80, 80, 0, radians(90));arc ( 190, 60, 80, 80, 0, radians(270));arc ( 290, 60, 80, 80, radians(180),radians(450));arc ( 390, 60, 80, 80, radians(45), radians(225));

Disegnare in Ordine

Quando un programma viene eseguito, il computer comincia dalla cima e legge ogni riga del codice fino a raggiungere l'ultima linea e poi si ferma.Se vuoi una forma che sia disegnata in cima alle altre forme, dev'essere scritta di seguito alle altre nel codice.

Esempio 3-9: Controllare l'Ordine di Disegno

size (480, 120);ellipse(140, 0, 190, 190);//il rettangolo viene disegnato sopra l'ellisse//perchè viene dopo nel codicerect (160, 30, 260, 20);

Esempio 3-10: Metterlo al Contrario

Modifica l'esempio 3-9 invertendo l'ordine di rect( ) ed ellipse( ) per vedere il cerchio sopra il rettangolo:

size(480,120);rect(160, 30, 260, 20 );//L'ellisse viene disegnata sopra il rettangolo// poiché viene scritta successivamente nel codiceellipse(140, 0, 190, 190);

Puoi pensarlo come dipingere con un pennello o come fare un collage. L'ultimo elemento che aggiungi è quello che si vede in cima.

Proprietà delle Forme

Le proprietà delle forme più fondamentali e utili sono lo spessore del contorno e l'anti-aliasing, chiamato anche smoothing.

Esempio 3-11: Disegnare Linee Smussate.

La funzione smooth( ) smussa i bordi delle linee disegnate sullo schermo fondendo i margini con i valori dei pixel nelle vicinanze. Al contrario, se lo smoothing è già attivato, la funzione noSmooth( )lo renderà inattivo:

size(480,120);

smooth( ); // attiva lo smoothingellipse ( 140, 60, 90, 90 );noSmooth ( ); // disattiva lo smoothingellipse ( 240, 60, 90, 90);

NOTA: Qualche implementazione di Processing (come la versione per JavaScript) smusserà sempre le forme; altre potrebbero non supportare del tutto questa funzione. In alcune situazioni, non è possibile abilitare e disabilitare lo smoothing nello stesso passaggio mediante draw( ). Vedi le referenze riguardanti lo smooth( ) per maggiori dettagli.

Esempio 3-12: Impostare lo Spessore del Contorno

La larghezza standard per il contorno è di un singolo pixel, ma può essere cambiata con la funzione strokeWeight( ). L'unico parametro per strokeWeight( ) regola la larghezza delle linee disegnate:

size(480, 120);smooth();ellipse(75, 60, 90, 90);strokeWeight(8); // Spessore del contorno a 8 pixelellipse(175, 60, 90, 90);ellipse(279, 60, 90, 90);strokeWeight(20); // Spessore del contorno a 20 pixelellipse(389, 60, 90, 90);

Esempio 3-13: Stabilire gli Attributi del Contorno

La funzione strokeJoin( ) cambia il modo con cui le linee sono unite (cioè come appaiono gli angoli), e la funzione strokeCap( ) modifica il modo in cui le linee vengono disegnate al loro punto di partenza e alla loro fine .

size(480, 120);smooth();strokeWeight(12);strokeJoin(ROUND); // Arrotonda lo spessore degli angolirect(40, 25, 70, 70);strokeJoin(BEVEL); // Smussa lo spessore degli angolirect(140, 25, 70, 70);strokeCap(SQUARE); // Squadra le terminazioni delle lineeline(270, 25, 340, 95);strokeCap(ROUND); // Arrotonda le terminazioni delle lineeline(350, 25, 420, 95);

La collocazione di forme come rect( ) ed ellipse( ) è controllato con le funzioni rectMode( ) e ellipseMode( ). Controlla le Reference (Help → Reference) per vedere gli esempi e come posizionare i rettangoli in riferimento al loro centro (invece che partendo dall'angolo in alto a sinistra), o come disegnare le ellissi dall'angolo in alto a sinistra come i rettangoli.

Quando ognuno di questi attributi è stabilito, tutte le forme disegnate di seguito vengono condizionate. Come dimostrazione, nota come nell' Esempio 3-12 il secondo ed il terzo cerchio

abbiano entrambi lo stesso spessore del contorno, sebbene la larghezza è impostata solo una volta prima che entrambi siano disegnati.

Colore

Tutte le forme fino a questo momento sono state riempite di bianco con i lineamenti neri, e lo sfondo della finestra di visualizzazione era regolata su un grigio chiaro. Per cambiarli, usa le funzioni background( ), fill( ) e stroke( ). I valori dei parametri sono in una gamma che va da 0 a 255, dove 255 è bianco , 128 è grigio medio, e 0 è nero. La figura 3-3 ti mostra come i valori da 0 a 255 scalano a differenti livelli di grigio.

Esempio 3-14: Dipingere con i Grigi

Questo esempio mostra tre differenti valori di grigio su uno sfondo grigio:

size(480, 120);smooth();background(0); // Nerofill(204); // Grigio chiaroellipse(132, 82, 200, 200); // Cerchio grigio chiarofill(153); // Grigio medioellipse(228, -16, 200, 200); // Cerchio grigio mediofill(102); // Grigio scuroellipse(268, 118, 200, 200); // Cerchio grigio scuro

Esempio 3-15: Controlla il Riempimento ed il Contorno

Puoi disabilitare il contorno così che non ci siano linee esterne con noStroke( ) e puoi disabilitare il riempimento della forma con noFill( ) :

size(480, 120);smooth();fill(153); // Grigio medioellipse(132, 82, 200, 200); // Cerchio grigionoFill(); // Disattiva il riempimentoellipse(228, -16, 200, 200); // Profilo del cerchionoStroke(); // Disattiva il contornoellipse(268, 118, 200, 200); // Non disegna nulla!

Stai attento a non disabilitare allo stesso tempo contorno e riempimento, come abbiamo fatto nell'esempio precedente, altrimenti non verrà disegnato nulla sullo schermo.

Esempio 3-16: Disegnare con i Colori

Per muoverti tra i valori della scala di grigi, usa tre parametri per specificare le componenti di rosso, verde e blu di un colore . Poiché questo libro è stampato in nero e bianco, vedrai qui solo valori di grigio. Esegui il codice con Processing per rivelare i colori:

size(480, 120);noStroke();smooth();

background(0, 26, 51); // Colore blu scurofill(255, 0, 0); // Colore rossoellipse(132, 82, 200, 200); // Cerchio rossofill(0, 255, 0); // Colore Verdeellipse(228, -16, 200, 200); // Cerchio verdefill(0, 0, 255); // Colore bluellipse(268, 118, 200, 200); // Cerchio blu

Questo è denominato colore RGB, il quale deriva dal modo in cui i computer definiscono i colori sullo schermo. I tre numeri riportano i valori di rosso, verde e blu e la loro gamma da 0 a 255, nello stesso modo dei valori di grigio. Usare i colori RGB non è così intuitivo, quindi per scegliere i colori , usa Tools → Color Selector, che mostra una tavolozza di colori simile a quella trovata in altri software ( vedi la Figura 3-4 ) . Seleziona un colore, ed usa i valori R, G e B come parametri per le tue funzioni di background( ), fill( ), o stroke( ).

Esempio 3-17: Impostare la Trasparenza

Con l'aggiunta di un quarto parametro opzionale a fill( ) o stroke( ) , Puoi controllare la trasparenza.Questo quarto parametro è conosciuto come il valore alpha , ed è anch'esso usato in un intervallo che va da 0 a 255 per impostare il grado di trasparenza. Il valore 0 definisce il colore come completamente trasparente ( non viene visualizzato) , il valore 255 è completamente opaco, e i valori che si trovano tra questi estremi provocano la fusione dei colori sullo schermo.

size(480, 120);noStroke();smooth();background(204, 226, 225); // Colore blu chiarofill(255, 0, 0, 160); // Colore rossoellipse(132, 82, 200, 200); // Cerchio rossofill(0, 255, 0, 160); // Colore verdeellipse(228, -16, 200, 200); // Cerchio verdefill(0, 0, 255, 160); // Colore bluellipse(268, 118, 200, 200); // Cerchio blu

Forme Personalizzate

Non sei limitato ad usare queste forme geometriche di base – puoi anche definire nuove forme connettendo delle serie di punti .

Esempio 3-18: Disegnare una Freccia

La funzione beginShape( ) dichiara il punto di partenza di una nuova forma. La funzione vertex( ) è usata per definire ogni coppia di coordinate X e Y per la forma . Infine, endShape( ) è usata per segnalare la fine della forma.

size(480, 120);beginShape();vertex(180, 82);vertex(207, 36);vertex(214, 63);vertex(407, 11);vertex(412, 30);vertex(219, 82);vertex(226, 109);

endShape();

Esempio 3-19: Chiudere l'Apertura

Quando esegui l'esempio 3-18, vedrai che il primo e l'ultimo punto non sono connessi. Per farlo, aggiungiamo la parola CLOSE come un parametro in endShape( ), in questo modo:

size(480, 120);beginShape();vertex(180, 82);vertex(207, 36);vertex(214, 63);vertex(407, 11);vertex(412, 30);vertex(219, 82);vertex(226, 109);endShape(CLOSE);

Esempio 3-20: Creare alcune Creature

La capacità di definire forme con la funzione vertex( ) è l'abilità di creare forme con contorni complessi. Processing può disegnare migliaia e migliaia di linee in una volta per riempire lo schermo con forme fantastiche che fuoriescono dalla tua immaginazione . Un esempio modesto ma più complesso è quello che segue:

size(480, 120);smooth();// Left creaturebeginShape();vertex(50, 120);vertex(100, 90);vertex(110, 60);vertex(80, 20);vertex(210, 60);vertex(160, 80);vertex(200, 90);vertex(140, 100);vertex(130, 120);endShape();fill(0);ellipse(155, 60, 8, 8);// Right creaturefill(255);beginShape();vertex(370, 120);vertex(360, 90);vertex(290, 80);vertex(340, 70);vertex(280, 50);vertex(420, 10);vertex(390, 50);vertex(410, 90);vertex(460, 120);endShape();fill(0);

ellipse(345, 50, 10, 10);

Commenti

Gli esempi in questo capitolo usano un doppio slash ( // ) alla fine di una riga per aggiungere dei commenti al codice. I commenti sono parti del programma che vengono ignorati quando questo viene eseguito. Sono utili per creare note per te stesso che spiegano cosa sta succedendo all'interno del codice . Se altri stanno leggendo il tuo codice, i commenti sono particolarmente importanti per aiutarli a capire il tuo processo di pensiero.

I commenti sono particolarmente utili inoltre per un numero di opzioni differenti, come quando si prova a scegliere il colore giusto. Ad esempio, posso provare a trovare il rosso giusto per un'ellissi.

size(200, 200);fill(165, 57, 57);ellipse(100, 100, 80, 80);

Ora supponiamo di voler provare un rosso differente, ma non vogliamo perdere quello vecchio.Posso copiare e incollare la linea, fare un cambiamento, poi commentare quella vecchia.

size(200, 200);//fill(165, 57, 57);fill(144, 39, 39);ellipse(100, 100, 80, 80);

Collocare // all'inizio di una linea la disabilita temporaneamente. Oppure posso rimuovere le // e collocarle davanti ad un'altra linea se voglio provarla ancora:

size(200, 200);fill(165, 57, 57);//fill(144, 39, 39);ellipse(100, 100, 80, 80);

NOTA: Come scorciatoia, puoi anche usare Ctrl-/ (Cmd-/ per il Mac) per aggiungere o rimuovere i commenti dalla linea corrente o da un blocco di testo selezionato. Puoi anche commentare più linee in una volta con la notazione di commento alternativa introdotta nell'Appendice A.

Lavorando con gli schizzi di Processing, ti troverai a creare dozzine di ripetizioni di idee: usare i commenti per creare annotazioni o per disabilitare il codice può aiutarti a tenere traccia di opzioni differenti.

Robot 1: Disegna

Questo è P5, il robot di Processing. Ci sono 8 diversi programmi per disegnarlo e animarlo in questo libro – ognuno esplora un'idea differente di programmazione. Il design di P5 è ispirato da Sputnik 1 (1957), Shakey dallo Stanford Research Institute (1966-1972), il drone combattente in Dune di David Lynch (1984), e HAL 9000 da 2001:Odissea nello Spazio (1968), oltre ad altri robot che ammiriamo.

Il primo programma del robot usa la funzione di disegno introdotta nel capitolo precedente. I parametri delle funzioni fill( ) e stroke( ) regolano i valori di grigio. Le funzioni line( ), ellipse( ), e rect( ) definiscono le forme che creano il collo,le antenne, il corpo e la testa del robot. Per prendere maggiore confidenza con le funzioni, esegui il programma e cambia i valori per riprogettare il robot:

size(720, 480);smooth();strokeWeight(2);background(204);ellipseMode(RADIUS);// Collostroke(102); // Imposta il contorno in grigioline(266, 257, 266, 162); // Sinistraline(276, 257, 276, 162); // Centroline(286, 257, 286, 162); // Destra// Antenneline(276, 155, 246, 112); // Bassaline(276, 155, 306, 56); // Altaline(276, 155, 342, 170); // Media// CorponoStroke(); // Disabilita il contornofill(102); // Imposta il riempimento in grigioellipse(264, 377, 33, 33); // Sfera antigravitàfill(0); // Imposta il riempimento in nerorect(219, 257, 90, 120); // Corpo principalefill(102); // Imposta il riempimento in grigiorect(219, 274, 90, 6); // Banda grigia// Testafill(0); // Imposta il riempimento in neroellipse(276, 155, 45, 45); // Testafill(255); // Imposta il riempimento in biancoellipse(288, 150, 14, 14); // Occhio grandefill(0); // Imposta il riempimento in neroellipse(288, 150, 3, 3); // Pupillafill(153); // Imposta il riempimento in grigio chiaroellipse(263, 148, 5, 5); // Occhio piccolo 1ellipse(296, 130, 4, 4); // Occhio piccolo 2ellipse(305, 162, 3, 3); // Occhio piccolo 3

4/Variabili

Una variabile immagazzina un valore nella memoria così da poter essere usata più tardi nel programma. La variabile può essere usata diverse volte all'interno di un singolo programma, ed il valore viene cambiato facilmente mentre il programma è in esecuzione.

La ragione primaria per cui usiamo le variabili è per evitare di ripeterci all'interno del codice. Se stai digitando lo stesso numero più di una volta, prendi in considerazione di trasformarlo in una variabile per rendere il tuo codice più universale e facile da aggiornare.

Esempio 4-1: Riutilizzare gli Stessi Valori

Come dimostrazione, quando trasformi in variabili la coordinata X e il diametro per i tre cerchi in questo esempio, gli stessi valori sono usati per ogni ellisse:

size(480, 120);smooth();int y = 60;int d = 80;ellipse(75, y, d, d); // Sinistraellipse(175, y, d, d); // Centroellipse(275, y, d, d); // Destra

Esempio 4-2: Cambia i valori

Perciò semplicemente cambiando le variabili y e d vengono alterate tutte e tre le ellissi:

size(480, 120);smooth();int y = 100;int d = 130;ellipse(75, y, d, d); // Sinistraellipse(175, y, d, d); // Centroellipse(275, y, d, d); // Destra

Senza le variabili, avresti bisogno di cambiare la coordinata y usata nel codice tre volte, e il diametro sei volte. Quando si confrontano gli Esempi 4-1 e 4-2, notiamo come le tre righe in fondo siano le stesse, e solamente le due righe con le variabili al centro sono differenti. Le variabili ti permettono di separare righe di codice che richiedono cambiamenti da quelle che non lo richiedono,

per creare programmi più facili da modificare. Ad esempio, se poniamo delle variabili che controllano i colori e la dimensione delle forme in un unico luogo, poi potrai velocemente esplorare differenti opzioni visive concentrandoti solo su poche righe di codice.

Creare Variabili

Quando crei le tue variabili, determini il nome (name), il tipo di dati (data type), ed il valore (value). Il nome è come decidi di chiamare la variabile. Scegli un nome che sia descrittivo di ciò che è contenuto nella variabile, ma allo stesso tempo cerca di essere coerente e non troppo prolisso.Ad esempio, la variabile chiamata “radius” sarà più chiara di “r” quando in seguito leggerai il codice.

La gamma di valori che può essere immagazzinata nella variabile è definita dal suo data type. Per esempio, il tipo integer (intero) può memorizzare numeri senza decimali (numeri interi). Nel codice , integer è abbreviato con int . Ci sono data type per depositare ogni genere di dati: interi, numeri in virgola mobile (decimali), caratteri, parole, immagini, font, e così via.

Le variabili devono essere innanzitutto dichiarate, per mettere da parte uno spazio nella memoria del computer per memorizzare le informazioni. Quando si dichiara una variabile, puoi anche aver bisogno di specificare il tipo di dati (come int), il quale indica quale genere di informazione è stata memorizzata. Dopo che il tipo di dati e il nome sono stati definiti, può essere assegnato un valore alla variabile:

int x; // Dichiara x come una variabile interax = 12; // Assegna un valore alla x

Questo codice fa la stessa cosa, ma è più breve:

int x = 12; // Dichiara x come una variabile intera e assegna un valore

Il nome della tipologia di dati è incluso nella riga di codice che dichiara una variabile, ma non viene scritto un'altra volta. Ogni volta che il data type viene scritto davanti al nome di una variabile, il computer pensa che tu stia provando a dichiarare un'altra variabile. Non puoi avere due variabili con lo stesso nome nella stessa parte di programma ( vedi l'Appendice D ), perchè il programma avrà un errore:

int x; // dichiara x come una variabile intint x = 12; // ERRORE! Non puoi avere qui due variabili con lo

stesso nome

Variabili di Processing

Processing possiede una serie di variabili speciali per depositare informazioni riguardo al programma mentre esso è in esecuzione. Ad esempio, la larghezza e l'altezza della finestra sono memorizzate in variabili chiamate width ed height. Questi valori sono impostati nella funzione size( ). Possono essere usati per disegnare elementi relativi alla dimensione della finestra, anche se la riga di size( ) viene cambiata.

Esempio 4-3: Regola la Dimensione, Vedi Cosa Accade

In questo esempio, cambia i parametri della funzione size( ) per vedere come funziona:

size(480, 120);smooth();line(0, 0, width, height); // Linea da (0,0) a (480, 120)line(width, 0, 0, height); // Linea da (480, 0) a (0, 120)ellipse(width/2, height/2, 60, 60);

Altre variabili speciali tengono traccia dello status del mouse, dei valori della tastiera, ed altro ancora. Di questi si parlerà nel Capitolo 5.

Un po' di Matematica

Le persone spesso ritengono che la matematica e la programmazione sono la stessa cosa. Sebbene la conoscenza della matematica può essere utile per certe tipologie di codificazione, l'aritmetica di base ricopre le parti più importanti.

Esempio 4-4: Aritmetica di Base

size(480, 120);int x = 25;int h = 20;int y = 25;rect(x, y, 300, h); // Superiorex = x + 100;rect(x, y + h, 300, h); // Centralex = x - 250;rect(x, y + h*2, 300, h); // Inferiore

Nel codice, simboli come +, -, e * sono chiamati operatori. Quando sono posizionati tra due valori, creano un' espressione. Ad esempio, 5+9 e 1024-512 sono entrambe espressioni. Gli operatori per le operazioni base di matematica sono:

+ Addizione- Sottrazione* Moltiplicazione/ Divisione= Assegnazione

Processing ha una serie di regole per definire quale operatore ha la precedenza sugli altri, ciò significa che decide quale calcolo viene risolto per primo, secondo, terzo, e così via. Queste regole definiscono l'ordine in cui il codice viene eseguito. Una piccola cognizione riguardo questo argomento inizia una lunga strada verso la comprensione di come una piccola riga di codice come questa può funzionare:

int x = 4 + 4 * 5; // Assegna 24 ad x

L'espressione 4*5 è valutata per prima poiché la moltiplicazione ha la priorità più alta. Come seconda cosa, 4 è addizionato al prodotto di 4*5 per ottenere 24. Infine, siccome l'operatore di assegnazione ( il simbolo uguale ) ha la precedenza più bassa, il valore 24 è assegnato alla variabile x. Ciò è chiarito con le parentesi, ma il risultato è lo stesso:

int x = 4 + (4 * 5); // Assegna 24 ad x

Se vuoi costringere l'addizione ad essere verificata per primo, basta solamente muovere le parentesi.

Poiché ciò che è tra parentesi ha una precedenza più alta della moltiplicazione, l'ordine viene cambiato ed il calcolo viene influenzato:

int x = (4 + 4) * 5; // Assegna 40 ad x

Un acronimo per quest'ordine è spesso insegnato nelle classi di matematica: PEMDAS, che sta per Parentesi, Esponenti, Moltiplicazione, Divisione, Addizione, Sottrazione, dove le parentesi hanno la più alta priorità e la sottrazione la più bassa. L'ordine completo delle operazioni si trova nell'Appendice C.

Alcuni calcoli vengono usati così frequentemente nella programmazione che si sono sviluppate delle abbreviazioni; è sempre una buona cosa salvare alcune parole chiave. Ad esempio, puoi fare un'addizione ad una variabile, oppure una sottrazione, con un unico operatore:

x += 10; // è come dire x = x + 10y -= 15; // è come dire y = y – 15

E' inoltre cosa comune addizionare o sottrarre 1 da una variabile, così esiste anche un'abbreviazione per questo caso. Gli operatori ++ e - - fanno proprio questo:

x++; // è come dire x = x + 1y--; // è come dire y = y – 1

Altre abbreviazioni possono essere trovate nelle referenze.

Ripetizione

Nel momento in cui scriverai altri programmi, noterai che ricorreranno dei pattern quando le righe di codice verranno ripetute, ma con sottili variazioni. Una struttura del codice chiamata ciclo for rende possibile l'esecuzione di una riga di codice più di una volta per condensare questo tipo di ripetizione in poche righe. Questo rende i tuoi programmi modulari e più facili da modificare.

Esempio 4-5: Fare la stessa cosa più e più volte

Questo esempio possiede il tipo di pattern che può essere semplificato con un ciclo for:

size(480, 120);smooth();strokeWeight(8);line(20, 40, 80, 80);line(80, 40, 140, 80);line(140, 40, 200, 80);line(200, 40, 260, 80);line(260, 40, 320, 80);line(320, 40, 380, 80);line(380, 40, 440, 80);

Esempio 4-6; Usa un ciclo for

La stessa cosa può essere fatta con un ciclo for, e con meno codice:

size(480, 120);

smooth();strokeWeight(8);for (int i = 20; i < 400; i += 60) {line(i, 40, i + 60, 80);}

Il ciclo for differisce in molti modi dal codice che abbiamo scritto fino ad ora. Nota le parentesi graffe, i caratteri { e } . Il codice all'interno delle parentesi graffe è chiamato blocco. È questo il codice che viene ripetuto in ogni iterazione del ciclo for .All'interno delle parentesi ci sono tre dichiarazioni, separate da punti e virgola, che lavorano assieme per controllare quante volte il codice all'interno del blocco viene eseguito. Da sinistra a destra, queste dichiarazioni si riferiscono come l'inizializzazione (init) , il test, e l'aggiornamento (update) .

for (init; test; update) {dichiarazioni}

La init tipicamente dichiara una nuova variabile da usare all'interno del ciclo for e ne assegna un valore. Il nome della variabile i è usato di frequente, ma in realtà non c'è nulla di speciale riguardo questo nome. Il test sonda il valore di questa variabile, e l' update cambia il valore della variabile.La Figura 4-1 mostra l'ordine in cui vengono eseguiti e come controllino le dichiarazioni di codice all'interno del blocco.

Il test ha bisogno di ulteriori spiegazioni. É sempre un' espressione relazionale che compara due valori con un operatore relazionale. In questo esempio, l'espressione è “ i < 400” e l'operatore è il simbolo < ( minore di). Gli operatori relazionali più comuni sono:

> Maggiore di< Minore di>= Maggiore o uguale a<= Minore o uguale a== Uguale a!= Non uguale a

L'espressione relazionale valuta sempre il vero o il falso. Ad esempio, l'espressione 5>3 è vera. Possiamo porre la domanda, “è cinque maggiore di tre?” siccome la riposta è “si”, diciamo che l'espressione è vera.Per l'espressione 5<3, chiediamo, “è cinque minore di tre?”. Siccome la risposta è “no”, diciamo che l'espressione è falsa. Quando la valutazione è vera, il codice all'interno del blocco viene eseguito, e quando è falso, il codice all'interno del blocco non viene eseguito ed il ciclo for si ferma.

Esempio 4-7: Contrarre i Muscoli del Ciclo For

La forza fondamentale quando si lavora con un ciclo for è l'abilità di fare rapidi cambiamenti al codice. Poiché il codice all'interno del blocco è solitamente eseguito molteplici volte, un cambiamento al blocco è amplificato quando il codice è in esecuzione. Modificando anche

lievemente l'Esempio 4-6, possiamo creare una serie di pattern differenti:

size(480, 120);smooth();strokeWeight(2);for (int i = 20; i < 400; i += 8) {line(i, 40, i + 60, 80);}

Esempio 4-8: Aprire le Linee a Ventaglio

size(480, 120);smooth();strokeWeight(2);for (int i = 20; i < 400; i += 20) {line(i, 0, i + i/2, 80);}

Esempio 4-9: Attorcigliare le Linee

size(480, 120);smooth();strokeWeight(2);for (int i = 20; i < 400; i += 20) {line(i, 0, i + i/2, 80);line(i + i/2, 80, i*1.2, 120);}

Esempio 4-10: Incorporare un Ciclo For dentro un altro

Quando un ciclo for è annidato in un altro, il numero delle ripetizioni viene moltiplicato. Per prima cosa, diamo un'occhiata a questo breve esempio, poi lo scomporremo nell'Esempio 4-11:

size(480, 120);background(0);smooth();noStroke();for (int y = 0; y <= height; y += 40) {for (int x = 0; x <= width; x += 40) {fill(255, 140);ellipse(x, y, 40, 40);}}

Esempio 4-11: Righe e Colonne

In questo esempio, i cicli for sono adiacenti, invece di essere annidati l'uno dentro l'altro. Il risultato mostra che un ciclo for disegna una colonna di 4 cerchi e l'altro una riga di 13 cerchi:

size(480, 120);background(0);smooth();noStroke();for (int y = 0; y < height+45; y += 40) {fill(255, 140);

ellipse(0, y, 40, 40);}for (int x = 0; x < width+45; x += 40) {fill(255, 140);ellipse(x, 0, 40, 40);}

Quando uno di questi cicli for è posizionato dentro l'altro, come nell'esempio 4-10, le 4 ripetizioni del primo ciclo sono aggiunte alle 13 del secondo allo scopo di eseguire il codice all'interno del blocco incorporato per 52 volte ( 4*13=52).

L'Esempio 4-10 è un'ottima base per esplorare diversi tipi di pattern visivi ripetitivi. L'esempio che segue mostra un paio di modi che possono essere estesi, ma questo è solo un minuscolo esempio di quello che è possibile fare. Nell'Esempio 4-12, il codice disegna una linea da ciascun punto della griglia fino al centro dello schermo. Nell'Esempio 4-13, le ellissi si riducono ad ogni nuova riga e si spostano verso destra addizionando la coordinata y alla coordinata x .

Esempio 4-12: Spilli e Linee

size(480, 120);background(0);smooth();fill(255);stroke(102);for (int y = 20; y <= height-20; y += 10) {for (int x = 20; x <= width-20; x += 10) {ellipse(x, y, 4, 4);// Disegna una linea al centro della visualizzazioneline(x, y, 240, 60);}}

Esempio 4-13: Punti in Mezzotono

size(480, 120);background(0);smooth();for (int y = 32; y <= height; y += 8) {for (int x = 12; x <= width; x += 15) {ellipse(x + y, y, 16 - y/10.0, 16 - y/10.0);}}

Robot 2: Variabili

Le variabili introdotte in questo programma rendono l'aspetto del codice più complesso del Robot 1(vedi “Robot 1: Disegna” nel Capitolo 3), ma ora è molto più facile da modificare, poiché i numeri che dipendono gli uni dagli altri sono sistemati in un unico luogo. Ad esempio, il collo può essere disegnato basandosi sulla variabile bodyHeight . Il gruppo di variabili in cima al codice controlla gli aspetti del robot che vogliamo cambiare: posizione, altezza del corpo e altezza del collo. Puoi

osservare alcune delle serie di variazioni possibili nella figura; da sinistra a destra, ecco i valori che ne corrispondono:

y = 390bodyHeight = 180neckHeight = 40

y = 460bodyHeight = 260neckHeight = 95

y = 310bodyHeight = 80neckHeight = 10

y = 420bodyHeight = 110neckHeight = 140

Quando modifichi il tuo codice per usare variabili invece di numeri, pianifica i cambiamenti attentamente, e opera le modifiche a piccoli passi. Ad esempio, quando il programma viene scritto, viene creata una variabile alla volta per minimizzare la complessità della transizione. Dopo che una variabile è stata aggiunta ed il codice è stato eseguito per assicurare che funzioni, viene aggiunta la prossima variabile:

int x = 60; // coordinata-xint y = 420; // coordinata-yint bodyHeight = 110; // Altezza Corpoint neckHeight = 140; // Altezza Colloint radius = 45; // Raggio Testaint ny = y - bodyHeight - neckHeight - radius; // Neck Ysize(170, 480);smooth();strokeWeight(2);background(204);ellipseMode(RADIUS);// Collostroke(102);line(x+2, y-bodyHeight, x+2, ny);line(x+12, y-bodyHeight, x+12, ny);line(x+22, y-bodyHeight, x+22, ny);// Antenneline(x+12, ny, x-18, ny-43);line(x+12, ny, x+42, ny-99);line(x+12, ny, x+78, ny+15);// CorponoStroke();fill(102);ellipse(x, y-33, 33, 33);fill(0);rect(x-45, y-bodyHeight, 90, bodyHeight-33);fill(102);rect(x-45, y-bodyHeight+17, 90, 6);// Testafill(0);ellipse(x+12, ny, radius, radius);fill(255);ellipse(x+24, ny-6, 14, 14);fill(0);ellipse(x+24, ny-6, 3, 3);fill(153);

ellipse(x, ny-8, 5, 5);ellipse(x+30, ny-26, 4, 4);ellipse(x+41, ny+6, 3, 3);

5/Risposta

Un tipo di codice che risponda agli input del mouse, della tastiera, e ad altri dispositivi ha bisogno di essere eseguito in continuazione. Per far si che questo accada, inserisci le righe che devono essere aggiornate in una funzione di Processing chiamata draw( ).

Esempio 5-1: La funzione draw( ).

Per vedere come lavora la funzione draw( ), esegui questo esempio:

void draw() {// Visualizza il conteggio dei frame sulla consoleprintln("Sto disegnando");println(frameCount);}

Vedrai ciò che segue:

Sto disegnando1Sto disegnando2Sto disegnando3…

Il codice contenuto all'interno del blocco draw( ) scorre dalla cima al fondo, poi si ripete finchè non esci dal programma cliccando sul pulsante Stop o chiudendo la finestra. Ogni ciclo all'interno del draw( ) è chiamato frame. (la frequenza di default è di 60 frame al secondo, ma può essere cambiata. Vedi l'Esempio 7-2 per maggiori informazioni.) Nel programma dell'esempio precedente, la funzione println( ) scrive il testo “Sto disegnando” seguito dal conteggio del frame corrente calcolato dalla variabile speciale frameCount (1,2,3,...). Il testo appare sulla console, l'area nera nella finestra di editor di Processing.

Esempio 5-2: La Funzione Setup( )

Per completare la funzione ricorrente draw( ), Processing inserisce una funzione chiamata setup( )che viene eseguita solo una volta quando il programma parte:

void setup() {println("Sto iniziando");}void draw() {println("Sono in esecuzione");}

Quando il codice è in esecuzione, ciò che segue viene trascritto sulla console:

Sto iniziandoSono in esecuzioneSono in esecuzioneSono in esecuzione…

Il testo “Sono in esecuzione” continua ad essere scritto nella console finchè il programma non viene fermato.

In un programma tipico, il codice all'interno di setup( ) è usato per determinare i valori di partenza.La prima riga è sempre la funzione size( ), spesso seguita dal codice che imposta i colori di partenza per il riempimento ed il contorno, o magari per caricare immagini e font. (Se non inserisci la funzione size( ) , la finestra di visualizzazione sarà di 100x100 pixel.)

Ora sai come usare setup( ) e draw( ) , ma non finisce qua. C'è un altro luogo per inserire il codice, puoi anche inserire delle variabili all'esterno di setup( ) e draw( ) . Se crei una variabile all'interno di setup( ) , non puoi usarla all'interno di draw( ) , quindi hai bisogno di posizionare queste variabili da qualche altra parte. Queste variabili sono chiamate variabili globali, perchè possono essere usate ovunque (“globalmente”) all'interno del programma. Questo diventa chiaro quando elenchiamo l'ordine in cui il codice viene eseguito:

1. Sono create le variabili dichiarate fuori setup( ) e draw( ).2. Il codice all'interno di setup( ) viene eseguito una sola volta.3. Il codice all'interno di draw( ) è eseguito continuamente.

Esempio 5-3: setup( ) incontra draw( )

L'esempio che segue raccoglie tutto insieme:

int x = 280;int y = -100;int diameter = 380;void setup() {size(480, 120);smooth();fill(102);}void draw() {background(204);ellipse(x, y, diameter, diameter);}

Seguire

Ora che abbiamo codice che viene eseguito continuativamente, possiamo prender traccia della posizione del mouse e usare questi numeri per muovere gli elementi sullo schermo.

Esempio 5-4: Tracciare il Mouse

La variabile mouseX memorizza la coordinata-x, e la variabile mouseY immagazzina la coordinata-y:

void setup() {size(480, 120);fill(0, 102);smooth();noStroke();}void draw() {ellipse(mouseX, mouseY, 9, 9);}

In questo esempio, ogni volta che il codice all'interno del blocco draw( ) viene eseguito, un nuovo cerchio è disegnato sulla finestra. Questa immagine è stata fatta muovendo il mouse qua e là controllando la posizione del cerchio. Poiché il riempimento è impostato per essere parzialmente trasparente, le aree di nero più denso mostrano dove il mouse ha passato più tempo e dove si è mosso più lentamente. I cerchi che sono più spaziati tra loro mostrano dove il mouse si è mosso più velocemente.

Esempio 5-5: Il Punto ti Segue

In questo esempio, un nuovo cerchio è aggiunto alla finestra ogni volta che il codice all'interno di draw( ) è eseguito. Per rinnovare lo schermo e visualizzare solo in nuovo cerchio, inserisci la funzione background( ) all'inizio di draw( ) prima che la forma sia disegnata:

void setup() {size(480, 120);fill(0, 102);smooth();noStroke();}void draw() {background(204);ellipse(mouseX, mouseY, 9, 9);}

La funzione background( ) ripulisce l'intera finestra, quindi sii sicuro di inserirla sempre prima delle altre funzioni all'interno di draw( ) ; in caso contrario, le forme disegnate prima saranno cancellate.

Esempio 5-6: Disegna in Modo Continuo

Le variabili pmouseX e pmouseY assumono la posizione del mouse al frame precedente.Come mouseX e mouseY , queste variabili speciali sono aggiornate ogni volta che draw( ) viene eseguito. Quando sono combinate, possono essere usate per disegnare linee continue connettendo la posizione corrente con quella più recente.

void setup() {size(480, 120);strokeWeight(4);smooth();stroke(0, 102);}void draw() {line(mouseX, mouseY, pmouseX, pmouseY);}

Esempio 5-7: Imposta lo Spessore al Volo

Le variabili pmouseX e pmouseY possono essere usate anche per calcolare la velocità del mouse. Questo viene ottenuto dalla misurazione della distanza tra la posizione del mouse corrente e quella più recente. Se il mouse si muove lentamente, la distanza è piccola, ma se il mouse inizia a muoversi più velocemente, la distanza cresce. Una funzione chiamata dist( ) semplifica il calcolo, come mostrato nell'esempio seguente. In questo caso, la velocità del mouse è usata per regolare lo spessore della linea disegnata:

void setup() {size(480, 120);smooth();stroke(0, 102);}void draw() {float weight = dist(mouseX, mouseY, pmouseX, pmouseY);strokeWeight(weight);line(mouseX, mouseY, pmouseX, pmouseY);}

Esempio 5-8: l'Easing lo fa

Nell'esempio 5-7, i valori dal mouse sono convertiti direttamente in posizioni sullo schermo. Ma a volte puoi volere che i valori seguano il mouse vagamente, rimanendo indietro per creare un movimento più fluido. Questa tecnica è chiamata Easing. Con l'easing abbiamo due valori: il valore corrente ed il valore in cui ci andremo a muovere ( vedi figura 5-1). Ad ogni passo nel programma, il valore corrente si sposta leggermente più vicino al valore che abbiamo come obiettivo:

float x;float easing = 0.01;float diameter = 12;void setup() {size(220, 120);smooth();}void draw() {float targetX = mouseX;x += (targetX - x) * easing;ellipse(x, 40, 12, 12);println(targetX + " : " + x);}

Il valore della variabile x è sempre più vicino a targetX. La velocità in cui raggiungerà targetX è impostata con la variabile easing, un numero tra 0 e 1. Un piccolo valore per l'easing causa un ritardo maggiore che un valore più grande. Con un valore di easing impostato ad 1, non abbiamo ritardo. Quando esegui l'Esempio 5-8, il valori attuali sono mostrati nella Console attraverso la

funzione println( ) . Quando muoviamo il mouse, nota come i numeri sono distanti, ma quando il mouse smette di muoversi,il valore della x si avvicina a targetX.

Tutto il lavoro in questo esempio avviene nella riga che inizia con x +=.Qui viene calcolata la differenza tra l'obiettivo ed il valore corrente, poi moltiplicata dalla variabile di easing e aggiunta alla x per portarla vicino all'obiettivo.

Esempio 5-9:Smussa le Linee con l'Easing

In questa dimostrazione, la tecnica easing è applicata all'Esempio 5-7. Confrontandoli, le linee sono più smussate:

float x;float y;float px;float py;float easing = 0.05;void setup() {size(480, 120);smooth();stroke(0, 102);}void draw() {float targetX = mouseX;x += (targetX - x) * easing;float targetY = mouseY;y += (targetY - y) * easing;float weight = dist(x, y, px, py);strokeWeight(weight);line(x, y, px, py);py = y;px = x;}

Mappare

Quando vengono usati dei numeri per disegnare sullo schermo, è spesso utile convertirne i valori da una serie di numeri ad un'altra.

Esempio 5-10: Riportare i Valori ad una Serie

Il valore della variabile mouseX usualmente si trova tra lo 0 e la larghezza della finestra, ma potresti desiderare di rimappare questi valori ad una gamma differente di coordinate. Puoi farlo facendo dei calcoli, come dividere mouseX per un numero al fine di ridurre l'intervallo numerico e poi addizionare o sottrarre un numero per spostarlo a destra o a sinistra:

void setup() {size(240, 120);strokeWeight(12);smooth();}void draw() {background(204);stroke(255);line(120, 60, mouseX, mouseY); // Linea biancastroke(0);

float mx = mouseX/2 + 60;line(120, 60, mx, mouseY); // Linea nera}

La funzione map( ) è un modo più generico di operare questo tipo di cambiamento. Converte una variabile da una serie di numeri ad un'altra. Il primo parametro è la variabile che dev'essere convertita, il secondo ed il terzo parametro sono il valore più basso ed il valore più alto di questa variabile, ed il quarto ed il quinto parametro sono rispettivamente i valori più alto e più basso desiderati.La funzione map( ) ti permette di tralasciare la matematica che c'è dietro la conversione.

Esempio 5-11: Mappare con la Funzione map( )

Questo esempio riconsidera l'Esempio 5-10 usando map( ):

void setup() {size(240, 120);strokeWeight(12);smooth();}void draw() {background(204);stroke(255);line(120, 60, mouseX, mouseY); // Linea biancastroke(0);float mx = map(mouseX, 0, width, 60, 180);line(120, 60, mx, mouseY); // Linea nera}

La funzione map( ) rende il codice più facile da leggere, poiché i valori minimo e massimo sono chiaramente scritti come parametri. In questo esempio,i valori di mouseX tra lo 0 e width sono convertiti ad un numero che va da 60 (quando mouseX è 0) fino a 180 (quando mouseX ha il valore di width) Troverai l'utile funzione map( ) in molti esempi all'interno di questo libro.

Click

In aggiunta alla posizione del mouse, Processing può anche prender nota di quando il pulsante del mouse è premuto. La variabile mousePressed ha un valore differente quando il pulsante è premuto e quando non lo è. La variabile mousePressed ha una tipologia di dati chiamato booleana, cioè che ha solamente due possibili valori: vero e falso. Il valore di mousePressed è vero quando il mouse è premuto.

Esempio 5-12: Cliccare il Mouse

La variabile mousePressed è usata insieme alla dichiarazione if per determinare quando una riga di codice dev'essere eseguita e quando non dev'esserlo. Prova questo esempio prima di andare avanti ulteriormente:

void setup() {size(240, 120);smooth();strokeWeight(30);}void draw() {background(204);

stroke(102);line(40, 0, 70, height);if (mousePressed == true) {stroke(0);}line(0, 70, width, 50);}

In questo programma, il codice all'interno del blocco if viene eseguito solo quando un pulsante del mouse viene premuto. Quando un pulsante non è premuto, questo codice viene ignorato. Come il ciclo for trattato in “Ripetizione” nel Capitolo 4, anche l'if ha un test che valuta con la meccanica del true o false.

If (test) {dichiarazioni

}

Quando il test è vero, il codice all'interno del blocco viene eseguito; quando il test è falso , il codice non viene eseguito. Il computer determina se il test è vero o falso valutando l'espressione all'interno delle parentesi. (se hai bisogno di rinfrescare la memoria, la discussione riguardante le espressioni relative è nell'esempio 4-6.)

Il simbolo == confronta i valori sulla sinistra e sulla destra per valutare se sono equivalenti. Il simbolo == è diverso dall'operatore di assegnazione, il singolo simbolo =. Il simbolo == chiede,”Queste due cose sono uguali?” invece il simbolo = imposta il valore di una variabile.

NOTA: è un errore comune, anche per programmatori esperti, scrivere nel codice = quando invece volevi scrivere ==. Il software di Processing non ti avvertirà sempre quando questo accade, quindi cerca di essere preciso.

In alternativa, il testo all'interno di draw nell'Esempio 5-12 può venir scritto in questo modo:

if (mousePressed) {

Le variabili booleane, inclusa mousePressed, non hanno bisogno del confronto esplicito con l'operatore ==, perché può esser solo vero o falso.

Esempio 5-13: Individuare Quando non è Cliccato

Un blocco if singolo ti da la possibilità di scegliere tra l'eseguire una parte di codice o trascurarla.Puoi estendere un blocco if con un blocco else, permettendo al tuo programma di scegliere tra due opzioni. Il codice all'interno del blocco else viene eseguito quando il valore del test del blocco if è falso. Ad esempio, il colore del contorno per un programma può essere bianco quando il mouse non è premuto, e può cambiare nel colore nero quando il pulsante è premuto:

void setup() {size(240, 120);smooth();strokeWeight(30);}void draw() {background(204);stroke(102);line(40, 0, 70, height);

if (mousePressed) {stroke(0);} else {stroke(255);}line(0, 70, width, 50);}

Esempio 5-14: Pulsanti del Mouse Multipli

Processing inoltre registra quale pulsante è premuto se ne hai più di uno sul mouse.La variabile mouseButton può avere uno di questi tre valori: LEFT, CENTER, o RIGHT.Per provare quale pulsante è stato premuto, c'è bisogno dell'operatore == , come è mostrato qui:

void setup() {size(120, 120);smooth();strokeWeight(30);}void draw() {background(204);stroke(102);line(40, 0, 70, height);if (mousePressed) {if (mouseButton == LEFT) {stroke(255);} else {stroke(0);}line(0, 70, width, 50);}}

Un programma può avere molte più strutture di if e di else (vedi la Figura 5-2) di quelle trovate in questi brevi esempi.Essi possono essere incatenati assieme in lunghe serie, che testino ognuna qualcosa di differente, e i blocchi di if possono essere incorporati all'interno di altri blocchi di if per creare delle strutture più complesse.

Posizione

Una struttura if può essere usata con i valori di mouseX e mouseY per determinare la posizione del cursore all'interno della finestra.

Esempio 5-15: Trovare il Cursore

Per esaminare un caso, questo esempio prova a vedere se il cursore è sulla parte destra o sulla parte sinistra di una linea e quindi muove la linea verso il cursore.

float x;int offset = 10;void setup() {size(240, 120);smooth();x = width/2;}

void draw() {background(204);if (mouseX > x) {x += 0.5;offset = -10;}if (mouseX < x) {x -= 0.5;offset = 10;}line(x, 0, x, height);line(mouseX, mouseY, mouseX + offset, mouseY - 10);line(mouseX, mouseY, mouseX + offset, mouseY + 10);line(mouseX, mouseY, mouseX + offset*3, mouseY);}

Per scrivere dei programmi che abbiano delle interfacce grafiche per l'utente (pulsanti, caselle, barre di scorrimento, e così via), abbiamo bisogno di di scrivere del codice che riconosca quando il cursore è all'interno un'area circoscritta dello schermo.I due esempi seguenti introducono il modo di controllare se il cursore è all'interno di un cerchio e di un rettangolo. Il codice è scritto in maniera modulare con delle variabili, così che può essere usato per verificare qualsiasi cerchio e rettangolo cambiandone i valori.

Esempio 5-16: I Confini di un Cerchio

Per il test sul cerchio, usiamo la funzione dist( ) per prendere la distanza dal centro del cerchio al cursore, poi proviamo a vedere se questa distanza è minore del raggio del cerchio (vedi la Figura 5-3). Se questo accade, sappiamo che siamo all'interno.In questo esempio, quando il cursore è all'interno dell'area del cerchio, la sua dimensione aumenta:

int x = 120;int y = 60;int radius = 12;void setup() {size(240, 120);smooth();ellipseMode(RADIUS);}void draw() {background(204);float d = dist(mouseX, mouseY, x, y);if (d < radius) {radius++;fill(0);} else {fill(255);}ellipse(x, y, radius, radius);}

Esempio 5-17: I Confini di un Rettangolo

Usiamo un altro approccio per provare se il cursore è all'interno di un rettangolo.Facciamo quattro test separati per capire se il cursore è nella parte corretta di ogni margine del rettangolo, poi compariamo ciascun test e se sono tutti veri, sappiamo che il cursore è all'interno del rettangolo. Ciò è illustrato nella Figura 5-4. Ogni passo è semplice, ma appare complicato quando tutto ciò è messo insieme:

int x = 80;int y = 30;int w = 80;int h = 60;void setup() {size(240, 120);}void draw() {background(204);if ((mouseX > x) && (mouseX < x+w) &&(mouseY > y) && (mouseY < y+h)) {fill(0);} else {fill(255);}rect(x, y, w, h);}

Il test nella dichiarazione if è leggermente più complesso di quello che abbiamo visto.Quattro test individuali ( esempio, mouseX > x ) sono combinati con l'operatore logico AND, il simbolo &&, per assicurare che ogni espressione in relazione nella sequenza è vera. Se una di esse è falsa, l'intero test diventa falso ed il colore di riempimento non sarà impostato sul nero.Questo è spiegato ulteriormente nella voce && delle referenze.

Caratteri tipografici

Processing prende nota di quando un qualsiasi pulsante sulla tastiera viene premuto, così come l'ultimo pulsante premuto. Come la variabile mousePressed , la variabile keyPressed è vera quando qualsiasi pulsante viene premuto, e falsa quando non viene premuto alcun pulsante.

Esempio 5-18: Premere un Pulsante

In questo esempio, la seconda linea viene disegnata solamente quando viene premuto un pulsante:

void setup() {size(240, 120);smooth();}void draw() {background(204);line(20, 20, 220, 100);if (keyPressed) {line(220, 20, 20, 100);}}

La variabile key immagazzina il pulsante che è stato premuto più recentemente. Il data type per la variabile key è char, che è un'abbreviazione per “character” (carattere) , ma di solito viene pronunciato come la prima sillaba di “charcoal”. Una variabile char può contenere qualunque carattere singolo, il quale include lettere dell'alfabeto, numeri, e simboli.A differenza del valore string (vedi l'Esempio 6-8), il quale si distingue per le doppie virgolette, il data type char viene specificato dalle virgolette singole. Questo è come una variabile char è dichiarata ed assegnata:

char c = 'A'; // Dichiara ed Assegna 'A' alla variabile c

E questi tentativi causeranno un errore:

char c = "A"; // Errore!Non è possibile assegnare una stringa a Charchar h = A; // Errore!Mancano le singole virgolette per 'A'

A differenza della variabile booleana keyPressed , la quale si inverte in false ogniqualvolta un pulsante è rilasciato, la variabile key mantiene il suo valore finché non viene premuto il prossimo pulsante. L'esempio seguente utilizza il valore di key per disegnare dei caratteri sullo schermo.Ogni volta che viene premuto un nuovo pulsante, il valore si aggiorna e viene disegnato un nuovo carattere. Alcuni pulsanti, come Shift ed Alt, non hanno un carattere visibile, cosicché quando li premerai non sarà visualizzato nulla.

Esempio 5-19: Disegnare Alcune Lettere

Questo esempio introduce la funzione textSize( ) per impostare la dimensione delle lettere, la funzione textAlign( ) per centrare il testo sulla sua coordinata x, e la funzione text( ) per disegnare lettere. Queste funzioni verranno discusse più dettagliatamente nelle pagine 84-85.

void setup() {size(120, 120);textSize(64);textAlign(CENTER);}void draw() {background(0);text(key, 60, 80);}

Usando la struttura if , possiamo provare a vedere se un pulsante specifico è premuto e scegliere di disegnare qualcosa sullo schermo come risposta.

Esempio 5-20: Verificare i Pulsanti Specifici

In questo esempio, proviamo a digitare una H o una N. Usiamo l'operatore di paragone, il simbolo = =, per vedere se il valore key è uguale ai caratteri che stiamo cercando:

void setup() {size(120, 120);smooth();}void draw() {background(204);if (keyPressed) {if ((key == 'h') || (key == 'H')) {line(30, 60, 90, 60);}if ((key == 'n') || (key == 'N')) {line(30, 20, 90, 100);}}line(30, 20, 30, 100);line(90, 20, 90, 100);}

Quando stiamo osservando se H o N sono premuti, abbiamo bisogno di verificare sia se sono lettere

maiuscole o minuscole, nel caso che qualcuno prema il pulsante Shift o abbia attivato il Blocco Maiuscole. Combiniamo insieme i due test con un OR logico, il simbolo ||.Se traduciamo il primo dichiarato if di questo esempio in linguaggio semplice, questo dice,“Se il pulsante 'h' è premuto o il pulsante 'H' è premuto”. A differenza dell'Esempio 5-17 con l'AND logico (il simbolo &&), solamente una di queste dev'essere vera perchè l'intero test sia vero.

Alcuni pulsanti sono più difficili da individuare, poiché non sono legati d una lettera particolare.Pulsanti come Shift, Alt, e i tasti freccia sono codificati e richiedono un passo in più per capire se sono stati premuti. Prima di tutto abbiamo bisogno di verificare se il pulsante che è stato premuto è codificato, poi controlliamo il codice con la variabile keyCode per capire di quale pulsante si tratta.I valori di keyCode usati più frequentemente sono ALT, CONTROL, e SHIFT, così come i pulsanti freccia, UP, DOWN, LEFT, e RIGHT.

Esempio 5-21: Muoversi con le Frecce Direzionali

L'esempio seguente mostra come verificare se i pulsanti freccia destra o sinistra sono premuti per muovere un rettangolo:

int x = 215;void setup() {size(480, 120);}void draw() {if (keyPressed && (key == CODED)) { // If it’s a coded keyif (keyCode == LEFT) { // If it’s the left arrowx--;} else if (keyCode == RIGHT) { // If it’s the right arrowx++;}}rect(x, 45, 50, 50);}

Robot 3: Risposta

Questo programma utilizza le variabili introdotte in Robot 2 (vedi “Robot 2: Variabili” nel capitolo 4) e rende possibile cambiarle mentre il programma è in esecuzione così da far rispondere le forme al mouse . Il codice all'interno del blocco draw( ) viene eseguito diverse volte al secondo. Ad ogni nuovo frame, le variabili definite nel programma cambiano in risposta alle variabili mouseX o mousePressed.

Il valore di mouseX controlla la posizione del Robot con una tecnica di rallentamento cosicché i movimenti siano meno istantanei e sembrino così più naturali. Quando un pulsante del mouse viene premuto, i valori di neckHeight e bodyHeight cambiano per far abbassare il robot.

float x = 60; // coordinata Xfloat y = 440; // coordinata Yint radius = 45; // Raggio della Testaint bodyHeight = 160; // Altezza del Corpoint neckHeight = 70; // Altezza del Collofloat easing = 0.02;

void setup() {size(360, 480);smooth();strokeWeight(2);ellipseMode(RADIUS);}void draw() {int targetX = mouseX;x += (targetX - x) * easing;if (mousePressed) {neckHeight = 16;bodyHeight = 90;} else {neckHeight = 70;bodyHeight = 160;}float ny = y - bodyHeight - neckHeight - radius;background(204);// Collostroke(102);line(x+12, y-bodyHeight, x+12, ny);// Antenneline(x+12, ny, x-18, ny-43);line(x+12, ny, x+42, ny-99);line(x+12, ny, x+78, ny+15);// CorponoStroke();fill(102);ellipse(x, y-33, 33, 33);fill(0);rect(x-45, y-bodyHeight, 90, bodyHeight-33);// Testafill(0);ellipse(x+12, ny, radius, radius);fill(255);ellipse(x+24, ny-6, 14, 14);fill(0);ellipse(x+24, ny-6, 3, 3);}

6/Media

Processing è capace di disegnare più che semplici linee e forme.É arrivato il momento di imparare come caricare immagini raster, file vettoriali, e font all'interno del nostro programma per estendere le possibilità visuali alla fotografia , a diagrammi dettagliati, e ai più diversi caratteri tipografici.Processing utilizza una cartella chiamata data per conservare questi file, cosicché non c'è il bisogno di pensare alla loro posizione quando creiamo uno Sketch che verrà eseguito sul desktop, sul Web o su di un dispositivo mobile. Abbiamo postato alcuni file multimediali online perchè li usiate negli esempi di questo capitolo: http://www.processing.org/learning/books/media.zip .

Scarica questo file, decomprimilo sul desktop ( o da qualsiasi altra parte che sià più comoda), e prendi mentalmente nota della sua posizione.

NOTA: Per la decompressione su Mac OS X, basta fare doppio-click sul file, e verrà creata una cartella chiamata media. Su Windows, fai doppio-click sul file media.zip , che aprirà una nuova finestra. In questa finestra, trascina la cartella media sul desktop.

Crea un nuovo sketch, e seleziona Add File dal menu Sketch. Trova il file lunar.jpg dalla cartella media che hai appena decompresso e selezionalo. Se tutto va per il verso giusto, nell'area dei messaggi si leggerà “1 file added to the sketch.”

Per controllare il file, selezionare Show Sketch folder nel menu Sketch. Dovresti vedere una cartella chiamata data, con una copia di lunar.jpg all'interno. Quando aggiungi un file allo sketch, la cartella data verrà creata automaticamente. Invece di usare comando Add File dal menu, puoi ottenere la stessa cosa trascinando i file all'interno dell'area di editor della finestra di Processing. I file saranno copiati nella cartella data allo stesso modo ( e la cartella verrà creata se non esisteva già ).

Puoi anche creare la cartella data fuori da Processing e copiare qui i tuoi file da solo. Non avrai il messaggio che ti dirà che questi file sono stati aggiunti, ma questo è un utile metodo quando stai lavorando con un gran numero di file.

NOTA: Su Windows e Mac OS X, le estensioni dei file sono nascoste di default. É una buona idea cambiare questa impostazione così che potrai sempre vedere l'intero nome dei tuoi file.Su Mac OS X, seleziona Preferences dal menu Finder, e assicurati che “Show all filename extension” è selezionato nella tab Advanced. Su Windows, cerca “Folder

Options” ( Opzioni Cartella ) e selezionane qui l'opzione.

Immagini

Ci sono tre passi da seguire prima di poter disegnare un'immagine sullo schermo:

1. Aggiungere l'immagine nella cartella data dello sketch (le istruzioni sono state date in precedenza)

2. Creare una variabile PImage per immagazzinare le immagini.3. Caricare l'immagine nella variabile con loadImage( ).

Esempio 6-1: Caricare un'Immagine

Dopo che ogni passo è stato effettuato, puoi disegnare l'immagine sullo schermo con la funzione image( ) . Il primo parametro di image( ) specifica l'immagine da disegnare; il secondo ed il terzo impostano le coordinate x ed y:

PImage img;void setup() {size(480, 120);img = loadImage("lunar.jpg");}void draw() {image(img, 0, 0);}

I parametri quattro e cinque sono opzionali ed impostano l'altezza e la larghezza in cui verrà disegnata l'immagine.

Questi prossimi esempi mostrano come lavorare con più di un'immagine nello stesso programma e come ridimensionare un'immagine.

Esempio 6-2: Caricare più di un'Immagine

per questo esempio, hai bisogno di aggiungere il file capsule.jpg ( che si trova nella cartella media che hai scaricato ) al tuo sketch usando uno dei metodi spiegati prima.

PImage img1;PImage img2;void setup() {size(480, 120);img1 = loadImage("lunar.jpg");img2 = loadImage("capsule.jpg");}void draw() {image(img1, -120, 0);image(img1, 130, 0, 240, 120);image(img2, 300, 0, 240, 120);}

Esempio 6-3: Usare il Mouse con le Immagini

Quando i valori di mouseX e mouseY sono usati come parte del quarto e quinto parametro della

funzione image( ) , la dimensione dell'immagine verrà cambiata con il movimento del mouse:

PImage img;void setup() {size(480, 120);img = loadImage("lunar.jpg");}void draw() {background(0);image(img, 0, 0, mouseX * 2, mouseY * 2);}

NOTA: Quando un'immagine è visualizzata più grande o più piccola del suo formato reale, può venire distorta. Fai attenzione nel preparare la tua immagine nella dimensione in cui sarà utilizzata.Quando il formato di visualizzazione dell'immagine viene cambiato con la funzione image( ), l'immagine vera e propria sul disco rigido subisce modifiche.

Processing può caricare e visualizzare immagini raster nei formati JPEG, PNG e GIF.(le forme vettoriali nel formato SVG possono essere visualizzate in modo differente, come descritto in “Forme”, in seguito in questo capitolo.) Puoi convertire le immagini nei formati JPEG,PNG e GIF usando programmi come GIMP e Photoshop. La maggior parte delle fotocamere digitali salvano immagini in JPEG, ma di solito c'è bisogno di ridurne la grandezza prima di usarle con Processing. Una tipica fotocamera digitale crea un'immagine che è diverse volte più grande dell'area di disegno della maggioranza degli sketch di Processing, così ridimensionare queste immagini prima che siano aggiunte alla cartella data rende l'esecuzione degli sketch più efficiente, e riparmia spazio sul disco.

Le immagini GIF e PNG supportano la trasparenza, ciò vuol dire che questi pixel possono essere invisibili o parzialmente visibili (ricorda la discussione su color( ) e i valori alpha nelle pagine 26-29). Le immagini GIF hanno 1 bit di trasparenza, ovvero che i pixel sono o totalmente opachi o completamente trasparenti. Le immagini PNG hanno 8 bit di trasparenza, ciò comporta che ogni pixel può avere un livello variabile di trasparenza. L'esempio seguente mostra la differenza, usando i file clouds.gif e clouds.png trovati nella cartella media che hai scaricato. Sii sicuro di aggiungerla allo sketch prima di provare ogni esempio.

Esempio 6-4: Trasparenza con un GIF

PImage img;void setup() {size(480, 120);img = loadImage("clouds.gif");}void draw() {background(255);image(img, 0, 0);image(img, 0, mouseY * -1);}

Esempio 6-5: Trasparenza con un PNG

PImage img;void setup() {size(480, 120);img = loadImage("clouds.png");}

void draw() {background(204);image(img, 0, 0);image(img, 0, mouseY * -1);}

NOTA: Ricorda di inserire l'estensione del file .gif , .jpg , o .png quando carichi l'immagine. Inoltre assicurati che il nome dell'immagine è stato scritto correttamente così come appare nel file, anche se le lettere sono maiuscole o minuscole. E se te la sei persa, leggi la nota precedente in questo capitolo riguardo all'essere sicuri che l'estensione dei file sia visibile su Mac OS X e su Windows.

Font

Processing può visualizzare il testo con font diversi da quello predefinito. Prima di poter visualizzare il testo in un carattere differente, hai bisogno di convertire un font installato nel tuo computer nel formato VLW, il quale memorizza ogni lettera come una piccola immagine. Per fare ciò, seleziona Create Font dal menu Tools per aprire la finestra di dialogo ( Figura 6-1 ). Specifica il font che vuoi convertire, così come la dimensione e se vuoi che sia smussato (anti-aliased).

NOTA: Seleziona attentamente la dimensione del font considerando ciò che segue:crea il font con la grandezza in cui preferisci usarlo nel tuo sketch (o più largo), ma tieni in mente che dimensioni più grandi aumentano la dimensione del file. Seleziona l'opzione dei caratteri solo se userai caratteri non romani come testi giapponesi o cinesi, poiché anche questo aumenterà la grandezza del file significativamente.

Quando clicchi il pulsante OK nello strumento Create Font, il font VLW viene creato e posizionato nella cartella data dello sketch. Ora è possibile caricare il font e aggiungere parole allo sketch. Questa parte è simile a ciò che accade lavorando con le immagini, ma con un passo ulteriore:

1. Aggiungi il font alla cartella data dello sketch (istruzioni date in precedenza).2. Crea una variabile PFont per memorizzare il font.3. Carica il font nella variabile con loadFont( ) .4. Usa il comando textFont( ) per impostare il font corrente.

Esempio 6-6: Disegnare con i Font

Ora puoi disegnare queste lettere sullo schermo con la funzione text( ), e puoi cambiarne la dimensione con textSize( ). Per questo esempio, hai bisogno di usare lo strumento Create Font per creare un font VLW ( e modificare la riga loadFont( ) per usarlo), oppure puoi usare AndaleMono-36.vlw dalla cartella media:

PFont font;void setup() {size(480, 120);smooth();font = loadFont("AndaleMono-36.vlw");textFont(font);}void draw() {background(102);textSize(36);text("That’s one small step for man...", 25, 60);textSize(18);text("That’s one small step for man...", 27, 90);

}

Il primo parametro di text( ) è il carattere o i caratteri da tracciare sullo schermo.(nota che i caratteri sono racchiuse all'interno delle virgolette.) Il secondo e terzo parametro imposta la posizione orizzontale e verticale. La posizione è relativa alla linea di base del testo (vedi Figura 6-2).

Esempio 6-7: Disegnare del Testo in un Riquadro

Puoi anche impostare il testo per disegnarlo all'interno di un riquadro aggiungendo i parametri quattro e cinque che specificano l'altezza e la larghezza del riquadro:

PFont font;void setup() {size(480, 120);font = loadFont("AndaleMono-24.vlw");textFont(font);}void draw() {background(102);text("That’s one small step for man...", 26, 30, 240, 100);}

Esempio 6-8: Immagazzinare del Testo in una Stringa

Nell'esempio precedente, le parole all'interno della funzione text( ) cominciano a rendere il codice difficoltoso da leggere. Possiamo memorizzare queste parole in una variabile per rendere il codice più modulare. Il data type di String è usato per immagazzinare dati di testo.Questa è una nuova versione dell'esempio precedente usando String:

PFont font;String quote = "That’s one small step for man...";void setup() {size(480, 120);font = loadFont("AndaleMono-24.vlw");textFont(font);}void draw() {background(102);text(quote, 26, 30, 240, 100);}

Esiste una serie di funzioni supplementari che influenzano il modo di come le lettere saranno visualizzate sullo schermo. Queste sono spiegate, con esempi, nella categoria Typography delle referenze di Processing.

Forme

Se hai fatto forme vettoriali con programmi come Inkscape o Illustrator, puoi caricarle all'interno di Processing direttamente. Questo è utile per forme che si preferisce non costruire con le funzioni di disegno di Processing. Come per le immagini, devi aggiungerle al tuo sketch prima di poterle caricare.

Ci sono tre passi per caricare e tracciare un file SVG:

1. Aggiungi un file SVG alla cartella data dello sketch.2. Crea una variabile PShape per conservare il file vettoriale.3. Carica il file vettoriale all'interno della variabile con LoadShape( ).

Esempio 6-9: Disegnare con le Forme

Una volta che hai seguito questi passaggi, puoi visualizzare l'immagine sullo schermo con la funzione shape( ):

PShape network;void setup() {size(480, 120);smooth();network = loadShape("network.svg");}void draw() {background(0);shape(network, 30, 10);shape(network, 180, 10, 280, 280);}

I parametri per la funzione shape( ) sono simili ad image( ). Il primo parametro indica a shape( ) quale SVG va disegnata e i due consecutivi impostano la posizione. I parametri quattro e cinque sono opzionali e impostano la larghezza e l'altezza.

Esempio 6-10: Ridimensionare le Forme

A differenza delle immagini raster, le forme vettoriali possono essere scalate in ogni dimensione senza perdere di risoluzione. In questo esempio, la forma è ridimensionata basandosi sulla variabile mouseX, e la funzione shapeMode( ) viene usata per disegnare la forma dal centro, invece che dalla posizione predefinita, l'angolo in alto a sinistra:

PShape network;void setup() {size(240, 120);smooth();shapeMode(CENTER);network = loadShape("network.svg");}void draw() {background(0);float diameter = map(mouseX, 0, width, 10, 800);shape(network, 120, 60, diameter, diameter);}

NOTA: Esistono delle limitazioni sul tipo di file SVG che puoi caricare. Processing non supporta tutte le caratteristiche dei file SVG. Vedi le referenze di Processing per PShape per maggiori dettagli.

Robot 4: Media

A differenza dei robot creati con linee e rettangoli disegnati in Processing nei capitoli precedenti, questi robot sono stati creati con un programma di disegno vettoriale. Per alcune forme, è spesso più semplice puntare e cliccare in uno strumento software come Inkscape o Illustrator che definire le forme con il codice.

Esiste un compromesso per selezionare una tecnica di creazione dell'immagine piuttosto che un'altra. Quando le forme vengono definite in Processing, sono più facilmente modificabili mentre il programma è in esecuzione. Se le forme sono definite da qualche altra parte e poi caricate all'interno di Processing, i cambiamenti saranno limitati alla posizione, all'angolo, alla dimensione.Quando ciascun robot viene caricato da un file SVG, come mostra l'esempio, le variazioni caratterizzate in Robot 2 (vedi “Robot 2: Variabili” nel capitolo 4) sono impossibili.

Le immagini possono essere caricate all'interno di uno sketch per portare file visuali creati in altri programmi o acquisite con una fotocamera. Grazie a questa immagine come sfondo, i nostri robot sono intenti nell'esplorazione di forme di vita in Norvegia all'alba del Ventesimo secolo.

I file SVG e PNG usati in questo esempio possono essere scaricati da http://www.processing.org/learning/books/media.zip .

PShape bot1;PShape bot2;PShape bot3;PImage landscape;float easing = 0.05;float offset = 0;void setup() {size(720, 480);bot1 = loadShape("robot1.svg");bot2 = loadShape("robot2.svg");bot3 = loadShape("robot3.svg");landscape = loadImage("alpine.png");smooth();}void draw() {// Set the background to the "landscape" image; this image// must be the same width and height as the programbackground(landscape);// Set the left/right offset and apply easing to make// the transition smoothfloat targetOffset = map(mouseY, 0, height, -40, 40);offset += (targetOffset - offset) * easing;// Disegna il robot di sinistrashape(bot1, 85 + offset, 65);//Disegna il robot di destra più piccolo e ne da un contrasto minorefloat smallerOffset = offset * 0.7;shape(bot2, 510 + smallerOffset, 140, 78, 248);// Disegna il robot più piccolo e ne da un contrasto minoresmallerOffset *= -0.5;shape(bot3, 410 + smallerOffset, 225, 39, 124);}

7/MovimentoCome un flip book, l'animazione sullo schermo è ottenuta disegnando un'immagine, poi disegnare un'immagine leggermente differente, poi un'altra, e così via. L'illusione del movimento fluido è creata dalla persistenza della visione. Quando una serie di immagini simili viene presentata ad un ritmo abbastanza veloce, i nostri cervelli traducono queste immagini nel movimento.

Esempio 7-1: Osservare il Frame Rate

Per creare un movimento fluido, Processing prova ad eseguire il codice all'interno di draw( ) a 60 fotogrammi al secondo. Per confermare la frequenza dei fotogrammi, esegui questo programma e controlla i valori stampati sulla Console. La variabile frameRate prende nota della velocità del programma.

void draw() {println(frameRate);}

Esempio 7-2: Impostare il Frame Rate

La funzione FrameRate( ) cambia la velocità di esecuzione del programma. Per vederne il risultato, togli la funzione commento dalle differenti versioni di frameRate( ) in questo esempio:

void setup() {frameRate(30); // Thirty frames each second//frameRate(12); // Twelve frames each second//frameRate(2); // Two frames each second//frameRate(0.5); // One frame every two seconds}void draw() {println(frameRate);}

NOTA: Processing tenta di eseguire il codice a 60 fotogrammi al secondo, ma se questo richiede più di 1/60 di secondo per eseguire il metodo draw( ), il frame rate diminuirà. La funzione frameRate( ) specifica solo la frequenza massima dei fotogrammi, e la frequenza reale per qualsiasi programma dipende dal computer che eseguirà il codice.

Velocità e Direzione

Per creare esempi di movimento fluido, usiamo una tipologia di dati chiamata float. Questa tipologia di variabile memorizza numeri con cifre decimali, i quali forniscono maggiore risoluzione quando si lavora con il movimento. Ad esempio, quando si utilizza ints (numeri interi), la velocità minima in cui ti potrai muovere ad ogni fotogramma è di un pixel alla volta (1,2,3,4,...), ma con float, puoi muoverti alla “lentezza” che preferisci (1.01, 1.01, 1.02, 1.03,...).

Esempio 7-3: Muovere una Forma

L'esempio seguente fa muovere una forma da sinistra a destra aggiornando la variabile x:

int radius = 40;float x = -radius;float speed = 0.5;void setup() {size(240, 120);smooth();ellipseMode(RADIUS);}void draw() {background(0);x += speed; // Increase the value of xarc(x, 60, radius, radius, 0.52, 5.76);}

Quando eseguirai questo codice, noterai che la forma si muove oltre la parte destra dello schermo quando il valore della varibile x diventerà maggiore della larghezza dello schermo. Il valore di x continuerà a crescere, ma la forma non sarà più visibile.

Esempio 7-4: Girare Attorno

Ci sono molte alternative a questo comportamento, che possono essere scelte a seconda delle tue preferenze. Per prima cosa, estenderemo il codice per mostrare come far tornare la forma al bordo sinistro dello schermo dopo che essa è scomparsa a destra. In questo caso immagina lo schermo come un cilindro appiattito, con la forma che si muove all'esterno per tornare al punto si partenza:

int radius = 40;float x = -radius;float speed = 0.5;void setup() {size(240, 120);smooth();ellipseMode(RADIUS);}void draw() {background(0);x += speed; // Increase the value of xif (x > width+radius) { // If the shape is off screen,x = -radius; // move to the left edge}arc(x, 60, radius, radius, 0.52, 5.76);}

In ogni ciclo del draw( ), il codice esegue un test per vedere se il valore della x è andato oltre il valore della larghezza dello schermo (aggiungendo il raggio della forma). Se questo accade, impostiamo il valore della x con un segno negativo, in modo che se continua ad aumentare, apparirà sullo schermo da sinistra. Vedi la Figura 7-1 per un diagramma di questo funzionamento.

Esempio 7-5: Rimbalzare oltre il Muro

In questo esempio, estenderemo l'Esempio 7-3 affinchè la forma cambi direzione quando colpisce uno dei bordi, invece di girare attorno. Per far si che questo accada, aggiungiamo una nuova variabile per memorizzare la direzione della forma.Un valore di direzione fa muovere la forma verso destra, ed un valore di -1 muove la forma verso sinistra:

int radius = 40;float x = 110;float speed = 0.5;int direction = 1;void setup() {size(240, 120);smooth();ellipseMode(RADIUS);}void draw() {background(0);x += speed * direction;if ((x > width-radius) || (x < radius)) {direction = -direction; // Flip direction}if (direction == 1) {arc(x, 60, radius, radius, 0.52, 5.76); // Face right} else {arc(x, 60, radius, radius, 3.67, 8.9); // Face left}}

Quando la forma raggiunge un bordo, il codice inverte la direzione della forma cambiando il segno della variabile direction. Ad esempio, se la variabile direction fosse positiva quando la forma raggiunge uno dei bordi, il codice la inverte in negativa.

Interpolazione

A volte potresti voler animare una forma per farla andare da un punto dello schermo ad un altro. Con poche linee di codice, puoi impostare il punto di partenza e la posizione finale, poi calcolare le posizioni che sono nel mezzo (tween) ad ogni frame.

Esempio 7-6: Calcolare le Posizioni di Interpolazione

Per rendere modulare questo esempio di codice, abbiamo creato un gruppo di variabili in cima. Esegui il codice diverse volte e cambiane i valori per vedere come può muovere una forma da una qualsiasi posizione ad un altra ad una serie di velocità:

int startX = 20; // Coordinata x inizialeint stopX = 160; // Coordinata x finaleint startY = 30; // Coordinata y iniziale

int stopY = 80; // Coordinata y finalefloat x = startX; // Coordinata x correntefloat y = startY; // coordinata y correntefloat step = 0.005; // Dimensione di ogni passaggio (0.0 to 1.0)float pct = 0.0; // Percentuale percorsa (0.0 to 1.0)void setup() {size(240, 120);smooth();}void draw() {background(0);if (pct < 1.0) {x = startX + ((stopX-startX) * pct);y = startY + ((stopY-startX) * pct);pct += step;}ellipse(x, y, 20, 20);}

Casualità

A differenza del movimento fluido e lineare comune alla computer graphic, il movimento nel mondo fisico è solitamente idiosincratico. Per fare un esempio, pensa ad una foglia che fluttua fino al suolo, o ad una formica che striscia sul terreno ruvido. Possiamo simulare le imprevedibili caratteristiche del mondo generando numeri casuali. La funzione random( )calcola questi valori; possiamo impostare una gamma per sintonizzare l'ammontare di disordine in un programma.

Esempio 7-7: Generare Valori Casuali

Il breve esempio seguente stampa valori casuali sulla Console, con un intervallo limitato dalla posizione del mouse. La funzione random( ) restituisce sempre un valore decimale, quindi sii sicuro che la variabile sulla parte sinistra dell'operatore di assegnazione (=) è decimale come è quello seguente:

void draw() {float r = random(0, mouseX);println(r);}

Esempio7-8: Disegnare in Modo Casuale

L'esempio seguente è costruito sull'esempio 7-7; usa i valori da random( ) per cambiare la posizione delle linee sullo schermo. Quando il mouse è a sinistra dello schermo, il cambiamento è minimo; come si muove sulla destra, i valori da random( ) crescono ed il movimento diviene più evidente.Poiché la funzione random( ) è all'interno del ciclo for, un nuovo valore casuale viene calcolato per tutti i punti di ogni linea.

void setup() {size(240, 120);smooth();}void draw() {background(204);for (int x = 20; x < width; x += 20) {float mx = mouseX / 10;

float offsetA = random(-mx, mx);float offsetB = random(-mx, mx);line(x + offsetA, 20, x - offsetB, 100);}}

Esempio 7-9: Muovere le Forme in Modo Casuale

Quando c'è bisogno di muovere delle forme sullo schermo, i valori casuali possono generare immagini che sono più naturali nell'aspetto. Nell'esempio seguente, la posizione del cerchio viene modificata da valori casuali in ogni ciclo del draw( ). poiché la funzione background( ) non è usata, rimane traccia delle posizioni precedenti.

float speed = 2.5;int diameter = 20;float x;float y;void setup() {size(240, 120);smooth();x = width/2;y = height/2;}void draw() {x += random(-speed, speed);y += random(-speed, speed);ellipse(x, y, diameter, diameter);}

Se osservi abbastanza a lungo questo esempio, potrai notare che il cerchio lascia la finestra e poi ritorna. Questo è lasciato al caso, ma possiamo aggiungere alcune strutture if o usare la funzione constrain( ) per non lasciare che il cerchio abbandoni lo schermo. La funzione constrain( ) limita un valore ad una gamma predefinita, la quale può essere usata per mantenere la x e la y all'interno dei confini della finestra di visualizzazione. Sostituendo il draw( ) nell'esempio precedente con quello seguente, sarai sicuro che l'ellisse rimarrà all'interno dello schermo.

void draw() {x += random(-speed, speed);y += random(-speed, speed);x = constrain(x, 0, width);y = constrain(y, 0, height);ellipse(x, y, diameter, diameter);}

NOTA: La funzione randomSeed( ) può essere usata per forzare la funzione random( ) a produrre la stessa sequenza di numeri ogni volta che il programma viene eseguito. Questo aspetto è descritto più approfonditamente nelle Reference di Processing.

Contatori

Ogni programma di Processing tiene conto dell'ammontare di tempo che è passato dal momento in cui è stato fatto partire. Viene contato in millisecondi (la millesima parte di un secondo) , così dopo 1 secondo, il contatore si trova a 1000; dopo 5 secondi, è a 5000; e dopo un minuto, è a 60000.Possiamo usare questo contatore per innescare le animazioni in un momento specifico.

La funzione millis( ) riporta il valore del contatore.

Esempio 7-10: Il Tempo Passa

Puoi osservare il tempo passare quando esegui questo programma:

void draw() {int timer = millis();println(timer);}

Esempio 7-11: Innescare Eventi a Tempo

Se abbinati con un blocco if, i valori da millis( ) possono essere utilizzati in sequenze animate ed eventi all'interno di un programma. Per esempio, dopo che due secondi sono trascorsi, il codice all'interno del blocco if può innescare un cambiamento. In questo esempio, le variabili chiamate time1 e time2 determinano quando il valore della variabile x dovrà essere cambiato.

int time1 = 2000;int time2 = 4000;float x = 0;void setup() {size(480, 120);smooth();}void draw() {int currentTime = millis();background(204);if (currentTime > time2) {x -= 0.5;} else if (currentTime > time1) {x += 2;}ellipse(x, 60, 90, 90);}

Circolare

Se sei un asso della trigonometria, già sai quanto siano stupefacenti le funzioni di seno e coseno. Se non lo sei, speriamo che il prossimo esempio farà scattare il tuo interesse. Non vogliamo parlare dettagliatamente di matematica qui, ma mostreremo qualche applicazione per generare un movimento fluido.

La figura 7-2 mostra un'immagine dei valori di un'onda sinusoidale e come si collegano agli angoli. In cima ed in fondo all'onda, c'è da notare come la frequenza di cambiamenti ( il cambiamento nell'asse verticale ) rallenta, si ferma, poi cambia direzione. È questa la qualità della curva che genera un movimento interessante.

Le funzioni sin( ) e cos( ) in Processing riportano un valore tra -1 e 1 per il seno ed il coseno dell'angolo specificato. Come arc( ), gli angoli devono essere dati in radianti (vedi l'Esempio 3-7 e 3-8 per un promemoria di come funzionano i radianti). Per facilità di disegno, i valori decimali riportati da sin( ) e cos( ) sono di solito moltiplicati per raggiungere un valore più grande.

Esempio 7-12: Valori dell'Onda Sinusoidale

Questo esempio mostra come i valori per la funzione sin( ) hanno un ciclo che va da -1 ad 1 quando l'angolo aumenta. Con la funzione map( ), la variabile sinval viene convertita da questo intervallo ai valori da 0 a 255. Questo nuovo valore viene usato per impostare il colore di sfondo della finestra:

float angle = 0.0;void draw() {float sinval = sin(angle);println(sinval);float gray = map(sinval, -1, 1, 0, 255);background(gray);angle += 0.1;}

Esempio 7-13: Movimento dell'Onda Sinusoidale

Questo esempio mostra come questi valori possono essere convertiti in movimento:

float angle = 0.0;float offset = 60;float scalar = 40;float speed = 0.05;void setup() {size(240, 120);smooth();}void draw() {background(0);float y1 = offset + sin(angle) * scalar;float y2 = offset + sin(angle + 0.4) * scalar;float y3 = offset + sin(angle + 0.8) * scalar;ellipse( 80, y1, 40, 40);ellipse(120, y2, 40, 40);ellipse(160, y3, 40, 40);angle += speed;}

Esempio 7-14: Moto Circolare

Quando sin( ) e cos( ) sono usati insieme, possono produrre il moto circolare. I valori del cos( ) forniscono le coordinate x, e i valori di sin( ) le coordinate y. Entrambi vengono moltiplicati da una variabile chiamata scalar per cambiare il raggio del movimento e sommati con un valore di offset per impostare il centro del movimento circolare:

float angle = 0.0;float offset = 60;float scalar = 30;float speed = 0.05;void setup() {size(120, 120);smooth();}void draw() {float x = offset + cos(angle) * scalar;float y = offset + sin(angle) * scalar;ellipse( x, y, 40, 40);angle += speed;}

Esempio 7-15: Spirali

Un leggero cambiamento fatto per aumentare il valore di scalar ad ogni frame produce una spirale, invece che un cerchio:

float angle = 0.0;float offset = 60;float scalar = 2;float speed = 0.05;void setup() {size(120, 120);fill(0);smooth();}void draw() {float x = offset + cos(angle) * scalar;float y = offset + sin(angle) * scalar;ellipse( x, y, 2, 2);angle += speed;scalar += speed;}

Traslare, Ruotare, Scalare

Cambiare le coordinate dello schermo è una tecnica alternativa per creare il movimento.Ad esempio, puoi muovere una forma a destra per 50 pixel, oppure puoi muovere la posizione delle coordinate (0,0) a destra per 50 pixel – il risultato visivo sullo schermo sarà lo stesso.Modificando il sistema predefinito delle coordinate, possiamo creare diverse trasformazioni incluse la traslazione, la rotazione, e il ridimensionamento. La figura 7-3 ne fa una dimostrazione grafica.Lavorare con le trasformazioni può essere complicato, ma la funzione translate( ) è il metodo più lineare, quindi iniziamo con questo. Questa funzione può cambiare il sistema di coordinate a destra, a sinistra, in alto e in basso grazie a questi due parametri.

Esempio 7-16: Traslare la Posizione

In questo esempio, nota che ogni rettangolo è disegnato alle coordinate (0,0), ma vengono spostati in giro per lo schermo, poiché sono condizionati da translate( ):

void setup() {size(120, 120);}void draw() {translate(mouseX, mouseY);rect(0, 0, 30, 30);}

La funzione translate( ) imposta le coordinate (0,0) dello schermo alla posizione del mouse.Nella linea successiva, il rect( ) già disegnato alle nuove coordinate (0,0) è appunto ridisegnato nella posizione del mouse.

Esempio 7-17: Traslazioni Multiple

Dopo che una trasformazione è stata effettuata, questa viene applicata a tutte le funzioni di disegno che seguono. Nota cosa succede quando un secondo comando traslate viene aggiunto per

controllare un secondo rettangolo:

void setup() {size(120, 120);}void draw() {translate(mouseX, mouseY);rect(0, 0, 30, 30);translate(35, 10);rect(0, 0, 15, 15);}

Il rettangolo più piccolo è stato traslato attraverso la somma di mouseX +35 e mouseY +10.

Esempio 7-18: Isolare le Trasformazioni

Per isolare gli effetti di una trasformazione così da non dover influenzare i comandi successivi, usa le funzioni pushMatrix( ) e popMatrix( ). Quando la funzione pushMatrix( ) viene eseguita, salva una copia dell'attuale sistema di coordinate e lo rispristina dopo popMatrix( ):

void setup() {size(120, 120);}void draw() {pushMatrix();translate(mouseX, mouseY);rect(0, 0, 30, 30);popMatrix();translate(35, 10);rect(0, 0, 15, 15);}

In questo esempio, il rettangolo più piccolo è disegnato sempre nell'angolo in alto a sinistra perchè la funzione translate(mouseX,mouseY) viene cancellata da popMatrix( ).

NOTA: Le funzioni pushMatrix( ) e popMatrix( ) vengono sempre usate in coppia. Per ogni pushMatrix( ), hai bisogno di avere un popMatrix( ) corrispondente.

Esempio 7-19: Rotazione

La funzione rotate( ) ruota il sistema di coordinate. Ha un solo parametro, cioè l'angolo (in radianti) da ruotare. Questo ruota sempre relazione a (0,0), che comunemente viene detto “ruotare attorno l'origine”. Per far girare una forma attorno al suo punto centrale, prima di tutto usa translate( ) per muoverlo nella posizione in cui preferisci che sia visualizzata la forma, poi richiama la funzione rotate( ), ed infine disegna la forma con il suo centro in (0,0):

float angle = 0.0;void setup() {size(120, 120);smooth();}void draw() {translate(mouseX, mouseY);rotate(angle);rect(-15, -15, 30, 30);angle += 0.1;}

Esempio 7-20: Combinare Trasformazioni

Quando translate( ) e rotate( ) vengono combinate, l'ordine in cui appaiono influenza il risultato. L'esempio seguente è identico all'Esempio 7-19, eccetto che per translate( ) e rotate( ) che sono invertite. La forma ora ruota attorno l'angolo in alto a sinistra nella finestra di visualizzazione, con la distanza dall'angolo stabilita da translate( ) :

float angle = 0.0;void setup() {size(120, 120);smooth();}void draw() {rotate(angle);translate(mouseX, mouseY);rect(-15, -15, 30, 30);angle += 0.1;}

NOTA: Puoi anche usare le funzioni rectMode( ),ellipseMode( ),imageMode( ), e shapeMode( ) per facilitare il disegno di forme a partire dal loro centro.

Esempio 7-21: Scalare

La funzione scale( ) estende le coordinate sullo schermo. Così come rotate( ), trasforma a partire dall'origine. Pertanto, così come rotate( ), per scalare una forma a partire dal suo centro, opera una traslazione dell'origine alla posizione determinata, ridimensiona la forma e poi disegnala con il centro alle coordinate (0,0):

float angle = 0.0;void setup() {size(120, 120);smooth();}void draw() {translate(mouseX, mouseY);scale(sin(angle) + 2);rect(-15, -15, 30, 30);angle += 0.1;}

Esempio 7-22: Mantenere il Contorno Costante

Dalle linee spesse nell'Esempio 7-21, puoi osservare come la funzione scale( ) condizioni la larghezza del contorno. Per mantenere costante la larghezza del contorno quando una forma viene ridimensionata, dividi la larghezza desiderata del contorno per il valore scalare:

float angle = 0.0;void setup() {size(120, 120);smooth();}void draw() {translate(mouseX, mouseY);float scalar = sin(angle) + 2;

scale(scalar);strokeWeight(1.0 / scalar);rect(-15, -15, 30, 30);angle += 0.1;}

Esempio 7-23: Un Braccio Articolato

In questo più lungo esempio finale riguardante le trasformazioni, abbiamo messo insieme una serie di funzioni rotate( ) e translate( ) per creare un braccio articolato che si piega avanti e indietro. Ogni translate( ) in più muove la posizione delle linee, ed ogni rotate( ) aggiunge alla rotazione precedente per far si che si pieghi ancor di più:

float angle = 0.0;float angleDirection = 1;float speed = 0.005;void setup() {size(120, 120);smooth();}void draw() {background(204);translate(20, 25); // Move to start positionrotate(angle);strokeWeight(12);line(0, 0, 40, 0);translate(40, 0); // Move to next jointrotate(angle * 2.0);strokeWeight(6);line(0, 0, 30, 0);translate(30, 0); // Move to next jointrotate(angle * 2.5);strokeWeight(3);line(0, 0, 20, 0);angle += speed * angleDirection;if ((angle > QUARTER_PI) || (angle < 0)) {angleDirection *= -1;}}

In questo caso, non usiamo un pushMatrix( ) o un popMatrix( ), poiché vogliamo che le trasformazioni si propaghino – così che ogni trasformazione venga costruita sopra l'ultima. Il sistema di coordinate è automaticamente resettato a quello predefinito quando draw( ) fa partire ciascun frame.

Robot 5: Movimento

In questo esempio, le tecniche per il movimento casuale e circolare vengono applicate al robot.Il background( ) viene eliminato per far si che sia più facile vedere come cambiano la posizione ed il corpo del robot.

Ad ogni frame, un numero casuale tra -4 e 4 è aggiunto alla coordinata x, ed un numero casuale tra -1 e 1 è aggiunto alla coordinata y. Questo causerà un movimento del robot maggiormente direzionato da sinistra a destra che da sopra a sotto. I numeri calcolati dalla funzione sin( ) modificano l'altezza del collo così da farlo oscillare tra un'altezza di 50 e 110 pixel:

float x = 180; // Coordinata-xfloat y = 400; // Coordinata-yfloat bodyHeight = 153; // Altezza del corpofloat neckHeight = 56; // Altezza del collofloat radius = 45; // Raggio della testafloat angle = 0.0; // Angolo per il movimentovoid setup() {size(360, 480);smooth();ellipseMode(RADIUS);background(204);}void draw() {// Cambia posizione tramite un piccolo numero casualex += random(-4, 4);y += random(-1, 1);// Cambia altezza del colloneckHeight = 80 + sin(angle) * 30;angle += 0.05;// Regola l'altezza della testafloat ny = y - bodyHeight - neckHeight - radius;// Collostroke(102);line(x+2, y-bodyHeight, x+2, ny);line(x+12, y-bodyHeight, x+12, ny);line(x+22, y-bodyHeight, x+22, ny);// Antenneline(x+12, ny, x-18, ny-43);line(x+12, ny, x+42, ny-99);line(x+12, ny, x+78, ny+15);// CorponoStroke();fill(102);ellipse(x, y-33, 33, 33);fill(0);rect(x-45, y-bodyHeight, 90, bodyHeight-33);fill(102);rect(x-45, y-bodyHeight+17, 90, 6);// Testafill(0);ellipse(x+12, ny, radius, radius);fill(255);ellipse(x+24, ny-6, 14, 14);fill(0);ellipse(x+24, ny-6, 3, 3);}

8/FunzioniLe funzioni sono i blocchi di costruzione di base per i programmi di Processing. Sono apparse in ogni dimostrazione che abbiamo presentato. Per esempio, abbiamo usato frequentemente la funzione size( ), la funzione line( ), e la funzione fill( ). Questo capitolo mostra come scrivere nuove funzioni per estendere le capacità di Processing oltre le sue funzionalità integrate.La forza delle funzioni è la modularità. Le funzioni sono unità di software indipendente che vengono usate per costruire programmi più complessi – come i mattoncini LEGO, dove ogni tipo di mattoncino ha un compito preciso, e costruire un modello complesso richiede l'utilizzo di parti differenti combinate assieme. Così come nelle funzioni, il vero potere di questi mattoni è l'abilità di costruire molte forme differenti dalla stessa serie di elementi. Lo stesso gruppo di LEGO che forma un'astronave può essere riutilizzata per costruire un camion, un grattacielo, e molti altri oggetti.

Le funzioni sono utili se vuoi disegnare una forma complessa come un albero più e più volte.La funzione per disegnare un albero dovrebbe esser fatta da comandi integrati di Processing, come line( ), che creano la forma. Dopo aver scritto il codice per costruire l'albero, non hai più bisogno di pensare di nuovo ai dettagli per disegnare l'albero – puoi semplicemente scrivere albero( ) (o qualsiasi nome tu abbia usato per la funzione) per disegnare la forma. Le funzioni consentono di poter astrarre una sequenza complessa di dichiarazioni, così da poter concentrarsi sull'obiettivo di livello più alto ( come disegnare un albero ), e non sui dettagli delle implementazioni ( il comando line( ) che definisce la forma). Una volta che una funzione è stata definita, il codice all'interno della funzione non ha bisogno di essere ripetuto di nuovo.

Funzioni di Base

Un computer esegue un programma una riga alla volta. Quando una funzione viene eseguita, il computer salta direttamente dove la funzione viene definita ed esegue il codice che vi si trova, poi torna indietro dove si era interrotto.

Esempio 8-1: Tirare i Dadi

Questo funzionamento è illustrato con la funzione rollDice( ) scritta per questo esempio. Quando un programma parte, esegue il codice in setup( ) e si ferma. Il programma prende una deviazione ed

esegue il codice all'interno di rollDice( ) ogni volta che appare:

void setup() {println("Ready to roll!");rollDice(20);rollDice(20);rollDice(6);println("Finished.");}void rollDice(int numSides) {int d = 1 + int(random(numSides));println("Rolling... " + d);}

Le due righe di codice in rollDice( ) selezionano un numero casuale tra 1 ed il numero di facce del dado, e stampa questo numero sulla Console. Poiché il numero è casuale, vedrai numeri differenti ogni volta che il programma viene eseguito:

Ready to roll!Rolling... 20Rolling... 11Rolling... 1Finished.

Ogni volta che la funzione rollDice( ) viene eseguita all'interno del setup( ), il codice nella funzione viene eseguito da cima a fondo, poi il programma continua sulla linea successiva nel setup( ).

La funzione random( ) (descritta a pagina 97) riporta un numero che va da 0 al numero specificato (ma senza includerlo) . Così random(6) riporta un numero tra 0 e 5.99999.... Siccome random( ) restituisce un valore decimale, usiamo anche int( ) per convertirlo in un valore intero. Così int(random(6)) restituirà 0,1,2,3,4 o 5. Poi aggiungiamo 1 così che il numero riportato vada da 1 a 6 (come un dado). Come in molti altri casi in questo libro, partire il conteggio da 0 rende più facile l'utilizzo del risultato di random( ) con altri calcoli.

Esempio 8-2: Un Altro Modo per Tirare i Dadi

Se un programma equivalente fosse scritto senza la funzione rollDice( ), potrebbe apparire in questo modo:

void setup() {println("Ready to roll!");int d1 = 1 + int(random(20));println("Rolling... " + d1);int d2 = 1 + int(random(20));println("Rolling... " + d2);int d3 = 1 + int(random(6));println("Rolling... " + d3);println("Finished.");}

La funzione rollDice( ) nell'Esempio 8-1 rende il codice più semplice da leggere e conservare. Il programma appare più chiaro, perchè il nome della funzione afferma con chiarezza la sua funzione. In questo esempio, vediamo la funzione random( ) in setup( ), ma la sua utilità non è così ovvia. Il numero delle facce del dado è chiarito con una funzione: quando il codice dice rollDice(6), è ovvio che sta simulando il lancio di un dado a sei facce. Inoltre, l'Esempio 8-1 è più facile da conservare,

poiché le informazioni non sono ripetute. La fase di rolling... viene ripetuta tre volte. Se desideri cambiare questo testo in un altro, hai bisogno di aggiornare il programma in tre parti,invece di fare una singola correzione all'interno della funzione rollDice( ). In aggiunta, come hai visto nell'Esempio 8-5, una funzione può anche rendere un programma più corto (e quindi più facile da mantenere e leggere), che aiuta a ridurre il potenziale numero di bug.

Creare una Funzione

In questa sezione, disegneremo un gufo per esporre i passi coinvolti nella creazione di una funzione.

Esempio 8-3: Disegnare un Gufo

Per prima cosa disegniamo il gufo senza usare una funzione:

void setup() {size(480, 120);smooth();}void draw() {background(204);translate(110, 110);stroke(0);strokeWeight(70);line(0, -35, 0, -65); // BodynoStroke();fill(255);ellipse(-17.5, -65, 35, 35); // Left eye domeellipse(17.5, -65, 35, 35); // Right eye domearc(0, -65, 70, 70, 0, PI); // Chinfill(0);ellipse(-14, -65, 8, 8); // Left eyeellipse(14, -65, 8, 8); // Right eyequad(0, -58, 4, -51, 0, -44, -4, -51); // Beak}

Nota che translate( ) viene usato per spostare l'origine (0,0) per 110 pixel a destra e 110 pixel verso il basso. Poi il gufo viene disegnato relativamente a (0,0), con le sue coordinate a volte positive e a volte negative,come se fosse centrato sul nuovo punto (0,0). Vedi la Figura 8-1.

Esempio 8-4: In due si è in compagnia

Il codice presentato nell'Esempio 8-3 è ragionevole se c'è solamente un gufo, ma quando ne disegnamo un secondo, la lunghezza del codice viene quasi duplicata:

void setup() {size(480, 120);smooth();}void draw() {background(204);// Left owltranslate(110, 110);stroke(0);strokeWeight(70);line(0, -35, 0, -65); // CorponoStroke();

fill(255);ellipse(-17.5, -65, 35, 35); // Cupola dell'occhio sinistroellipse(17.5, -65, 35, 35); // Cupola dell'occhio destroarc(0, -65, 70, 70, 0, PI); // Mentofill(0);ellipse(-14, -65, 8, 8); // Occhio sinistroellipse(14, -65, 8, 8); // Occhio destroquad(0, -58, 4, -51, 0, -44, -4, -51); // Becco// Gufo di destratranslate(70, 0);stroke(0);strokeWeight(70);line(0, -35, 0, -65); // CorponoStroke();fill(255);ellipse(-17.5, -65, 35, 35); // Cupola dell'occhio sinistroellipse(17.5, -65, 35, 35); // Cupola dell'occhio destroarc(0, -65, 70, 70, 0, PI); // Mentofill(0);ellipse(-14, -65, 8, 8); // Occhio sinistroellipse(14, -65, 8, 8); // Occhio destroquad(0, -58, 4, -51, 0, -44, -4, -51); // Becco}

Il programma è cresciuto da 21 righe a 34 righe, poiché il codice servito per disegnare il primo gufo è stato tagliato ed incollato nel programma ed un translate( ) è stato inserito per muoverlo di 70 pixel a destra. Questo è un metodo noioso ed inefficiente per disegnare un secondo gufo, senza menzionare il mal di testa causato dall'aggiungere un terzo gufo con questo metodo. Ma duplicare il codice non è necessario, poiché questo è il tipo di situazione in cui una funzione può venirci in aiuto.

Esempio 8-5: Una Funzione Gufo

In questo esempio, una funzione viene introdotta per disegnare due gufi con lo stesso codice. Se creiamo il codice che disegna il gufo sullo schermo in una nuova funzione, il codice ha bisogno solo di apparire una volta nel programma:

void setup() {size(480, 120);smooth();}void draw() {background(204);owl(110, 110);owl(180, 110);}void owl(int x, int y) {pushMatrix();translate(x, y);stroke(0);strokeWeight(70);line(0, -35, 0, -65); // CorponoStroke();fill(255);ellipse(-17.5, -65, 35, 35); // Cupola dell'occhio sinistroellipse(17.5, -65, 35, 35); // Cupola dell'occhio destroarc(0, -65, 70, 70, 0, PI); // Mentofill(0);

ellipse(-14, -65, 8, 8); // Occhio sinistroellipse(14, -65, 8, 8); // Occhio destroquad(0, -58, 4, -51, 0, -44, -4, -51); // BeccopopMatrix();}

Puoi osservare dall'illustrazione che questo esempio e l'Esempio 8-4 hanno lo stesso risultato, ma questo esempio è più breve, poiché il codice per disegnare il gufo appare solamente una volta, all'interno della funzione nominata appropriatamente owl( ). Questo codice viene eseguito due volte, perchè è richiamato per due volte all'interno di draw( ). Il gufo è disegnato in due posizioni differenti a causa dei parametri all'interno della funzione che imposta le coordinate x ed y.I parametri sono una parte importante delle funzioni, perchè garantiscono flessibilità. Abbiamo visto un'altro esempio nella funzione rollDice( ); il singolo parametro nominato numSides rende possibile la simulazione di un dado a sei facce, a 20 facce, a di un dado con un qualsiasi numero di facce. Questo è proprio come molte altre funzioni di Processing. Per esempio,i parametri nella funzione line( ) rendono possibile disegnare una linea da un qualsiasi pixel dello schermo ad un altro pixel.Senza i parametri, la funzione sarebbe stata abilitata a disegnare una linea solo da un punto fisso ad un altro.

Ogni parametro possiede un data type (come int o float ) , poiché ciascun parametro è una variabile che viene creata ogni volta che la funzione viene eseguita. Quando questo esempio viene eseguito, la prima volta che la funzione gufo viene richiamata, il valore del parametro x 110, ed y anche è 110. Nel secondo uso della funzione, il valore di x è 180 ed y è di nuovo 110. Ogni valore che passa attraverso la funzione e poi ovunque appare il nome della variabile all'interno della funzione, viene rimpiazzato con il valore in entrata.

Assicurati che i valori che passano all'interno di una funzione corrispondano ai data types dei parametri. Come dimostrazione, se la riga seguente apparisse all'interno di setup( ) nell'Esempio 8-5:

owl(110.5, 120.2);

Questo causerebbe un errore, poiché il data type per i parametri x e y è int, ed i valori 110,5 e 120,2 sono valori decimali.

Esempio 8-6: Accrescere la Popolazione

Ora che abbiamo una funzione di base per disegnare il gufo ad una qualsiasi posizione, possiamo disegnare molti gufi in modo efficiente posizionando la funzione all'interno di un ciclo for e cambiando il primo parametro ad ogni ciclo.

void setup() {size(480, 120);smooth();}void draw() {background(204);for (int x = 35; x < width + 70; x += 70) {owl(x, 110);}}// Inserisci la funzione owl() Dall'Esempio 8-5

é possibile aggiungere più e più parametri alla funzione per cambiare differenti aspetti di come il gufo sarà disegnato. I valori potrebbero essere inseriti per cambiare il colore del gufo, la rotazione,

la dimensione, o il diametro dei suoi occhi.

Esempio 8-7: Gufi di Dimensioni Differenti

In questo esempio, abbiamo aggiunto due parametri per cambiare il valore di grigio e la dimensione di ciascun gufo:

void setup() {size(480, 120);smooth();}void draw() {background(204);randomSeed(0);for (int i = 35; i < width + 40; i += 40) {int gray = int(random(0, 102));float scalar = random(0.25, 1.0);owl(i, 110, gray, scalar);}}void owl(int x, int y, int g, float s) {pushMatrix();translate(x, y);scale(s); // Imposta la dimensionestroke(g); // Imposta il valore di grigiostrokeWeight(70);line(0, -35, 0, -65); // CorponoStroke();fill(255-g);ellipse(-17.5, -65, 35, 35); // Cupola dell'occhi sinistroellipse(17.5, -65, 35, 35); // Cupola dell'occhio destroarc(0, -65, 70, 70, 0, PI); // Mentofill(g);ellipse(-14, -65, 8, 8); // Occhio sinistroellipse(14, -65, 8, 8); // Occhio destroquad(0, -58, 4, -51, 0, -44, -4, -51); // BeccopopMatrix();}

Restituire Valori

Le funzioni possono operare un calcolo e poi riportare un valore al programma principale. Abbiamo già utilizzato delle funzioni di questo tipo, incluse random( ) e sin( ). Nota che quando appaiono questo tipo di funzioni, il valore di ritorno è di solito assegnato ad una variabile:

float r = random(1, 10);

In questo caso, random( ) riporta un valore tra 1 e 10, che viene poi assegnato alla variabile r.

Una funzione che riporta un valore è inoltre frequentemente usata come parametro per un'altra funzione. Ad esempio:

point( random(width), random(height));

In questo caso, i valori da random( ) non sono assegnati ad una variabile – sono passati come parametri per point( ) ed usati per posizionare il punto all'interno della finestra.

Esempio 8-8: Restituire un Valore

Per creare una funzione che renda un valore, sostituisci la parola chiave void con il genere di dati che vuoi che la funzione riporti. Nella tua funzione, specifica i dati che devono essere segnalati con la parola chiave return. Per fare una prova, questo esempio include una funzione chiamata calculateMars( ) che calcola il peso di una persona o di un oggetto sul nostro pianeta vicino:

void setup() {float yourWeight = 132;float marsWeight = calculateMars(yourWeight);println(marsWeight);}float calculateMars(float w) {float newWeight = w * 0.38;return newWeight;}

Da notare che il tipo di dati float situato prima del nome della funzione per mostrare che riporta un valore decimale, e l'ultima riga del blocco, che riporta la variabile newWeight. Nella seconda linea di setup( ), questo valore viene assegnato alla variabile marsWeight. (Per controllare il tuo peso su Marte, scambia il valore della variabile yourWeight con il tuo peso.)

Robot 6: Funzioni

In contrasto con Robot 2 (vedi “Robot 2: Variabili” nel capitolo 4), questo esempio utilizza una funzione per disegnare quattro variazioni di robot all'interno dello stesso programma. Siccome la funzione drawRobot( ) appare quattro volte nel draw( ), il codice nel blocco drawRobot( ) viene eseguito quattro volte, ogni volta con un diverso gruppo di parametri per cambiare la posizione e l'altezza del corpo del robot.

Nota il modo in cui è stato isolato il posto in cui si trovavano le variabili globali in Robot 2 all'interno della funzione drawRobot( ). poiché queste variabili sono applicate solo per disegnare il robot, si trovano all'interno delle parentesi graffe che definiscono il blocco della funzione drawRobot( ). Siccome il valore della variabile radius non viene cambiato, non c'è bisogno che esso diventi un parametro. È invece definito all'inizio di drawRobot( ):

void setup() {size(720, 480);smooth();strokeWeight(2);ellipseMode(RADIUS);}void draw() {background(204);drawRobot(120, 420, 110, 140);drawRobot(270, 460, 260, 95);drawRobot(420, 310, 80, 10);drawRobot(570, 390, 180, 40);}

void drawRobot(int x, int y, int bodyHeight, int neckHeight) {int radius = 45;int ny = y - bodyHeight - neckHeight - radius;

// Collostroke(102);line(x+2, y-bodyHeight, x+2, ny);line(x+12, y-bodyHeight, x+12, ny);line(x+22, y-bodyHeight, x+22, ny);

// Antenneline(x+12, ny, x-18, ny-43);line(x+12, ny, x+42, ny-99);line(x+12, ny, x+78, ny+15);

// CorponoStroke();fill(102);ellipse(x, y-33, 33, 33);fill(0);rect(x-45, y-bodyHeight, 90, bodyHeight-33);fill(102);rect(x-45, y-bodyHeight+17, 90, 6);

// Testafill(0);ellipse(x+12, ny, radius, radius);fill(255);

ellipse(x+24, ny-6, 14, 14);fill(0);ellipse(x+24, ny-6, 3, 3);fill(153);ellipse(x, ny-8, 5, 5);ellipse(x+30, ny-26, 4, 4);ellipse(x+41, ny+6, 3, 3);}

9/OggettiLa programmazione ad oggetti (Object-oriented programming, OOP) è un modo differente di pensare i tuoi programmi. Sebbene il termine “object-oriented programming” può suonare intimidatorio, c'è una buona notizia: stai lavorando con gli oggetti fin dal Capitolo 6, quando hai iniziato ad usare PImage, PFont, String, e PShape. A differenza dei generi di dati primitivi come boolean, int, e float, che possono conservare solo un valore, un oggetto ne può immagazzinare diversi. Ma questa è solamente una parte della storia. Gli oggetti sono anche un modo di raggruppare variabili con le relative funzioni. Siccome già conosci il modo di lavorare con le variabili e con le funzioni, gli oggetti semplicemente combinano tutto ciò che hai già imparato in un pacchetto più comprensibile.Gli oggetti sono importanti, perchè spezzettano le idee in piccoli blocchi di costruzione. Questo riflette il mondo naturale dove, per esempio, gli organi sono fatti di tessuto, il tessuto è fatto di cellule, e così via. Similmente, come il tuo codice diventa più complesso, devi cominciare a pensare in termini di piccole strutture che ne formano altre più complicate. È più semplice scrivere e conservare piccoli e comprensibili pezzi di codice che lavorano assieme piuttosto che scrivere una grande parte di codice che fa tutto quanto in una volta.

Un oggetto software è una collezione di variabili e funzioni messe in relazione. Nel contesto degli oggetti, una variabile è chiamata campo, field ( o variabile istanza) ed una funzione è chiamata metodo, method. Campi e metodi lavorano proprio come le variabili e le funzioni spiegate nei capitoli precedenti, ma useremo i nuovi termini per enfatizzare il fatto che esse sono parti di un oggetto. Per dirlo in un altro modo, un oggetto combina i dati correlati (fields) con le azioni ed i comportamenti correlati (metodi). L'idea è di raggruppare insieme i relativi dati con i relativi metodi che agiscono su quei dati.

Per esempio, per creare un modello di una radio, pensa ai parametri che possono essere regolati ed alle azioni che possono condizionare questi parametri:

Campi: volume, frequenza, banda (FM,AM), energia (on,off)Metodi: regolaVolume, regolaFrequenza, regolaBanda

Creare il modello di un semplice dispositivo meccanico è semplice se paragonato al creare il

modello di un organismo come una formica od una persona. Non è possibile ridurre questi organismi complessi ad alcuni campi e metodi, ma è possibile creare un modello che sia abbastanza per dare una simulazione interessante. Il videogame The Sims ne è un chiaro esempio. Questo gioco funziona gestendo le attività giornaliere di persone simulate. I personaggi hanno abbastanza personalità per fare un videogame giocabile e accattivante, ma niente di più. Infatti, questi hanno solamente cinque attributi di personalità: acuto, espansivo, energico, scherzoso, e bello. Con la conoscenza che è possibile creare un modello altamente semplificato di organismi complessi, possiamo iniziare a programmare una formica con solamente pochi campi e metodi:

Campi: tipo (operaio,soldato), peso, lunghezzaMetodi: cammina, pizzica, rilasciaFeromoni, mangia

Se fai una lista dei campi e metodi di una formica, si potrebbe scegliere se concentrarsi su differenti aspetti del modello della formica. Non c'è un modo giusto per creare un modello, sei tu che scegli il metodo più appropriato per il proposito dell'obiettivo del tuo programma.

Classi ed Oggetti

Prima di poter creare un oggetto, devi definire una classe. Una classe è la specificazione per un oggetto. Per usare un'analogia architettonica, una classe è come il progetto di una casa, e l'oggetto è la casa in se stessa. Ogni casa fatta a partire dal progetto può avere variazioni, ed il progetto è solamente la specificazione, non la struttura costruita. Ad esempio, una casa può essere rossa ed un'altra verde; una casa potrebbe avere il caminetto ed un'altra no. Proprio come con gli oggetti, la classe definisce il genere di dati ed i comportamenti, ma ogni oggetto (casa) costruito da una singola classe (progetto) ha delle variabili (colore,caminetto) che sono inpostati in valori differenti.Per usare un termine più tecnico, ogni oggetto è un'istanza di una classe ed ogni istanza ha il proprio gruppo di campi e metodi.

Definire una Classe

Prima che tu cominci a scrivere una classe, raccomandiamo una piccola pianificazione. Pensa ai campi ed ai metodi che la tua classe dovrebbe avere. Fai un piccolo brainstorming per immaginare tutte le opzioni possibili e poi fai delle priorità e cerca la tua ipotesi migliore su quello che potrà funzionare. Farai cambiamenti durante il processo di programmazione, ma è importante avere un buon punto di partenza.

Per i tuoi campi, seleziona nomi chiari e decidi i tipi di dati per ognuno. I campi all'interno di una classe possono essere di ogni tipologia di dati. Una classe può nello stesso tempo contenere diverse booleane, valori decimali, immagini, stringhe, e così via. Tieni a mente che una ragione di creare una classe è di raggruppare insieme elementi di dati correlati. Per i tuoi metodi, seleziona nomi altrettanto chiari e decidi i valori da restituire (se c'è n'è bisogno). I metodi sono usati per cambiare i valori dei campi e per svolgere azioni basate sui valori dei campi.

Per la tua prima classe, convertiremo l'Esempio 7-9 precedentemente mostrato in questo libro. Partiremo facendo una lista dei campi da questo esempio:

float xfloat yint diameterfloat speed

Il prossimo passo sarà quello di capire quali metodi potrebbero essere utili per la classe.Guardando all'interno della funzione draw( ) dall'esempio che stiamo adattando, vediamo due componenti primarie. La posizione della forma è aggiornata e disegnata sullo schermo. Creiamo due metodi per la nostra classe, uno per ogni compito:

void move()void display()

Nessuno di questi metodi riporta un valore, così entrambi hanno il tipo di valore di ritorno come void. La prossima volta che scriveremo la classe basandosi sulla lista di campi e metodi, seguiremo quattro passaggi:

1. Creare il blocco.2. Aggiungere i campi.3. Scrivere un constructor (sarà spiegato a breve) per assegnare i valori ai campi.4. Aggiungere i metodi.

Prima di tutto, creiamo un blocco:

class jitterBug {

}

Nota che la parola chiave class è in minuscolo ed il nome jitterBug è in maiuscolo. Nominare le classi con lettera maiuscola non è richiesto, ma è una convenzione ( che noi incoraggiamo fortemente) usata per denotare che si tratta di una classe. ( La parola chiave class, d'altronde, dev'essere minuscola perchè è una regola del linguaggio di programmazione.)

Secondo, aggiungiamo i campi. Quando lo facciamo, dobbiamo decidere quali campi avranno i loro valori assegnati attraverso un constructor, un metodo speciale usato per questo scopo. In linea di massima, i valori dei campi che tu desideri siano diversi per ogni classe vengono passati attraverso il constructor, e gli altri valori dei campi possono essere definiti quando vengono dichiarati. Per la classe jitterBug, abbiamo deciso che i valori per x, y e diameter saranno inseriti nel constructor.Quindi i campi sono dichiarati come segue:

class JitterBug {float x;float y;int diameter;float speed = 0.5;}

Terzo, aggiungiamo il costruttore. Il constructor ha sempre lo stesso nome della classe. L'obiettivo del costruttore è di assegnare i valori iniziali ai campi quando un oggetto (l'istanza di una classe) viene creato (Figura 9-1). Il codice all'interno del blocco del costruttore viene eseguito una volta quando un oggetto è inizialmente creato. Come abbiamo detto prima, quando l'oggetto viene inizializzato, immettiamo tre parametri nel costruttore. Ognuno di questi valori è assegnato ad una variabile temporanea che esiste solo mentre il codice all'interno del costruttore viene eseguito.Per chiarire, abbiamo aggiunto il nome temp ad ognuna di queste variabili, ma possono essere nominate con qualunque termine tu preferisca. Questi sono usati solamente per assegnare i valori ai campi che sono parte della classe. Inoltre nota che il costruttore non riporta mai un valore e pertanto non ha void qualunque altro genere di dati posto prima. Dopo aver aggiunto il costruttore, la classe

avrà quest'aspetto:

class JitterBug {float x;float y;int diameter;float speed = 0.5;JitterBug(float tempX, float tempY, int tempDiameter) {x = tempX;y = tempY;diameter = tempDiameter;}}

Nell'ultimo passaggio si tratta di aggiungere i metodi. Questa parte è lineare; è proprio come scrivere delle funzioni, ma qui sono contenute all'interno di una classe. Inoltre, nota la spaziatura del codice. Ogni riga all'interno della classe ha un'indentazione di alcuni spazi per mostrare che si trova all'interno del blocco. All'interno del constructor e dei metodi, il codice è spaziato di nuovo per mostrare chiaramente la gerarchia:

class JitterBug {

float x; float y; int diameter; float speed = 2.5;

JitterBug(float tempX, float tempY, int tempDiameter) { x = tempX; y = tempY; diameter = tempDiameter; }

void move() { x += random(-speed, speed); y += random(-speed, speed); }

void display() { ellipse(x, y, diameter, diameter); }

}

Esempio 9-1: Costruire un Oggetto

Ora che hai definito una classe, per usarla in un programma devi definire un oggetto da questa classe. Ci sono due passaggi per creare un oggetto:

1. Dichiara la variabile oggetto.2. Crea (inizializza) l'oggetto con la parola chiave new.

Partiremo dal mostrare come questo funzioni all'interno dello sketch di Processing e poi continueremo con lo spiegare ogni parte nel dettaglio:

JitterBug bug; // Dichiara l'oggettovoid setup() {size(480, 120);

smooth();// Crea un oggetto ed inserisci i parametribug = new JitterBug(width/2, height/2, 20);}void draw() {bug.move();bug.display();}// Inserisci qui una copia della classe JitterBug

Ogni classe è una tipologia di dati ed ogni oggetto è una variabile. Dichiariamo le variabili oggetto in modo simile alle variabili con tipi di dati primitivi come boolean, int, e float. L'oggetto viene dichiarato affermando il genere di dati seguito da un nome per la variabile:

JitterBug bug;

Il secondo passo si inizializza l'oggetto con la parola chiave new. Questo crea spazio per l'oggetto in memoria e crea i campi. Il nome del constructora destra della parola chiave new, seguita dai parametri all'interno del constructor, se ce ne sono:

JitterBug bug = new JitterBug ( 200.0, 250.0, 30);

I tre numeri all'interno delle parentesi sono i parametri che vengono inseriti all'interno del constructor della classe JitterBug. Il numero di questi parametri e la loro tipologia di dati devono corrispondere a quelli del constructor.

Esempio 9-2: Creare Oggetti Multipli

Nell' Esempio 9-1, osserviamo qualcosa di nuovo: il punto che viene utilizzato per accedere ai metodi dell'oggetto all'interno di draw( ) . Il punto è usato per unire il nome dell'oggetto con i suoi campi e metodi. Ciò diventa chiaro in questo esempio, dove due oggetti sono costruiti a partire dalla stessa classe. Il comando jit.move( ) si riferisce al metodo move( ) che appartiene all'oggetto chiamato jit, e bug.move( ) si riferisce al metodo move( ) che appartiene all'oggetto chiamato bug:

JitterBug jit;JitterBug bug;void setup() {size(480, 120);smooth();jit = new JitterBug(width * 0.33, height/2, 50);bug = new JitterBug(width * 0.66, height/2, 10);}void draw() {jit.move();jit.display();bug.move();bug.display();}// Inserisci qui una copia della classe JitterBug

Ora che la classe esiste come proprio modulo di codice, ogni cambiamento modificherà l'oggetto da cui è stato fatto. Per esempio, potresti aggiungere un campo alla classe JitterBug che controlla il colore, oppure un'altra che determina la sua dimensione. Questi valori possono essere approvati usando un constructor oppure assegnati utilizzando metodi addizionali, come setColor( ) o

setSize( ). E siccome si tratta di un'unità autonoma, puoi anche utilizzare la classe JitterBug in un altro sketch.

Ora è un buon momento per conoscere la funzione delle schede nell'ambiente di Processing (Figura 9-2). Le schede ti permettono di distribuire il tuo codice in più di un file. Questo rende un codice più lungo più facile da curare ed in generale più maneggevole. Di solito viene creata una nuova scheda per ciascuna classe, la quale rinforza la modularità del lavoro con le classi e rende il codice più semplice da reperire.

Per creare una nuova scheda, clicca sulla freccia nella parte destra della barra delle schede. Quando selezioni New Tab dal menu, ti verrà richiesto di dare un nome alla scheda nella finestra di avviso. Utilizzando questa tecnica, modifica il codice di questo esempio per provare a fare una nuova scheda per la classe JitterBug.

NOTA: Ogni scheda si presenta come file .pde separato all'interno della cartella dello sketch.

Robot 7: Oggetti

Un software oggetto combina metodi (funzioni) e campi (variabili) in un'unità. La classe Robot in questo esempio definisce tutti gli oggetti robot che verranno creati da essa. Ogni oggetto Robot ha la propria serie di campi per memorizzare una posizione e la figura che verrà disegnata sullo schermo. Ognuno ha dei metodi per aggiornare la posizione e visualizzare la figura.

I parametri per bot1 e bot2 in setup( ) definiscono le coordinate x e y ed il file .svg che verrà usato per rappresentare il robot. I parametri tempX e tempY vengono esaminati dal constructor e assegnati ai campi xpos e ypos. Il parametro svgName viene utilizzato per caricare la relativa immagine. Gli oggetti (bot1 e bot2) disegnano ognuno nella propria posizione e con una figura differente perchè ognuno possiede dei valori unici analizzate dai constructor:

Robot bot1;Robot bot2;void setup() {size(720, 480);bot1 = new Robot("robot1.svg", 90, 80);bot2 = new Robot("robot2.svg", 440, 30);smooth();}void draw() {background(204);// Aggiorna e visualizza il primo robotbot1.update();bot1.display();// Aggiorna e visualizza il secondo robotbot2.update();bot2.display();}class Robot {float xpos;float ypos;float angle;PShape botShape;float yoffset = 0.0;// Imposta i valori iniziali nel constructorRobot(String svgName, float tempX, float tempY) {botShape = loadShape(svgName);xpos = tempX;ypos = tempY;angle = random(0, TWO_PI);}// Aggiorna i campivoid update() {angle += 0.05;yoffset = sin(angle) * 20;}// Disegna il robot sullo schermovoid display() {shape(botShape, xpos, ypos + yoffset);}}

10/ ArrayAbbiamo introdotto nuove idee riguardo la programmazione in ogni capitolo (variabili, funzioni, oggetti) ed ora arriviamo all'ultimo passaggio – gli array! Un array è una lista di variabili che condividono un nome comune. Gli array sono utili perchè rendono possibile lavorare con molte variabili senza bisogno di creare un nuovo nome per ciascuna di esse. Questo rende il codice più breve, facile da leggere, e più comodo da aggiornare.

Esempio 10-1: Molte Variabili

Per capire quello che vogliamo dire, facciamo riferimento all' Esempio 7-3. Questo codice funziona bene se ci stiamo muovendo con solamente una forma, ma cosa succede se vogliamo averne 2? Abbiamo bisogno di creare una nuova variabile x ed aggiornarla nel draw( ):

float x1 = -20;float x2 = 20;void setup() {size(240, 120);smooth();noStroke();}void draw() {background(0);x1 += 0.5;x2 += 0.5;arc(x1, 30, 40, 40, 0.52, 5.76);arc(x2, 90, 40, 40, 0.52, 5.76);}

Esempio 10-2: Troppe Variabili

Il codice dell'esempio precedente è ancora maneggevole, ma cosa succede se vogliamo avere cinque cerchi? Abbiamo bisogno di aggiungere ancora tre variabili alle due che già avevamo:

float x1 = -10;

float x2 = 10;float x3 = 35;float x4 = 18;float x5 = 30;void setup() {size(240, 120);smooth();noStroke();}void draw() {background(0);x1 += 0.5;x2 += 0.5;x3 += 0.5;x4 += 0.5;x5 += 0.5;arc(x1, 20, 20, 20, 0.52, 5.76);arc(x2, 40, 20, 20, 0.52, 5.76);arc(x3, 60, 20, 20, 0.52, 5.76);arc(x4, 80, 20, 20, 0.52, 5.76);arc(x5, 100, 20, 20, 0.52, 5.76);}

Il codice comincia ad essere fuori controllo.

Esempio 10-3: Array, non Variabili

Immagina cosa potrebbe succedere se volessi avere 3,000 cerchi. Questo vorrebbe dire creare 3,000 singole variabili, poi aggiornarne ognuna separatamente. Potresti tenere sotto controllo così tante variabili? Davvero vorresti? Usiamo invece un array:

float[] x = new float[3000];void setup() {size(240, 120);smooth();noStroke();fill(255, 200);for (int i = 0; i < x.length; i++) {x[i] = random(-1000, 200);}}void draw() {background(0);for (int i = 0; i < x.length; i++) {x[i] += 0.5;float y = i * 0.4;arc(x[i], y, 12, 12, 0.52, 5.76);}}

Spenderemo il resto di questo capitolo parlando dei dettagli che rendono possibile questo esempio.

Creare un Array

Ogni voce dell'array è chiamato elemento, ed ognuno ha un valore di indice (index) per contrassegnare la sua posizione all'interno dell'array. Proprio come le coordinate sullo schermo, i valori di indice per un array partono il conteggio da 0. Per esempio, il primo elemento in un array ha il valore di index a 0, il secondo elemento ha il valore di index a 1, e così via. Se ci sono 20

valori nell'array, il valore di index dell'ultimo elemento sarà 19. La Figura 10-1 mostra la struttura concettuale di un array.

Usare gli array somiglia al lavorare con le singole variabili; segue lo stesso schema. Come sai, puoi creare una singola variabile con un numero intero chiamata x con questo codice:

int x;

Per creare un array, devi solo aggiungere delle parentesi dopo il tipo di dati:

int[] x;

Il bello di creare un array è l'abilità di fare 2, 10, o 100.000 valori di variabile solamente con una linea di codice. Ad esempio, la riga seguente crea un array di 2.000 variabili intere:

int[] x = new int[2000];

Puoi creare array con tutti i generi di dati di Processing: boolean, float, string, PShape, e così via, così come qualsiasi classe definita dall'utente. Per esempio, il codice seguente crea un array di 32 variabili PImage:

PImage[] images = new PImage[32];

Per creare un array inizia con il nome del tipo di dati, seguito dalle parentesi. Il nome che hai selezionato per l'array va subito dopo, seguito dall'operatore di assegnazione (il simbolo uguale), seguito dalla parola chiave new, seguito ancora dal nome del tipo di dati, con il numero di elementi da creare all'interno delle parentesi. Questo schema funziona per gli array di qualunque tipologia di dati.

NOTA: Ogni array può memorizzare solamente un tipo di dati (boolean, int, float, PImage, etc.). Non puoi mischiare e combinare generi di dati diversi all'interno di un singolo array. Se invece hai bisogno di farlo, lavora con gli oggetti.

Prima di andare ancora avanti, rallentiamo un poco e parliamo di come lavorare con gli array in maggior dettaglio. Così come quando si crea un oggetto, ci sono tre passaggi per lavorare con un array:

1. Dichiara l'array e definisci il tipo di dati.2. Crea un array con la parola chiave new e definiscine la lunghezza.3. Assegna i valori a ciascun elemento.

Ogni passaggio può verificarsi nella sua riga, oppure tutte le fasi possono essere compresse insieme.Ciascuno dei tre esempi seguenti mostra una tecnica differente per creare un array chiamato x che incorpora due interi, 12 e 2. Presta la massima attenzione a quello che accade prima di setup( ) e a quello che accade all'interno di setup( ).

Esempio 10-4: Dichiarare ed Assegnare un Array

Prima di tutto dichiareremo l'array all'esterno del setup( ) e poi creeremo ed assegneremo i valori all'interno. La sintassi x[0] si riferisce al primo elemento nell'array e x[1] è il secondo:

int[] x; // Declare the array

void setup() {size(200, 200);x = new int[2]; // Create the arrayx[0] = 12; // Assign the first valuex[1] = 2; // Assign the second value}

Esempio 10-5: Unire le Assegnazioni di un Array

Questo è un esempio leggermente più compatto, in cui l'array è sia dichiarato che creato nella stessa riga, poi i valori sono assegnati in setup( ):

int[] x = new int[2]; // Dichiara e crea l'arrayvoid setup() {size(200, 200);x[0] = 12; // Assegna il primo valorex[1] = 2; // Assegna il secondo valore}

Esempio 10-6: Assegnare ad un Array in un Colpo Solo

Puoi anche assegnare i valori all'array quando viene creato, se mettiamo tutto in un'unica istruzione:

int[] x = { 12, 2 }; // Dichiara, crea ed assegnavoid setup() {size(200, 200);}

NOTA: Evita di creare gli array all'interno di draw( ), poiché creare un nuovo array ad ogni frame rallenterà la frequenza dei fotogrammi.

Esempio 10-7: Rivisitare il Primo Esempio

Per fare un esempio completo di come utilizzare gli array, abbiamo ricodificato qui l'Esempio 10-1.Sebbene non abbiamo ancora visto i pieni benefici rivelati nell'Esempio 10-3, vediamo alcuni importanti dettagli di come gli array funzionano:

float[] x = {-20, 20};void setup() {size(240, 120);smooth();noStroke();}void draw() {background(0);x[0] += 0.5; // Incrementa il primo elementox[1] += 0.5; // Incrementa il secondo elementoarc(x[0], 30, 40, 40, 0.52, 5.76);arc(x[1], 90, 40, 40, 0.52, 5.76);}

Ripetizione ed Array

Il ciclo for, introdotto in “Ripetizione” nel Capitolo 4, facilita il lavoro con array molto ampi mantenendo sintetico il codice. L'idea è di costruire un ciclo che permette di muoversi attraverso ogni elemento dell'array. Per fare questo, hai bisogno di conoscere la lunghezza dell'array. Il campo

lenght associato ad ogni array memorizza il numero degli elementi. Noi usiamo il nome dell'array con il punto per avere accesso a questo valore. Facciamo un esempio:

int[] x = new int[2]; // Dichiara e crea l'arrayprintln(x.length); // Stampa 2 sulla consoleint[] y = new int[1972]; // Dichiara e crea l'arrayprintln(y.length); // Stampa 1972 sulla console

Esempio 10-8: Inserire un Array in un Ciclo for

Un ciclo for può essere usato per riempire un array con dei valori, o per leggere i valori che esso produce. In questo esempio, l'array è prima riempito con numeri casuali all'interno del setup( ), poi questi numeri sono usati per impostare il valore del contorno in draw( ). Ogni volta che il programma viene eseguito, una nuova serie di numeri casuali è inserito nell'array:

float[] gray;void setup() {size(240, 120);gray = new float[width];for (int i = 0; i < gray.length; i++) {gray[i] = random(0, 255);}}void draw() {for (int i = 0; i < gray.length; i++) {stroke(gray[i]);line(i, 0, i, height);}}

Esempio 10-9: Prendere Traccia dei Movimenti del Mouse

In questo esempio, ci sono due array per immagazzinare la posizione del mouse – uno per la coordinata-x ed uno per la coordinata-y. Questi array memorizzano la posizione del mouse nei 60 fotogrammi precedenti. Ad ogni nuovo frame, i valori delle coordinate x ed y più vecchi vengono rimossi e rimpiazzati con i valori attuali di mouseX e mouseY. I nuovi valori sono aggiunti alla prima posizione dell'array, ma prima che questo accada, ogni valore nell'array è spostato di una posizione verso destra (da dietro in avanti ) per fare spazio ai nuovi numeri. Questo esempio rende visibile l'azione.

Invece, ad ogni frame, tutte e 60 le coordinate vengono usate per disegnare una serie di ellissi sullo schermo:

int num = 60;int x[] = new int[num];int y[] = new int[num];void setup() {size(240, 120);smooth();noStroke();}void draw() {background(0);// Copia i valori dell'array da dietro in avantifor (int i = x.length-1; i > 0; i--) {x[i] = x[i-1];

y[i] = y[i-1];}x[0] = mouseX; // Imposta il primo elementoy[0] = mouseY; // Imposta il primo elementofor (int i = 0; i < x.length; i++) {fill(i * 4);ellipse(x[i], y[i], 40, 40);}}

NOTA: La tecnica di immagazzinare una memoria mobile di numeri in un array come mostrato in questo esempio e nella Figura 10-2 è meno efficiente di una tecnica alternativa che utilizza l'operatore % (modulo). Questo è spiegato nell'esempio Examples → Basics → Input → StoringInput che è incluso con Processing.

Array di Oggetti

I due brevi esempi in questa sezione raccolgono insieme ogni principale concetto di programmazione contenuto in questo libro: variabili, iterazione, condizionali, funzioni, oggetti ed array. Costruire un array di oggetti è più o meno la stessa cosa di costruire un array come lo abbiamo spiegato nelle pagine precedenti, ma con una considerazione in più: poiché ogni elemento dell'array è un oggetto, dev'essere prima creato con la parola chiave new (come ogni altro oggetto) prima che sia assegnato ad un array. Con una classe personalizzata come JitterBug (vedi il Capitolo 9), questo significa usare new per impostare ogni elemento prima che sia assegnato all'array. Oppure, per una classe precostruita di Processing come PImage, significa utilizzare la funzione loadImage( ) per creare un oggetto prima che sia assegnato.

Esempio 10-10: Gestire Molti Oggetti

Questo esempio crea un array di 33 oggetti JitterBug e poi aggiorna e ne visualizza ognuno in draw( ). Per far funzionare questo esempio, hai bisogno di aggiungere la classe JitterBug al codice:

JitterBug[] bugs = new JitterBug[33];void setup() {size(240, 120);smooth();for (int i = 0; i < bugs.length; i++) {float x = random(width);float y = random(height);int r = i + 2;bugs[i] = new JitterBug(x, y, r);}}void draw() {for (int i = 0; i < bugs.length; i++) {bugs[i].move();bugs[i].display();}}// Copia qui la classe JitterBug

L'array dell'esempio finale carica una sequenza di immagini e ne memorizza ognuno come una elemento all'interno di un array di oggetti PImage.

Esempio10-11: Sequenze di Immagini

Per eseguire questo esempio, acquisisci le immagini dal file media.zip come descritto nel Capitolo 6. Le immagini sono nominate in sequenza (frame-0001.png, frame-0002.png, e così via),che rende possibile creare il nome di ciascun file in un ciclo for, come vediamo nell'ottava linea del programma:

int numFrames = 12; // Il numero dei framePImage[] images = new PImage[numFrames]; // Crea un arrayint currentFrame = 1;void setup() {size(240, 120);for (int i = 1; i < images.length; i++) {String imageName = "frame-" + nf(i, 4) + ".png";images[i] = loadImage(imageName); // Carica ogni immagine}frameRate(24);}void draw() {image(images[currentFrame], 0, 0);currentFrame++; // Prossimo frameif (currentFrame >= images.length) {currentFrame = 1; // Ritorna al primo frame}}

La funzione nf( ) formatta i numeri cosicchè nf (1,4) restituisce la stringa “0001” e nf (11,4) restituisce “0011”. Questi valori vengono concatenati con l'inizio del nome del file (“frame-”) e con la fine (“.png”) per creare il nome completo del file come una variabile String. I file sono caricati nell'array della riga successiva. Le immagini vengono visualizzate sullo schermo una alla volta in draw( ). Quando l'ultima immagine nell'array viene visualizzata, il programma torna all'inizio dell'array e mostra di nuovo le immagini in sequenza.

Robot 8: Array

Gli array facilitano ad un programma il lavoro con più elementi. In questo esempio, un array di oggetti Robot viene dichiarato all'inizio. L'array è poi collocato all'interno di setup( ), ed ogni oggetto Robot viene creato all'interno del ciclo for. Nel draw( ), un altro ciclo for è usato per aggiornare e visualizzare ogni elemento dell'array dei robot.

Il ciclo for ed un array creano una potente combinazione. Nota le sottili differenze tra il codice in questo esempio e Robot 7 (vedi “Robot 7: Oggetti” nel Capitolo 9 ) in contrasto con gli estremi cambiamenti nel risultato visivo. Una volta che un array viene creato ed un ciclo for è messo in atto, diventa facile lavorare con 3 elementi così come con 3000.

La decisione di caricare il file SVG all'interno del setup( ) invece che nella classe Robot è la modifica maggiore da Robot 7. Questa scelta è stata effettuata così che il file venga caricato una sola volta, invece che tante volte quanti sono gli elementi nell'array (in questo caso, 20 volte). Questo cambiamento fa si che il codice parta prima poiché caricare un file richiede tempo, ed inoltre usa meno memoria poiché il file è memorizzato solo una volta. Ogni elemento dell'array bot fa riferimento allo stesso file.

Robot[] bots; // Dichiara l'array di oggetti robotvoid setup() {size(720, 480);PShape robotShape = loadShape("robot1.svg");// Crea l'array di oggetti robotbots = new Robot[20];// Crea ciascun oggettofor (int i = 0; i < bots.length; i++) {// Create a random x-coordinatefloat x = random(-40, width-40);// Assegna la coordinata y in base all'ordine float y = map(i, 0, bots.length, -100, height-200);bots[i] = new Robot(robotShape, x, y);}smooth();}void draw() {background(204);// Aggiorna e visualizza ogni robot nell'arrayfor (int i = 0; i < bots.length; i++) {bots[i].update();bots[i].display();}}class Robot {float xpos;float ypos;float angle;PShape botShape;float yoffset = 0.0;// Imposta il valore iniziale nel constructorRobot(PShape shape, float tempX, float tempY) {botShape = shape;xpos = tempX;ypos = tempY;angle = random(0, TWO_PI);

}// Aggiorna i campivoid update() {angle += 0.05;yoffset = sin(angle) * 20;}// Disegna il robot sullo schermovoid display() {shape(botShape, xpos, ypos + yoffset);}}

11/ EstendereQuesto libro si concentra nell'utilizzare Processing per grafiche interattive, poiché è questo il cuore di ciò a cui Processing tende. D'altronde, il software può fare molto di più ed è spesso parte di progetti che si muovono al di là di un semplice schermo del computer. Ad esempio, Processing è stato usato per controllare macchine, esportare immagini per film ad alta definizione, ed esportare modelli per stampe 3D.

Durante l'ultima decade, Processing è stato utilizzato per fare video musicali per Radiohead e R.E.M., per creare illustrazioni per pubblicazioni come Nature ed il New York Times, per produrre sculture per mostre, per controllare una parete video di 120 per 120 piedi, per cucire maglioni, e molto altro. Processing deve questa flessibilità al suo sistema di librerie.

Una libreria di Processing è una collezione di codice che estende il software al di là delle sue funzioni e classi fondamentali. Le librerie hanno avuto un'importanza fondamentale per la crescita del progetto, poiché lasciano aggiungere agli sviluppatori nuove funzionalità velocemente. Come piccoli progetti autosufficienti, le librerie sono più semplici da gestire di quanto lo sarebbero queste funzioni se fossero integrate nel software principale.

In aggiunta alle librerie incluse in Processing (che sono chiamate core libraries), ci sono oltre 100contributed libraries che si possono raggiungere tramite un link dal sito web di Processing. Tutte le librerie sono elencate online a http://p rocessing.org/reference/libraries/ .

Per usare una libreria, seleziona Import Library dal menu Sketch. Scegliere una libreria aggiungerà una riga di codice che indica che la libreria sarà usata con lo sketch corrente. Ad esempio, quando la libreria OpenGL viene aggiunta, appare questa riga di codice in cima allo sketch:

import processing.opengl.*;

Prima che una libreria possa essere importata attraverso il menu Sketch, dev'essere scaricata dal suo sito web e posizionata all'interno della cartella libraries nel tuo computer. La tua cartella libraries è collocata nel tuo sketchbook. Puoi trovare la posizione del tuo sketchbook aprendo le Preferences.Posiziona la libreria scaricata in una cartella nel tuo sketchbook chiamata libraries. Se questa cartella ancora non esiste, creala.

Come già menzionato, ci sono più di 100 librerie di Processing, così non possono venir tutte discusse qui in modo esaustivo.

3D

Ci sono due modi di disegnare in 3D con Processing: entrambi richiedono di aggiungere un terzo parametro alla funzione size( ) per cambiare il modo in cui la grafica viene disegnata. Di default, Processing disegna usando un rendering 2D molto preciso, ma lento. Questo è il renderer JAVA2D. Una versione qualche volta più veloce ma di qualità più bassa è il P2D, il renderer 2D di Processing. Puoi anche cambiare il renderer in Processing 3D, chiamato P3D, oppure OpenGL, per permettere ai tuoi programmi di disegnare in una dimensione in più, l'asse z (vedi la Figura 11-1).

Render con Processing 3D in questo modo:

size(800,600, P3D);

Ed OpenGL in questo modo:

size (800, 600, OPENGL) ;

Il renderer P3D è incorporato, invece il renderer OpenGL è una libreria e richiede l'istruzione import all'interno del codice, come mostrato all'inizio dell'Esempio 11-1. Il renderer OpenGL fa uso di grafica più veloce che è disponibile sulla maggior parte delle macchine vendute al giorno d'oggi.

NOTA: Il renderer OpenGL non garantisce la velocità in ogni occasione; vedi le referenze per size( ) per maggiori dettagli.

Molte delle funzioni introdotte in questo libro hanno variazioni per lavorare in 3D. Ad esempio, le funzioni base di disegno point( ), line( ), e vertex( ) semplicemente aggiungono i parametri z ai parametri x ed y che sono stati spiegati in precedenza. Anche le trasformazioni translate( ), rotate( ) e scale( ) funzionano in 3D.

Esempio 11-1: Una Demo 3D

Molte funzioni 3D sono spiegate nelle Referenze di Processing, ma qui c'è un esempio per farti iniziare:

import processing.opengl.*;void setup() {size(440, 220, OPENGL);noStroke();fill(255, 190);}void draw() {background(0);translate(width/2, height/2, 0);rotateX(mouseX / 200.0);rotateY(mouseY / 100.0);int dim = 18;for (int i = -height/2; i < height/2; i += dim*1.2) {for (int j = -height/2; j < height/2; j += dim*1.2) {beginShape();vertex(i, j, 0);vertex(i+dim, j, 0);

vertex(i+dim, j+dim, -dim);vertex(i, j+dim, -dim);endShape();}}}

Quando inizi a lavorare con il 3D, è possibile esplorare nuove funzioni. É possibile cambiare la visuale, le luci, le proprietà dei materiali, e disegnare forme 3D come sfere e cubi.

Esempio 11-2: Illuminazione

Questo esempio è costruito sull'Esempio 11-1 sostituendo i rettangoli con i cubi e aggiungendo alcuni tipi di luci. Prova a commentare ed a decommentare luci differenti per vedere come ciascuna lavori da sola ed in combinazione con le altre:

import processing.opengl.*;void setup() {size(420, 220, OPENGL);noStroke();fill(255);}void draw() {lights();//ambientLight(102, 102, 102);//directionalLight(255, 255, 255, // Color// -1, 0, 0); // Direction XYZ//pointLight(255, 255, 255, // Color// mouseX, 110, 50); // Position//spotLight(255, 255, 255, // Color// mouseX, 0, 200, // Position// 0, 0, -1, // Direction XYZ// PI, 2); // ConcentrationrotateY(PI/24);background(0);translate(width/2, height/2, -20);int dim = 18;for (int i = -height/2; i < height/2; i += dim*1.4) {for (int j = -height/2; j < height/2; j += dim*1.4) {pushMatrix();translate(i, j, -j);box(dim, dim, dim);popMatrix();}}}

Ci sono quattro tipi di luci in Processing: spot, a punto, direzionali, e ambientali. Le luci spot si irradiano in una forma conica; hanno una direzione, una collocazione ed un colore. Le luci a punto si irradiano da un singolo punto come una lampadina di qualsiasi colore. Le luci direzionali si proiettano in una direzione per creare forti luci ed ombre. Le luci ambientali creano una luce uniforme di qualsiasi colore sull'intera scena e vengono per lo più utilizzate con le altre luci.La funzione lights( ) crea un'impostazione di luci predefinita con una luce ambientale ed una direzionale. Le luci devono essere resettate ogni volta all'interno di draw( ), quindi dovrebbero comparire all'inizio di draw( ) per assicurare risultati consistenti.

Lavorare in 3D introduce l'idea di una “camera” puntata sulla scena tridimensionale che è stata

costruita. Come una videocamera reale, mappa lo spazio 3D nel piatto piano 2D dello schermo. Muovere la camera cambia il modo in cui Processing mappa le coordinate 3D del tuo disegno nello schermo 2D.

Esempio 11-3: La Telecamera di Processing

Di default, Processing crea una telecamera che punta al centro dello schermo, quindi le forme lontano dal centro sono viste in prospettiva. La funzione camera( ) offre un controllo sulla posizione della videocamera, la posizione in cui è puntata, e l'orientamento (sopra, sotto, inclinato).Nell'esempio seguente, il mouse viene usato per muovere la posizione in cui la telecamera è puntata:

import processing.opengl.*;void setup() {size(420, 220, OPENGL);noStroke();}void draw() {lights();background(0);float camZ = (height/2.0) / tan(PI*60.0 / 360.0);camera(mouseX, mouseY, camZ, // Posizione della telecamerawidth/2.0, height/2.0, 0, // Bersaglio della telecamera0, 1, 0); // Orientamento della telecameratranslate(width/2, height/2, -20);int dim = 18;for (int i = -height/2; i < height/2; i += dim*1.4) {for (int j = -height/2; j < height/2; j += dim*1.4) {pushMatrix();translate(i, j, -j);box(dim, dim, dim);popMatrix();}}}

Questa sezione ha presentato la punta dell'iceberg delle capacità del 3D. In aggiunta alle funzionalità di base menzionate qui, ci sono molte altre librerie di Processing che aiutano a generare forme 3D, a caricare ed esportare le forme, e forniscono un controllo più avanzato della telecamera.

Esportazione delle Immagini

Le immagini animate create da un programma di Processing possono essere trasformate in una sequenza di file con la funzione saveFrame( ). Quando saveFrame( ) si trova alla fine del draw( ), memorizza una sequenza numerata di immagini in formato TIFF dell'output del programma nella cartella sketch, nominandoli screen-0001.tif, screen-0002.tif, e così via. Questi file possono essere importati in un programma di video o animazione e salvati come un filmato. Puoi anche specificare il nome del file ed il formato dell'immagine con una riga di codice come questa:

saveFrame (“output-####.png”);

NOTA: Quando utilizzi saveFrame( ) all'interno del draw( ), un nuovo file viene salvato ad ogni frame – quindi stai attento poiché può rapidamente riempire la tua cartella dello sketch con migliaia di file.

Usa il simbolo # (cancelletto) per mostrare dove i numeri vengono mostrati all'interno del nome del file. Questi vengono rimpiazzati con il numero attuale dei frame quando il file viene salvato. Puoi anche specificare una sottocartella dove salvare le immagini, la quale è utile quando si lavora con molti fotogrammi:

saveFrame (“frames/output-####.png”);

Esempio 11-4: Salvare le immagini

Questo esempio mostra come salvare le immagini memorizzando abbastanza fotogrammi di un'animazione di due secondi. Il programma viene eseguito a 30 frame al secondo e si conclude dopo 60 frame:

float x = 0;

void setup() {size(720, 480);smooth();noFill();strokeCap(SQUARE);frameRate(30);}void draw() {background(204);translate(x, 0);for (int y = 40; y < 280; y += 20) {line(-260, y, 0, y + 200);line(0, y + 200, 260, y);}if (frameCount < 60) {saveFrame("frames/SaveExample-####.tif");} else {exit();}x += 2.5;}

Processing scriverà un'immagine basata sull'estensione del file che hai usato (.png, .jpg, o .tif sono tutti incorporati, ed alcune piattaforme possono supportarne altre). Un'immagine .tif viene salvata senza compressione, il quale è un metodo più veloce ma che richiede uno spazio maggiore nel disco. Sia il .png che il .jpg creeranno file più piccoli, ma a causa della compressione, verrà solitamente richiesto più tempo per salvarlo, rendendo l'esecuzione del file più lenta.

Se ciò che devi produrre è grafica vettoriale, puoi scriverlo in file PDF per una maggiore risoluzione. La libreria PDF Export rende possibile scrivere file PDF direttamente dallo sketch.Questi file di grafica vettoriale possono essere ridimensionati ad ogni dimensione senza perdere risoluzione, il che li rende ideale per una prodotto da stampare – dai poster alle insegne ad interi libri.

Esempio 11-5: Disegnare in formato PDF

Questo esempio viene costruito sull'Esempio 11-4 per disegnare più parentesi uncinate di differenti misure, ma il movimento viene rimosso. Viene creato un file PDF chiamato Ex-11-5.pdf per il terzo

ed il quarto parametro di size( ):

import processing.pdf.*;void setup() {size(600, 800, PDF, "Ex-11-5.pdf");noFill();strokeCap(SQUARE);}void draw() {background(255);for (int y = 100; y < height - 300; y+=20) {float r = random(0, 102);strokeWeight(r / 10);beginShape();vertex(100, y);vertex(width/2, y + 200);vertex(width-100, y);endShape();}exit();}

La geometria non viene disegnata sullo schermo; è scritta direttamente nel file PDF, il quale è salvato nella cartella sketch. Il codice in questo esempio viene eseguito una volta e poi si conclude alla fine del draw( ). Il prodotto risultante è mostrato nella Figura 11-2.

Ci sono altri esempi di PDF Export inclusi nel software di Processing. Guarda nella sezione PDF Export degli esempi di Processing per vedere altre tecniche.

Hello Arduino

Arduino è una piattaforma per prototipi elettronici con una serie di schede di microcontroller ed il software per programmarle. Processing e Arduino condividono una lunga storia insieme; sono dei progetti fratelli con molte idee ed obiettivi simili, sebbene possiedano campi separati.Poiché condividono lo stesso editor ed ambiente di programmazione ed una sintassi simile, è facile muoversi tra di loro e trasferire conoscenza dall'uno all'altro.

In questa sezione, ci focalizziamo con sulla lettura di dati da Processing ad una scheda Arduino e poi sul visualizzare questi dati sullo schermo. Ciò rende possibile l'utilizzo di nuovi input in un programma di Processing e permette ai programmatori di Arduino di vedere i propri sensori di ingresso come grafica. Questi nuovi input possono essere i più disparati che possono venir collegati ad una scheda Arduino. Questi dispositivi spaziano da un sensore di distanza ad una bussola ad un network mesh a dei sensori di temperatura.

Questa sezione da per scontato che tu possieda una scheda Arduino e che possiedi già una conoscenza di base per saperlo usare. Se non è così, puoi saperne di più online a http://www.arduino.cc e nell'ottimo libro Getting Started With Arduino di Massimo Banzi (O'Reilly). Una volta che hai compreso le basi, puoi imparare altro sull'invio di dati da Processing ad Arduino in un altro eccezionale libro, Making Things Talk di Tom Igoe (O'Reilly).

I dati possono essere trasferiti dagli sketch di Processing ad una scheda Arduino con un po' d'aiuto dalla Serial Library di Processing. Serial è un formato i dati che spedisce un byte alla volta. Nel mondo di Arduino, un byte è una tipologia di dati che può immagazzinare i valori tra lo 0 ed il 255;

lavora come un int, ma con un intervallo più breve. I numeri più grandi sono inviati per essere frammentati in una lista di byte e poi riassemblati successivamente.

Nell'esempio successivo, ci concentriamo sulla parte riguardante Processing e lasciamo il codice di Arduino semplificato. Visualizziamo i dati in arrivo dalla scheda Arduino un byte alla volta. Con le tecniche apprese in questo libro e i centinaia di esempi online di Arduino, speriamo che sia abbastanza per farti iniziare.

Esempio 11-6: Leggere un sensore

Il seguente codice di Arduino viene usato con i prossimi tre esempi di Processing:

// Nota:Questo è un codice per la scheda Arduino, non per Processing

int sensorPin = 0; // Seleziona pin di inputint val = 0;void setup() {Serial.begin(9600); // Apri porta seriale}void loop() {val = analogRead(sensorPin) / 4; // Leggi i valori dal sensoreSerial.print(val, BYTE); // Stampa la variabile nella porta serialedelay(100); // Aspetta 100 millisecondi}

Ci sono due dettagli importanti da notare riguardo questo esempio di Arduino. Primo, richiede di inserire un sensore nell'ingresso analogico sul pin 0 nella scheda Arduino.Potresti usare un sensore luminoso ( chiamato anche foto-resistenza, fotocellula, o resistenza dipendente dalla luce) oppure un'altra resistenza analogica come un termistore (resistenza sensibile alla temperatura), un sensore di flessione, od un sensore di pressione (resistenze sensibili alla forza).Il diagramma ed il disegno dei circuiti della breadboard con i componenti è mostrata nella Figura 11-4. Poi nota che il valore riportato dalla funzione analogRead( ) si trova tra lo 0 e 1023, così lo dividiamo per 4 per convertirlo ad un intervallo tra 0 e 255 così che i dati possono essere inviati in un singolo byte.

Esempio 11-7: Leggere i Dati dalla Porta Seriale

Il primo esempio di visualizzazione mostra come leggere i dati seriali dalla scheda Arduino e come convertire questi dati nei valori che si adattano alle dimensioni dello schermo:

import processing.serial.*;Serial port; // Crea un oggetto dalla classe Serialfloat val; // I dati ricevuti dalla porta serialevoid setup() {size(440, 220);// NOTA IMPORTANTE:// La prima porta seriale estratta da Serial.list()// dev'essere il tuo Arduino. Se non è così, decommenta la linea// di testo cancellando le // prima di essa. Esegui lo sketch// un'altra volta per vedere una lista di porte seriali. Poi // cambia lo 0 all'interno di [ e ] con il numero della porta// a cui il tuo Arduino è connesso

//println(Serial.list());String arduinoPort = Serial.list()[0];port = new Serial(this, arduinoPort, 9600);}void draw() {if (port.available() > 0) { // Se i dati non sono disponibili,val = port.read(); // leggilo e memorizzalo in valval = map(val, 0, 255, 0, height); // converti il valore}rect(40, val-10, 360, 20);

La libreria Serial viene importata nella prima linea e la porta seriale viene aperta in setup( ).Questo può o non può essere facile per far si che lo sketch di Processing con la scheda Arduino; dipende dalla tua configurazione hardware. C'è spesso più di un dispositivo con cui lo sketch di Processing può comunicare. Se il codice non funziona la prima volta, leggi attentamente il commento in setup( ) e segui le istruzioni.

All'interno del draw( ), il valore viene portato all'interno del programma con il metodo read( ) dell'oggetto Serial. Il programma legge i dati dalla porta seriale solamente quando è disponibile un nuovo byte. Il metodo available( ) prova a vedere se un nuovo byte è pronto e restituisce il numero dei byte disponibili. Questo programma viene scritto così che un singolo nuovo byte verrà letto ogni volta all'interno di draw( ). La funzione map( ) converte il valore in arrivo dal suo range iniziale che va da 0 a 255 ad un range che va da 0 all'altezza dello schermo;In questo programma, è da 0 a 220.

Esempio 11-8: Visualizzare il Flusso di Dati

Ora che i dati sono riusciti a passare, li visualizzeremo in un formato più interessante. I valori che entrano direttamente da un sensore sono spesso incostanti, ed è utile semplificarli facendone una media. Qui presenteremo il segnale grezzo proveniente da un sensore di luce illustrato nella figura 11-4 nella metà superiore dell'esempio ed il segnale perfezionato nella metà inferiore:

import processing.serial.*;Serial port; // Crea un oggetto dalla classe Serialfloat val; // I dati ricevuti dall porta serialeint x;float easing = 0.05;float easedVal;void setup() {size(440, 440);frameRate(30);smooth();String arduinoPort = Serial.list()[0];port = new Serial(this, arduinoPort, 9600);background(0);}void draw() {if ( port.available() > 0) { // Se i dati sono disponibili,val = port.read(); // leggili e memorizzali in valval = map(val, 0, 255, 0, height); // Converti i valori}float targetVal = val;easedVal += (targetVal - easedVal) * easing;stroke(0);line(x, 0, x, height); // Linea nerastroke(255);line(x+1, 0, x+1, height); // Linea bianca

line(x, 220, x, val); // Valore grezzoline(x, 440, x, easedVal + 220); // Valore mediox++;if (x > width) {x = 0;}}

Simile all'Esempio 5-8 e 5-9, questo sketch usa la tecnica easing.Ogni nuovo byte dalla scheda Arduino è impostato come il valore obiettivo, la differenza fra il valore corrente ed il valore obiettivo viene calcolata, ed il valore corrente si muove più vicino all'obiettivo. Regola la variabile easing per influenzare l'intensità dello smoothing applicata al valore in arrivo.

Esempio 11-9: Un altro modo di guardare ai Dati

Questo esempio è ispirato dagli schermi di visualizzazione dei radar. I valori sono letti nello stesso modo dalla scheda Arduino, ma sono visualizzati in un pattern circolare usando le funzioni di sin( ) e cos( ) introdotte precedentemente negli Esempi che vanno dal 7-12 al 7-15:

La variabile angle viene aggiornata continuamente per muovere la linea disegnando il valore corrente attorno al cerchio, e la variabile val ridimensiona la lunghezza della linea in movimento, per impostare la sua distanza dal centro dello schermo.Dopo un giro attorno al cerchio, i valori iniziano ad essere scritti in cima ai dati precedenti.

Siamo eccitati dalla potenziale di utilizzare Processing e Arduino insieme per collegare il mondo del software e dell'elettronica. A differenza di come sono fatti gli esempi stampati in questo libro, le comunicazioni possono essere bidirezionali. Gli elementi sullo schermo possono anche influenzare ciò che accade sulla scheda Arduino. Ciò significa che tu puoi usare un programma di Processing come un'interfaccia tra il tuo computer e motori, altoparlanti, luci, camere, sensori, e praticamente qualsiasi cosa che può essere controllata da un segnale elettrico. Di nuovo, ulteriori informazioni riguardo Arduino possono esser trovate ad http://www.arduino.cc .

Community

Abbiamo lavorato duramente per rendere facile l'esportazione di programmi di Processing cosicché tu possa condividerli facilmente con altri. Nel secondo capitolo, abbiamo parlato della condivisione dei tuoi programmi attraverso l'esportazione. Crediamo che la condivisione favorisca l'apprendimento e lo sviluppo della comunità. Nel momento in cui modificherai i programmi di questo libro ed inizierai a scrivere i tuoi programmi da zero, ti incoraggiamo a rivedere questa sezione del libro e condividere il tuo lavoro con altri.Allo stato attuale, i gruppi di OpenProcessing, Vimeo, Flickr, e la Processing Wiki sono luoghi eccitanti da visitare e a cui dare un contributo.Su Twitter, le ricerche di #Processing e Processing.org producono risultati interessanti.Queste comunità sono sempre in movimento. Controlla il sito principale di Processing ( http://www.processing.org ) per link recenti come questi:

>> http://www.openprocessing.org>> http://www.vimeo.com/tag:processing.org>> http://www.flickr.com/groups/processing/>> http://www.delicious.com/tag/processing.org/

A/Suggerimenti per Scrivere CodiceCodificare è un tipo di scrittura. Come tutti le tipologie di scrittura, il codice ha le sue regole specifiche. Per fare un confronto, citeremo velocemente alcune delle regole dell'Inglese su cui non ti sarai soffermato da un po'. Alcune tra le regole più invisibili sono lo scrivere da sinistra a destra e l'inserire lo spazio tra ogni parola. Altre regole evidenti sono le convinzioni ortografiche, mettere le lettere maiuscole all'inizio dei nomi di persone e luoghi, ed usare la punteggiatura alla fine delle frasi per dare enfasi!Se non rispettiamo una o più di queste regole quando scriviamo una mail ad un amico, il messaggio arriva comunque. Ad esempio, “Ciao ben, cm stai gg?” è altrettanto chiaro di, “Ciao Ben, come stai oggi?”D'altronde la flessibilità con le regole della scrittura non è applicabile alla programmazione.Poiché stai scrivendo per comunicare con un computer, invece che con un'altra persona, hai bisogno di essere più preciso e attento.Un carattere fuori posto fa spesso la differenza tra un programma che funziona ed uno che non funziona.

Processing prova a dirti dov'è stato fatto l'errore ed a indovinare qual è l'errore.Quando premi il pulsante Run, se ci sono problemi grammaticali (di sintassi) con il tuo codice (noi li chiamiamo bugs), l'area dei messaggi diventa rossa e Processing prova ad evidenziare la linea di codice che si sospetta abbia il problema.La linea di codice con il bug è spesso una riga sotto o sopra quella evidenziata, anche se in alcuni casi non è in nessun posto vicino.Il testo nell'area dei messaggi cerca di essere utile suggerisce il potenziale problema, ma talvolta il messaggio è troppo criptico da capire.Per un principiante, questi messaggi di errore possono essere frustranti.Bisogna capire che Processing è un semplice software che prova ad essere d'aiuto, ma ha una conoscenza limitata di ciò che stai provando a fare.

I lunghi messaggi di errore sono stampati più in dettaglio sulla Console, e qualche volta scorrere il testo può offrire un suggerimento.Inoltre Processing può trovare più di un bug alla volta. Se il tuo programma ha più di un bug, devi continuare ad eseguire il programma e sistemarli uno alla volta.

Ti preghiamo di leggere e rileggere attentamente i seguenti suggerimenti per aiutarti a scrivere un codice pulito.

Funzioni e Parametri

I programmi sono composti di tante piccole parti, le quali sono raggruppate insieme per creare strutture più grandi. Abbiamo un sistema simile nella lingua Inglese: le parole sono raggruppate in frasi, le quali sono raggruppate in periodi, i quali sono raggruppati in paragrafi.L'idea è la stessa nel codice, ma le piccole parti hanno nomi differenti e si comportano in modo differente. Funzioni e Parametri sono due parti importanti. Le funzioni sono i blocchi di costruzione principali di un programma di Processing. I parametri sono valori che definiscono il comportamento delle funzioni.

Prendi in considerazione una funzione come background( ). Come suggerisce il nome, è usata per impostare il colore dello sfondo della finestra di visualizzazione. La funzione ha tre parametri che definiscono il colore. Questi numeri definiscono le componenti di rosso, verde e blu del colore composto. Ad esempio, il codice seguente disegna uno sfondo blu:

background(51, 102, 153);

Guarda attentamente questa singola riga di codice. I dettagli chiave sono le parentesi dopo il nome della funzione che racchiudono i numeri, le virgole tra ogni numero, ed il punto e virgola alla fine della riga. Il punto e virgola è usato come un punto. Ciò significa che una dichiarazione è chiusa ed il computer può guardare l'inizio della prossima.Tutte queste parti devono essere lì perchè il codice venga eseguito.Confronta la riga di esempio precedente a queste tre versioni incomplete della stessa riga:

background 51, 102, 153; // Errore! Mancano le parentesibackground(51 102, 153); // Errore! Manca una virgolabackground(51, 102, 153) // Errore! Manca un punto e virgola

Il computer è spietato riguardo anche la più piccola omissione o deviazione da quello che si aspetta.Se tu ricordi queste parti, avrai pochi bug. Ma se ti dimentichi di digitarli, come tutti facciamo, non è un problema. Processing ti avvertirà del problema, e quando è risolto, il programma verrà eseguito correttamente.

Scrivere Codice a Colori

L'ambiente di Processing produce un codice a colori in differenti parti di ogni programma.Le parole che sono parte di Processing sono disegnate in blu e arancio per distinguerle dalle parti di programma che inventi tu stesso. Le parole che vengono usate unicamente per il tuo programma, come i nomi delle variabili e delle funzioni, sono scritte in nero. I simboli di base come ( ), [ ], e > sono anch'essi in nero.

Commenti

I commenti sono annotazioni che si scrivono a se stessi (o ad altre persone) all'interno del codice.Potresti usarli per chiarire cosa fa il codice in linguaggio semplice e per fornire informazioni addizionali come il titolo e l'autore del programma. Un commento inizia con due slash (//) e continua fino alla fine della riga:

// Questo è un commento ad una linea

Puoi creare un commenti in più linee facendolo partire con /* e finirlo con */. Ad esempio:

/* Questo commentocontinua per piùdi una linea*/

Quando un commento è digitato correttamente, il colore del testo diventerà grigio. L'intera area commentata diventerà grigia così potrai vederne chiaramente l'inizio e la fine.

Maiuscolo e Minuscolo

Processing distingue le lettere maiuscole da quelle minuscole e perciò leggerà “Ciao” come una parola distinta da “ciao”. Se stai tentando di disegnare un rettangolo con la funzione rect( ) e scriverai Rect( ), il codice non verrà eseguito. Puoi vedere se Processing riconosce il colore intenzionale osservando il colore del testo.

Stile

Processing è flessibile riguardo alla quantità di spazio che utilizzi per formattare il tuo codice. Processing ignora se scrivi:

rect(50, 20, 30, 40);

oppure:

rect (50,20,30,40);

oppure:

rect ( 50,20,30, 40)

Tuttavia, è nel tuo interesse creare codice leggibile. Ciò diventa importante specialmente quando il codice cresce in lunghezza. Una formattazione pulita rende la struttura del codice immediatamente leggibile, ed una formattazione scomposta spesso nasconde i problemi. Prendi l'abitudine di scrivere codice pulito. Ci sono differenti modi di formattare il codice in modo corretto, ed il modo che scegli per spaziare gli oggetti è fa parte delle preferenze personali.

Console

La console è l'area in fondo all'ambiente di Processing. Puoi scrivere messaggi sulla Console con la funzione println( ). Ad esempio, il codice seguente stampa un messaggio seguito dall'orario attuale:

println("Hello Processing.");println("The time is " + hour() + ":" + minute());

La Console è essenziale per osservare cosa sta succedendo all'interno del tuo programma mentre è in esecuzione. Viene usato per stampare il valore delle variabili in modo che tu possa prenderne nota, per confermare se gli eventi stanno accadendo, e per determinare dove il programma sta avendo un problema.

Un Passo alla Volta

Raccomandiamo di scrivere poche righe di codice alla volta ed eseguire il codice frequentemente per esser sicuri che i bug non vengano accumulati senza che tu lo sappia. Ogni programma ambizioso è scritto una riga alla volta. Suddividi il tuo progetto in semplici sottoprogetti e

completali uno alla volta così che potrai avere tanti piccoli successi, invece di uno sciame di bug.Se hai un bug, prova ad isolare l'area di codice dove pensi sia il problema. Prova a pensare al riparare i bug come a risolvere un mistero o un puzzle. Se ti ritrovi bloccato o sei frustrato, prenditi una pausa per chiarire la tua mente e chiedi ad un amico un aiuto. Talvolta la risposta è proprio sotto il tuo naso ma richiede un secondo parere per palesarsi.

B/Tipologie di datiCi sono diverse categorie di dati. Ad esempio, pensa ai dati su una carta d'identità. La carta ha numeri per memorizzare peso, altezza, data di nascita, indirizzo e codice postale. Ci sono parole per memorizzare un nome di persona e la città. Ci sono inoltre dati in immagini (una foto) e spesso una scelta di donare gli organi, una scelta si/no. Ognuno dei tipi seguenti è spiegato più in dettaglio in altre parti del libro, ma questo è un riepilogo:

Nome Descrizione Gamma di valoriint Numeri interi -2,147,483,648 a 2,147,483,647float Valori decimali Da -3.40282347E+38 a

3.40282347E+38boolean Valore logico Vero o falsochar Singolo carattere A-z, 0-9 e simboliString Sequenza di caratteri Qualunque lettera, parola, frase

e così viaPImage Immagine PNG, JPG o GIF N/APFont Font in formato VLW: usa lo

strumento Create Font per crearlo

N/A

PShape File SVG N/A

Come linea guida, un numero decimale ha quattro cifre di precisione dopo il punto decimale.Se stai contando o facendo brevi misurazioni, dovresti usare un valore int per prendere le misure, e poi magari reimpostarle in un float quando hai la necessità di utilizzarle.

Ci sono ulteriori tipologie di dati che non vengono menzionate qui, ma queste sono le più utili per il lavoro tipico di Processing. Infatti, come menzionato nel capitolo 9, ci sono infiniti tipi di dati, poiché ogni nuova classe è un tipo differente di dati.

C/Ordine delle OperazioniQuando i calcoli matematici sono svolti in un programma, ogni operazione prende posto secondo un ordine prefissato. Questo ordine delle operazioni assicura che il codice viene eseguito allo stesso modo ogni volta. Non c'è differenza tra aritmetica ed algebra, ma la programmazione ha altri operatori che risultano meno familiari.

Nella tavola seguente, gli operatori in cima vengono eseguiti prima di quelli sul fondo.Perciò, un'operazione all'interno delle parentesi verrà eseguita per prima ed un'assegnazione verrà eseguita per ultima.

D/Portata delle VariabiliLa regola della portata delle variabili viene spiegata facilmente: una variabile creata all'interno di un blocco (codice racchiuso all'interno di parentesi: { e } ) esiste solamente all'interno di quel blocco. Ciò significa che una variabile creata all'interno del blocco setup( ) può essere usata solo all'interno del blocco setup( ), e allo stesso modo, una variabile dichiarata all'interno di draw( ) può essere usata solo all'interno del blocco draw( ). L'eccezione a questa regola è una variabile dichiarata al di fuori di setup( ) e draw( ). Queste variabili possono essere usate sia in setup( ) che in draw( ) (o all'interno di ogni altra funzione che hai creato). Pensa all'area che si trova all'esterno di setup( ) e draw( ) come ad un blocco di codice implicito. Noi chiamiamo tutte queste variabili variabili globali, poiché possono essere usate ovunque all'interno del programma. Chiamiamo una variabile che viene usata solo all'interno di un singolo blocco una variabile locale. Di seguito ci sono una coppia di esempi di codice che spiegano ulteriormente il concetto. Il primo:

int i = 12; // Dichiara la variabile globale i ed assegna ad essa 12void setup() {size(480, 320);int i = 24; // Dichiara la variabile locale i ed assegna ad essa 24println(i); // Stampa 24 sulla console}void draw() {println(i); // Stampa 12 sulla console}

Ed il secondo:

void setup() {size(480, 320);int i = 24; // Dichiara la variabile locale ed assegna ad essa 24}void draw() {println(i); // ERRORE! La variabile i è locale in setup()}