Processing tutorial basico

27
Instrucciones de dibujo en 2D con Processing Píxel | línea recta | triángulo | círculo/elipse | cuadrado/rectángulo | curva bezier | arco Píxelset() Modo de Uso set (x,y,c); Parámetros X x del pixel Y y del pixel C Color. Si se usa un valor entero, se interpreta como valor de gris. Ejemplo código size(150,150); //define el tamaño de ventana background(0); //pinta la ventana de negro set(75,75,255); //dibuja un pixel blanco Línea Rectaline() Modo de Uso line (x1,y1,x2,y2); Parámetros x1 x de un extremo y1 y de un extremo x2 x del otro extremo y2 y del otro extremo Ejemplo código size(150,150); //define el tamaño de ventana background(255); //pinta el fondo de blanco strokeWeight(4); //ancho de la linea (4 pixeles) line(10,20,130,140); Triángulotriangle() Modo de Uso triangle(x1,y1,x2,y2,x3,y3); Parámetros x1 x del primer vértice y1 y del primer vértice x2 x del segundo vértice y2 y del segundo vértice x3 x del tercer vértice y3 y del tercer vértice Ejemplo código size(150,150); //define el tamaño de ventana background(255); //pinta el fondo de blanco strokeWeight(4); //ancho de la linea (4 pixeles) triangle(10,110,80,20,130,130); Círculo / Elipseellipse() Modo de uso ellipse(x1,y1,x1,y2); Parámetros El uso de los parametros depende de ellipseMode(); ellipseMode(CENTER); (valor por defecto) x1 x del centro y1 y del centro x2 ancho (diámetro) y2 alto (diámetro)

description

tutorial super basico para processing, en español, creditos para emiliano causa

Transcript of Processing tutorial basico

Page 1: Processing tutorial basico

Instrucciones de dibujo en 2D con ProcessingPíxel | línea recta | triángulo | círculo/elipse | cuadrado/rectángulo | curva bezier | arco

Píxelset()Modo de Usoset (x,y,c);

ParámetrosX x del pixelY y del pixelC Color. Si se usa un valor entero, se interpreta como valor de gris.Ejemplo códigosize(150,150); //define el tamaño de ventanabackground(0); //pinta la ventana de negroset(75,75,255); //dibuja un pixel blanco

Línea Rectaline()Modo de Usoline (x1,y1,x2,y2);

Parámetrosx1 x de un extremoy1 y de un extremox2 x del otro extremoy2 y del otro extremoEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta el fondo de blancostrokeWeight(4); //ancho de la linea (4 pixeles)line(10,20,130,140);

Triángulotriangle()Modo de Usotriangle(x1,y1,x2,y2,x3,y3);Parámetrosx1 x del primer vérticey1 y del primer vérticex2 x del segundo vérticey2 y del segundo vérticex3 x del tercer vérticey3 y del tercer vérticeEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta el fondo de blancostrokeWeight(4); //ancho de la linea (4 pixeles)triangle(10,110,80,20,130,130);

Círculo / Elipseellipse()

Modo de usoellipse(x1,y1,x1,y2);

ParámetrosEl uso de los parametros depende de ellipseMode();ellipseMode(CENTER); (valor por defecto)x1 x del centroy1 y del centrox2 ancho (diámetro)y2 alto (diámetro)

Page 2: Processing tutorial basico

ellipseMode(CORNER);x1 x del vértice superior izquierdo del rectángulo que la contieney1 y del vértice superior izquierdo del rectángulo que la contienex2 ancho (diámetro)y2 alto (diámetro)ellipseMode(CORNERS);x1 x de un vértice del rectángulo que la contieney1 y de un vértice del rectángulo que la contienex2 x del vértice opuesto del rectángulo que la contieney2 y del vértice opuesto del rectángulo que la contieneEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta el fondo de blancostrokeWeight(4); //ancho de la linea (4 pixeles)rectMode(CENTER); //(valor por defecto)ellipse(70,80,130,80);

Cuadrado / Rectángulorectangle()Modo de usorect(x1,y1,x1,y2);

ParámetrosEl uso de los parametros depende de rectMode();rectMode(CENTER);x1 x del centroy1 y del centrox2 anchoy2 altorectMode(CORNER); (valor por defecto)x1 x del vértice superior izquierdoy1 y del vértice superior izquierdox2 anchoy2 altorectMode(CORNERS);x1 x de un vérticey1 y de un vérticex2 x del vértice opuestoy2 y del vértice opuestoEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta el fondo de blancostrokeWeight(4); //ancho de la linea (4 pixeles)rectMode(CORNER); //modo en que se interpretarán los parámetros en rect()rect(10,10,120,80);

Cuadriláteroquad()Modo de Usoquad(x1,y1,x2,y2,x3,y3,x4,y4);

Parámetrosx1 x del primer vérticey1 y del primer vérticex2 x del segundo vérticey2 y del segundo vérticex3 x del tercer vérticey3 y del tercer vérticex4 x del cuarto vérticey4 y del cuarto vérticeEjemplo código

Page 3: Processing tutorial basico

size(150,150); //define el tamaño de ventanabackground(255); //pinta la ventana de blancostrokeWeight(4); //ancho de la linea (4 pixeles)quad(20,10,130,30,110,115,40,140);

Curvabezier()Modo de Usobezier(x1,y1,x2,y2,x3,y3,x4,y4);

Parámetrosx1 x de un extremoy1 y de un extremox2 x del punto de dirección de saliday2 y del punto de dirección de salidax3 x de la dirección de llegaday3 y de la dirección de llegadax4 x del otro extremoy4 y del otro extremoEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta la ventana de blancostrokeWeight(4); //ancho de la linea (4 pixeles)bezier(20,10,40,140,120,30,110,115);

Arcoarc()Esta función es similar a ellipse, con dos párametro más para indicar el inicio y el final del arco que se representará.Modo de usoarc(x1,y1,x1,y2,rad1,rad2);

ParámetrosEl uso de los primeros cuatro parámetros depende de ellipseMode();En este caso se explican los parámetro con ellipseMode(CENTER); que es el valor por defecto.ver ellipse();x1 x del centroy1 y del centrox2 ancho (diámetro)y2 alto (diámetro)rad1 punto de iniciorad2 punto de finalEjemplo códigosize(150,150); //define el tamaño de ventanabackground(255); //pinta la ventana con colore de fondo blancostrokeWeight(4); //ancho de la linea (4 pixeles)ellipseMode(CENTER); //modo de los parámetros en ellipse() y arc();arc(80,70,120,80,PI/2,0);

Tipos de datos y operaciones IntroducciónLa programación trata acerca de la cosbtrucción de algoritmos (conjunto de instrucciones que la computadora deberá seguir), durante el desarrollo de dichos algoritmos es necesario establecer algunos datos. Los datos sirven generalmente como parámetros que establecen el grado y forma con el que se ejecutan ciertas instrucciones. Para dar un ejemplo, en el siguiente algoritmo: size(150,150); //define el tamaño de ventana

background(0); //pinta la ventana de negro

set(75,75,255); //dibuja un pixel blanco

Page 4: Processing tutorial basico

todos los números que aparecen (como el 150 en la instrucción size) son datos. En este casos todos los datos que aparecen son constantes, es decir que no cambian su valor durante el transcurso del algoritmo, pero también es posible establecer datos variables. Los textos que aparecen en cada línea después de la doble barra (//) son comentarios, sirven para que el programador puedo escribir notas para guiarse sin que el compilador las tome como instrucciones,es decir que no son instrucciones ejecutables y el programa las desestima como tales.

Las VariablesLas variables son espacios de memoria que permiten almacenar datos e ir variando sus valores durante el transcurso de un programa. Una variables deber ser declarada para poder ser utilizada, luego se le puedo asignar un valor y ser utilizada:

 int miVar; //declara una variable numérica llamada "miVar" miVar = 23; //le asigna el valor 23 a la variable miVar println(miVar); //imprime el valor almacenado en miVar.

En el ejemplo anterior, en la primer línea se declaró una variable (es decir un espacio de memoria RAM) llamada "miVar", en la segunda línea se le asignó el valor numérico 23, y en la tercer línea la instrucción println nos permite ver el valor almacenado actualmente en la variable miVar. La instrucción println imprime el valor de variable, así como el resultado de operaciones, en el área negra de la interface de processing.

Tipos de datosLos datos que se pueden guardar en variables pueden ser de diferentes tipos, estos tipos responden a la naturaleza de información que pueden guardar y operar. Por ejemplo, los dostipos de datos prinicipales son los numérico y los alfanuméricos. Los primeros, como su nombre lo indica, almacenan valores numéricos, lo que permite realizar operaciones matemáticas con ellos, mientras los alfanumércos almacenan y operan caracteres, es decir letras y otros signos que sirvan para escribir.

Datos numéricosDentro de los tipos numéricos exiten dos tipos principales: los enteros y los reales (con decimales). Los enteros invluyen a los números naturales (que sirven para contar cosas: 1,2,3,...) a los negativos (-1,-2,-3,...) y al cero. Mientras que los reales incluyen a los enteros pero también a los números fraccionarios, racionales e irracionales (como la raiz cuadrada de dos o el número Pi), es decir todo lo que puede ser representado con decimales (0.14 , 15.67 , -6.8998762 ,etc.).

Los enteros se declaran con la palabara int, que viene del término ingles integer. Mientras que los reales se declaran con la palabra float, este término viene de la denominación inglesa de "coma flotante" qué es como se llamaba a estos números. Así, en el ejemplo que sigue, la primer línea declara una variable llamada "miVar" de tipo entero, la segunda declara una variable de tipo real llamada "otraVar", la tercer línea declara 3 variables "a","b" y "c" de tipo entero, y la última línea dos vriables (d y e) de tipo real.

 int miVar; float otraVar;int a,b,c;float d,e;

Cada tipo de dato define las operaciones que se pueden realizar con dichas variables. Por ejemplo, las variables enteras permiten las 4 operaciones aritméticas básicas: +,-,*,/ (es decir: suma, resta, multiplicación y división, respectivamente). Si bien la variables de tipo real tambien permite las cuatros operaciones básicas, una de la diferencias principales es que la división es diferente. Por ejemplo, la división con datos enteros devuelve valores enteros, mientras que la división real devuelve un resultado con decimales.

 int a,b,e; float c,d,f;a = 10;b = 3;c = 40.0;d = 6.0;println( a / b ); //imprime 3 println( c / d ); //imprime 6.66666666...e = a + b * 8;f = c - d * 2.0;

Page 5: Processing tutorial basico

En este ejemplo, la división entre las variables a y b devuelve como resultado un 3 (en vez de 3.3333... que sería el resultado más preciso), mientras que la división entre c y d devuelve 6.6666666.... . En las dos últimas líneas se puede ver también que es posible operar variables entre sì y asignar el resultado de dicha operación a otra variable.

El ejemplo que sigue muestra algunas formas abreviadas de escribir ciertas operaciones, como en el caso de a=a+1 que pueden ser escrito como a++:

 int x,b;x = 100;b = 5;x++; // esto equivale a x=x+1x--; // esto equivale a x=x-1 x+=b; // esto equivale a x=x+b x-=b; // esto equivale a x=x-b x*=b; // esto equivale a x=x*b x/=b; // esto equivale a x=x/b

Datos alfanuméricosLos datos alfanuméricos permiten trabajar con caracteres y cadenas de caracteres (secuencias de caracteres). Los caracteres que la computadora puede utilizar pertenecen al código ASCII (ver el tema en Wikipedia). Los dos tipos de datos alfanuméricos que se pueden usar son el tipo caracter y el tipo cadena de caracteres, la diferencia entre estos dos tipos es que el primero sólo puede almacenar un caractere mientras que el segundo puede almacenar secuencias y por ende palabras oraciones y cualquier otro tipo de secuencia . Los caracteres se declaran con la palabra char y sus valores constantes se encierran con comillas simples:

char miVar;miVar = 'b';println(miVar); imprime una b

Las cadenas de caracteres se declaran con la palabra String y sus valores constantes se encierran entre comillas dobles. La función de las comillas en ambos casos es de distinguir los valores alfanuméricos del resto del texto del algoritmo. En el ejemplo que sigue se puede ver también la única operación que permiten los tipos alfanuméricos, la concatenación, que se representa con el signo (+). En la cuarta línea se puede ver como se le asigna a la variable c la concatenación de la variable a y la variable b, es decir el valos de la variable a ("hola ") y el valor de la variable b ("mundo!!!!"), lo que sería "hola "+"mundo!!!!":

String a,b,c;a = "hola ";b = "mundo!!!!";c = a + b; println(a); imprime holaprintln(c); imprime hola mundo!!!!

Otros tipos de datosAdemás de los tipos de datos numéricos y alfanuméricos, existen otros tipos. Uno de estos, son los datos de tipo lógico, que permiten operar y almacenar valores de verdad lógica. Los datos lógicos pueden adquirir dos valores: verdadero y falso,, que en ingles se escriben: true y false. Estos tipos de datos los veremos más adelante.

Dependiendo del Lenguaje de programación que se trate, veremos que pueden existir muchos más tipos de datos primitivos. Por ejemplo en Processing existe el tipo de dato para tratar colores, llamado color.

Interactividad básicaLos modos estático y dinámicoLos siguientes ejemplos muestran como trabajar con interactividad en Processing. Este lenguaje permite trabajar e dos modos de programación, uno estático y otro dinámico. En el primer modo se escriben las instrucciones en orden descendente pero sin una organización externa, mientras que en el segundo modo de programación el código se organiza en estructuras. Las dos estructuras principales con setup() y draw() (que en versiones anteriores de Processing se llamaba loop() ).

En el ejemplo que sigue, las instrucciones que se detallan se ejecutan de arriba a abajo, y el código se ejecuta una única vez, lo que hace que el algoritmo sirva para generar una ùnica imagen estática:

Page 6: Processing tutorial basico

int a;a = 10;size(150,150);background(100);a = (a+1) % 150;rect(a,50,10,10);

A diferencia de el anterior ejempo, en el siguiente, las instrucciones mismas instrucciones estan organizadas dentro de la estructura void setup(){ ... } y la estructura void draw(){ ... } . Las instrucciones que se encuentran en el setup() sólo se ejecutan una única vez al inicio del programa. Las instrucciones que se encuentran en el draw() se ejecutan 30 veces por segundo luego de la ejecución del setup(). Fuera de estas dos estructuras se pueden escribir declaraciones de variables u otras estructuras que luego veremos.

int a;void setup(){a = 10;size(150,150);}void draw(){background(100);a = (a+1) % 150;rect(a,50,10,10);}

El uso del mousePara detectar la posición del mouse en la pantalla existen dos variables del sistema llamadas mouseX y mouseY. Estas variables representan la posición horizontal y vertical del mouse, respectivamente. No es necesario declarar estas variables dado que ya pertenecen al sistema. Con el simple hecho de referenciarlas, estas devuelven en cada momento los valores numéricos que expresan la posición del mouse. En los ejemplos siguientes se usan estas variables para dibujar un rectángulo en la posición del mouse:

Ejemplo: Siguiendo el mouse (dejando rastro)

int x,y; void setup(){ background(230); //la diferencia esta en esta linea size(200,200); } void draw(){ x=mouseX-25; y=mouseY-25; rect(x,y,50,50); }

Ejemplo: Siguiendo el mouse (sin rastro)

int x,y; void setup(){ size(200,200); } void draw(){ background(230); //la diferencia esta en esta lineax=mouseX-25; y=mouseY-25; rect(x,y,50,50); }

Otros ejemplosEjemplo: Redimensionando el rectángulo con el mouse

int x,y;void setup(){ size(200,200); rectMode(CORNER);}void draw(){ background(230); x=mouseX-100; y=mouseY-100; rect(100,100,x,y);}

Page 7: Processing tutorial basico

Ejemplo: Movimiento inverso

int x,y;void setup(){ size(200,200); //rectMode(CORNER);}void draw(){ background(230); x=200-mouseX-25; y=200-mouseY-25; rect(x,y,50,50);}

Ejemplo: Seguimientos y movimientos inverso

int x,y,x1,y1;void setup(){ size(200,200); noFill();}

void draw(){ background(230); x=200-mouseX-25; y=200-mouseY-25; x1=mouseX-25; y1=mouseY-25; rect(x,25,50,50); rect(x1,125,50,50); rect(25,y,50,50); rect(125,y1,50,50);}

Ejemplo: Multiplicación

int x,x2,x3,x4,x5,x6;void setup(){ size(600,200); noFill();}void draw(){ background(230); x=mouseX; x2=x*2; x3=x*3; x4=x*4; x5=x*5; x6=x*6; line(x,0,x,200); line(x2,0,x2,200); line(x3,0,x3,200); line(x4,0,x4,200); line(x5,0,x5,200); line(x6,0,x6,200);}

Ejemplo: División

int x,x2,x3,x4,x5,x6;void setup(){ size(600,200); noFill();

Page 8: Processing tutorial basico

}void draw(){ background(230); x=mouseX; x2=x/2; x3=x2/2; x4=x3/2; x5=x4/2; x6=x5/2; line(x,0,x,200); line(x2,0,x2,200); line(x3,0,x3,200); line(x4,0,x4,200); line(x5,0,x5,200); line(x6,0,x6,200);}

Ejemplo: Controlando colores con el mouse

int x,y,xc,yc;void setup(){ size(255,255); noStroke();}void draw(){ x=mouseX; y=mouseY; xc=255-x; yc=255-y; fill(x,y,0); rect(0,0,255,255); fill(xc,yc,255); rect(50,50,155,155); }

Estructuras de control condicionalesEstructuras de controlLos ejemplos de los anteriores apartados siguen una línea única de ejecución, es decir, no tienen posibilidad de bifurcar su línea de ejecución, ni de repetir ninguna porción de su código. Para poder dirigir, controlar, la forma en que se ejecuta el algoritmo, es decir, para controlar su flujo de ejecución, existen dos tipos principales de estructuras: las estructuras condicionales y las estructuras iterativas (repetitivas). Entendemos por estructura a un tipo de demarcación del código que nos permite organizarlo de alguna forma. En el ejemplo que sigue se ve una estructura condicional que bifurca el código en dos líneas de ejecución:

 ...void draw(){if(mouseX>200){ //comienzo estructurabackground(255); //primera línea de ejecución}else{ //separación entre las líneasbackground(0); //segunda línea de ejecución} //fin de la estructura}

Las estructuras condicionales

Las estructuras condicionales permiten bifurcar un algoritmo en función de una condición. Existen diferentes tipos de estructuras condicionales, una de las primeras que veremos es la estructura if-then que se traduce como si-entonces, lo que quiere decir es "si tal cosa entonces hacer tal otra":

 if( condición ){cuerpo de la estructura}

Page 9: Processing tutorial basico

La estructura if-then permite encerrar una porción de código entre sus dos llaves ( { } ) . Esa porción de código se ejecuta sólo si se cumple la condición que se encuentra entre los paréntesis:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( mouseX > 100 ){rect( 50 , 50 , 100 , 100 );}fill(255,0,0,150);rect(100,0,100,200);}

En el ejemplo de arriba, la instrucción "rect(..." , sólo se ejecuta cuando se cumple la condición "mouseX>200", es decir, se dibuja un rectángulo en la pantalla sólo cuando el mouse está más a la derecha de los 100 píxeles. El segundo rectángulo marca la zona en que la posición horizontal del mouse supera el valor de 100. A continuación se puede ver un diagrama de flujo que muestra en qué orden se van ejecutando las instrucciones y bajo qué condiciones:

Como muestra el diagrama de arriba el orden en que se ejecutan las instrucciones es:

1ero, se pinta el fondo de negro2do, se define el color de relleno en blanco, se pregunta 3ero, se evalua si el mouse supera la posición horizontal 1004to, sólo si la condición se cumple se dibuja el cuadrado del centro de color blanco5to, se define el color de relleno como rojo con un poco de transparencia6to, se dibuja un rectángulo del color rojo que muestra el área activa

La CondiciónEn este punto es preciso ver qué es una condición. Se considera condición a cualquier variable, constante u operación que devuelva un valor lógico. Los valores lógicos sólo pueden adoptar dos estados: verdadero o falso. En inglés los los valores lógicos verdadero o falso, se escriben true o false respectivamente. Es decir, true o false son las dos únicas constantes lógicas que existen.

Una estructura if-then se ejecuta si la condición devuelve un valor true. En el ejemplo anterior la condición era una operación de comparación ( mouseX > 100 ), las comparaciones dan como resultado un valor de verdad, como muestra el siguiente ejemplo:

 int a = 10;println( a > 5 ); //esta operación devuelve el valor true println( a > 15 ); //esta operación devuelve el valor false

Los comparativosLos operadores comparativos son los siguientes:

println( 3 > 2 ); // esto significa 3 es mayor que 2 println( 2 < 3 ); // esto significa 2 es menor que 3println( 2 == 2 ); // esto significa 2 es igual a 2println( 3 >= 2 ); // esto significa 3 es mayor o igual que 2 println( 2 <= 3 ); // esto significa 2 es menor o igual que 3 println( 3 != 2 ); // esto significa 3 es distinto a 2

En el ejemplo anterior todas las líneas devuelven true. Hay que señalar que el signo de "igual a" se escribe con un doble signo (=), no hay que confundir el (==), que es una comparación, con el (=), que es una asignación.

En los casos del mayor o igual (>=), la operación devuelve true tanto en los casos en que el primer valor es mayor al segundo, así como cuando el valor es igual al segundo, es decir que 3>=2 devuelve true y 2==2 también devuelve true. El mismo caso se dá con el signo menor o igual.

Page 10: Processing tutorial basico

La estructura if-then-elseLa estructura if-then, permite ejecutar u omitir una porción de código en función de una condición. A veces es necesario bifurcar el código en vez de omitirlo. La estructura if-then-else, que se traduciría como si-entonces-sino, quiere decir "si tal cosa entonces hacer tal cosa sino hacer tal otra":

if( condición ){se ejecuta si la condición es verdadera}else{se ejecuta si la condición es falsa}

En el ejemplo que sigue, que es una variación del primer ejemplo, se puede ver como se bifurca el algoritmo a partir de la condición. Si la condición ( mouseX > 100 ) se cumple, entonces se dibuja el cuadrado, sino se dibuja el círculo:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( mouseX > 100 ){rect( 50 , 50 , 100 , 100 );}else{ellipse( 100 , 100 , 100 , 100 );}fill(255,0,0,150);rect(100,0,100,200);}

La estructura if-then-else if-elseLa estructura if-then-else_if-else, permite evaluar varias condiciones para tomar diferentes caminos en función de cada una y por último tomar un camino si no se ha cumplido ninguna de estas:

 if( condición 1 ){se ejecuta si la condición 1 es verdadera}else if( condición 2 ){se ejecuta si la condición 1 es falsa y la 2 es verdadera}else if( condición 3 ){se ejecuta si la condición 1 y 2 son falsas y la 3 es verdadera...}else{se ejecuta si todas las condiciones anteriores son falsas}

En el ejemplo que sigue, que es una nueva variación del primer ejemplo, se puede ver como se bifurca dos veces el algoritmo a partir de dos condiciones:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( mouseX > 100 ){rect( 50 , 50 , 100 , 100 );}else if( mouseX > 50 ){ellipse( 100 , 100 , 100 , 100 );}else{triangle(50,150,100,50,150,150);}fill(255,0,0,70);rect(100,0,100,200);rect(50,0,150,200);}

Las variables booleanasAsí como existen los valores de verdad true y false, valores lógicos o booleanos (en honor a George Boole ver el tema en Wikipedia), también existen variables de tipo lógico. Estas variables se declaran con la palabra boolean y sólo pueden adquirir valores booleanos: true o false. Debido a que las comparaciones devuelven valores booleanos, se puede asignar a una variable booleana el resultado de una comparación:

 boolean a,b; int c = 10;int d = 20;

Page 11: Processing tutorial basico

a = true;b = c > d; println( a ); //imprime true println( b ); //imprime falseEn los ejemplos anteriores se podría reemplazar, en la condición, la operación de comparación por una variable booleana:

 ...boolean a; a = mouseX > 100; if( a ){…

En este caso no es muy útil, pero existen casos en que se hace necesario cambiar la condición en forma dinámica.

Las operaciones booleanasAsí como cada tipo de dato permite realizar ciertas operaciones, los datos booleanos pueden ser operados por tres operadores llamados: and (que se escribe && ), or (que se escribe || ) y not (que se escribe ! ). Estos operadores sirven para combinar más de un valor de verdad y obtener uno solo como resultado:

println( true && true ); //imprime true println( true && false); //imprime false println( false && true ); //imprime false println( false && false); //imprime false

println( true || true ); //imprime true println( true || false); //imprime true println( false || true ); //imprime true println( false || false); //imprime false

println( ! true ); //imprime false println( ! false ); //imprime true

Como muestra el ejemplo anterior, el operador and (&&) devuelve un valor true sólo cuando los dos operadores son true, caso contrario devuelve false. El operador or (||) devuelve un valor false sólo cuando ambos operadores son false, caso contrario devuelve true. Y el operador not (!) invierte el valor de verdad de true a false y viceversa.

Estos operadores sirven para evaluar varias comparaciones en una sola condición, como muestra el ejemplo siguiente, en donde las condición es cierta cuando se cumplen las dos comparaciones a la vez: cuando mouseX>100 y mouseY>100:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( mouseX > 100 && mouseY > 100){ //solo se cumple //cuando las dos condiciones son ciertasrect( 50 , 50 , 100 , 100 );}fill(255,0,0,150);rect(100,100,100,100);}

El ejemplo que sigue muestra como se usa el operador or para unir condiciones que no se superponen, dado que alcanza que se de una para ser verdadera:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( mouseX > 160 || mouseX < 40){ //basta que una de las //dos condiciones sea cierta para cumplirserect( 50 , 50 , 100 , 100 );}fill(255,0,0,150);rect(160,0,40,200);rect(0,0,40,200);}

Page 12: Processing tutorial basico

El ejemplo que sigue muestra como el operador not invierte la condición, haciendo que se cumpla cuando mouseX NO es mayor a 100:

void setup(){size(200,200);} void draw(){background( 0 ); fill(255);if( !(mouseX > 100) ){ //se cumple si NO es mayor a 100rect( 50 , 50 , 100 , 100 );}fill(255,0,0,150);rect(0,0,100,200);}

Estructuras de control condicionales (parte II)Incrementos cíclicosHasta aquí hemos visto las estructuras condicionales, ahora veremos una aplicación de estas estructuras a un problema de incremento con restricciones. Supongamos que tenemos un ejemplo como el que sigue en donde incrementamos una variable para desplazar un objeto en la pantalla: (si el objeto ya salio de pantalla haga click sobre el ejemplo para que vuelva a empezar)

int x;void setup(){size(200,200);smooth();x = 10;}void draw(){background(0,0,50);ellipse(x,100,20,20);x++;println(x);}void mousePressed(){x = 10;}

En el ejemplo anterior hemos empleado una estructura void mousePressed(), esta estructura es como setup() o draw(), con la única diferencia de que esta estructura se ejecuta cuando hacemos click con el mouse. Este ejemplo establece el valor inicial de la variable x en 10, luego en cada fotograma que se ejecuta la estructura draw() la variable x se incrementa en 1. Esto sucede hasta que se termine el programa o el usuario haga click. Es fácil ver que con un algoritmo como este, el valor de x se incrementará hasta el infinito (o por lo menos hasta valores muy grandes en función de la presición del lenguaje de prorgramación), pero en principio esto es un problema dado que si bien queremos que el objeto se desplace no queremos que se vaya de pantalla.

La forma de resolver este problema es usando un if-then que nos permita "condicionar" el incremento:

int x;void setup(){size(200,200);smooth();x = 10;}void draw(){background(0,0,50);ellipse(x,100,20,20);x++;if( x > width ){ //agregamos esta línea para condicionar el //incrementox = 0;}}

Como se puede ver en este ejemplo, el "if( x > width )" evalúa si la variable x tiene una valor mayor al ancho de la pantalla (determinado por la variable del sistema llamada width), y si esto es cierto entonces le asigna a x un cero, el equivalente a enviar al objeto al extremo izquierdo de la pantalla. Cabe aclarar que en este ejemplo hubiera sido lo mismo poner "if( x > 200 )" dado que ese es el ancho de la pantalla, pero al usar la variable width nos aseguramos de

Page 13: Processing tutorial basico

que si cambiamos el ancho en algún momento con la instrucción size() entonces no estaremos obligados a buscar los valores del ancho por todo el programa dado que width se acomoda automáticamente.

El ejemplo que sigue es análogo al anterior sólo que el objeto va de derecha a izquierda y por ende cambia la "condición de borde", teniendo que evaluar si x es menor a cero, y en caso de ser cierto le asigna el valor width, el equivalente a trasladar al objeto al borde derecho:

int x;void setup(){size(200,200);smooth();x = 100;}void draw(){background(0,0,50);ellipse(x,100,20,20);x--;if( x < 0){x = width;}}

Incremento ida y vueltaSupongamos ahora que desamos hacer que el objeto vaya ida y vuelta de un extremo al otro. Entonces no encontramos con el problema de que la condición de borde depende de en qué dirección estamos llendo, pero no sólo eso, sino que el incremento también depende de la dirección en la que se está moviendo. En el ejemplo que sigue, pusimos una variable que se encarga de señalar la dirección hacia la que nos dirigimos. El círculo comienza en el centro y se aleja hacia la izquierda o derecha en función de la variable llamada haciaLaDerecha que es booleana e indica la dirección que sigue el objeto. (si el objeto sale de pantalla haga click con el mouse y el objeto volverá al centro de la pantalla y cambiará de dirección)

int x;boolean haciaLaDerecha;void setup(){size(200,200);smooth();x = width/2; //inicia del centro haciaLaDerecha = true; //establece como dirección la derecha}void draw(){background(0,0,50);ellipse(x,100,20,20);if( haciaLaDerecha ){x++; //incrementa si haciaLaDerecha es true}else{x--; //decrementa si haciaLaDerecha es false}}void mousePressed(){x=width/2; //si se presiona el mouse vuelve al punto //central yhaciaLaDerecha = !haciaLaDerecha; //cambia de dirección}

En el ejemplo podemos ver como en función de la variable booleana llamada haciaLaDerecha, se produce un incremento (x++) o un decremento (x--). Al presionar el mouse, el objeto vuelve al centro (x=width/2), a la vez que cambia de dirección, dado que la instrucción "haciaLaDerecha = !haciaLaDerecha", cambia el valor de la variable de true a false y viceversa, funciona como un interruptor ON/OFF.

Entonces ya que establecimos con la variable haciaLaDerecha la dirección en que se mueve el objeto, entonces ahora podemos hacer que este cambie de dirección cuando este choca el borde:

int x;boolean haciaLaDerecha;void setup(){size(200,200);smooth();x = width/2; //inicia del centro haciaLaDerecha = true; //establece como dirección la //derecha}void draw(){background(0,0,50);ellipse(x,100,20,20);if( haciaLaDerecha ){

Page 14: Processing tutorial basico

x++; //incrementa si haciaLaDerecha es true if( x > width ){ //si choca el borde derechahaciaLaDerecha = false; //cambia //de dirección}}else{x--; //decrementa si haciaLaDerecha es false if( x < 0 ){ //si choca el borde izquierdohaciaLaDerecha = true; //cambia //de dirección}}}

Cuando el objeto se dirije hacia la derecha (es decir cuando la variable haciaLaDerecha es true), entonces el borde se evalúa preguntando si x es mayor que width, mientras que cuendo el objeto se dirije a la izquierda, dicha evaluación se realiza preguntado si x es menor que cero.

Aprovechando el signo positivo o negativoEl ejemplo que sigue hace lo mismo que el anterior, sólo que en vez de tener una variable booleana llamada haciaLaDerecha, tiene una variable entera llamada paso que se encarga de señalar la dirección así como de establecer el incremento o decremento. Veamos cómo hace esto:

int x;int paso;void setup(){size(200,200);smooth();x = width/2; //inicia del centro paso = 2;}void draw(){background(0,0,50);ellipse(x,100,20,20);x += paso; //cuando paso es negativo, esto es un //decrementoif( x > width || x < 0 ){ //si choca algún bordepaso *= -1; //cambia de dirección}}

La clave de este programa está en la operación "x += paso", dado que si paso es positivo (en este caso el valor 2), entonces esta operación es un incremento (y por ende el objeto se desplaza hacia la derecha), pero cuando paso tiene un valor negativo ( -2 ), entonces esta operación es un decremento (sumar a un valor otro negativo es el equivalente a restar) y por ende el objeto se dirije a la izquierda. Esta posibilidad del uso del signo para poder realizar decrementos o incrementos con una sola operación nos permite transformar el cambio de dirección en un cambio de signo, lo que se resuelve en la operación " paso *= -1", que significa multiplicar a paso por -1 (menos uno). Dado que ambos cambios de dirección son idénticos, entonces podemos evaluar una única condición que se ver si x se pasó de algún borde (x > width || x < 0).

En dos dimensionesEl ejemplo que sigue traslada estos conceptos de movimiento unidimensional a un movimiento bi-dimensional. Simplemento duplicamos las variables x y paso con otras para el movimiento vertical (y y pasoY), dado que el paso del movimiento vertical se llama pasoY, decidí cambiar el nombre de paso por pasoX. Para el límite vertical usamos la variable de sistema height que es la altura de la pantalla.

Note que cambiamos la altura con respecto a la anchura, así como el paso de avance horizontal con respecto al vertical, para mostrar que el ejemplo aún funciona:

int x,y;int pasoX,pasoY;void setup(){size(200,300);smooth();x = 87;y = 13;pasoX = 2;pasoY = 4;}void draw(){background(0,0,50);ellipse(x,y,20,20);x += pasoX; //movimiento horizontalif( x > width || x < 0 ){ //bordes horizontalespasoX *= -1; //cambia de dirección horizontal

Page 15: Processing tutorial basico

}y += pasoY; //movimiento verticalif( y > height || y < 0 ){ //bordes verticalespasoY *= -1; //cambia de dirección vertical}

Estructuras de control iterativas (repetitivas)IntroducciónCuando en un apartado anterior introdujimos el tema de las estructuras de control, se dijo que existían dos tipos principales de estructuras: las condicionales y la iterativas (o repetitivas, que es un sinónimo). Mientras que las estructuras condicionales permiten bufurcar el flujo de ejecución en función de una condición, las estructuras iterativas permiten repetir una porción de código en función de una condición.

Los ciclos for-nextLa estructura iteartiva más utilizada es la que se conoce como ciclo for-next. Esta estructura permite repetir, una cantidad determinada de veces, las instrucciones que se encuentran en su interior. Como veremos a continuación, la estructura posee tre parámetros que son: la inicialización, la condición y el incremento:

...for( inicializacion ; condición ; incremento ){cuerpo de la estructura}...

Como muestra el esquema anterior, estos tres parámetros van separados por puntos y comas (;) a diferencia de la mayoría de las instrucciones en donde los parámetros en que los parámetros van separados por comas (,). En el ejemplo a continuación se muestra una ciclo for-next utilizado para repetir una instrucción 3 veces:

size(200,200);int a = 10;for(int i=0 ; i<3 ; i++){rect( a , 75 , 50 , 50 );a += 60;}

En el ejemplo anterior, las intrucciones que se encuentran en el interior del ciclo for-next ( "rect( a , 75 , 50 , 50 )" y "a += 60") se repiten 3 veces. Es decir que este programa es el equivalente al que sigue, donde la variable a va adoptando los valores 10,70 y 130, que son las posiciones horizontales de los cuadrados:

size(200,200);int a = 10;rect( a , 75 , 50 , 50 );a += 60;rect( a , 75 , 50 , 50 );a += 60;rect( a , 75 , 50 , 50 );a += 60;

¿Cómo es que se produce esta repetición? Bueno, la forma en que la estructura se ejecuta es la siguiente:Paso 1: en el primer ciclo se ejecuta la inicialización (en este caso se declara la variable entera llamada i, y se le asigna el valor 0 ) y luego se evalua la condición (en este caso se evalua si el valor de la variable i es menor a 3) y si se cumple se ejecuta el cuerpo de la estructura .Paso 2: en el siguiente ciclo, ya no se ejecuta la inicialización, sino que se ejecuta el incremento (en este caso i++, que significa incrementar en 1 el valor de la variable i) y luego se vuelve a evaluar la condición (nuevamente i<3) y si se cumple la condición se vuelve a ejecutar el cuerpo del ciclo.Paso 3 al N-ésimo: a partir de aquí la estructura repite los mismos paso que el paso 2.En el ejemplo anterior, se inicia la variable i en 0 y como cumple la condición de ser menor a 3 (0 es menor que 3), entonces se ejecuta el cuerpo ( "rect( a , 75 , 50 , 50 )" y "a += 60"), luego se incrementa i (i++) y como i vale 1 y sigue siendo menor a 3, se vuelve a ejecutar el cuerpo, posteriormente vuelve a hacer el incremento y a evaluar la condición e i que pasa a valer 2 sigue siendo menor que 3, y se vuelve a ejecutar el cuerpo, hasta que en el siguiente incremento i pasa a valer 3 que ya no es menor a 3 (sino igual), y por ende termina el ciclo.

La condiciónEn un ciclo for-next es muy importante que la condición se dé al menos una vez, por que sino no se ingresa nunca en el ciclo:

Page 16: Processing tutorial basico

size(200,200);int a = 10;for(int i=4 ; i<3 ; i++){ //esta línea se modifico poniendo i=4rect( a , 75 , 50 , 50 );a += 60;}

En el ejemplo anterior se muestra queque la condición de i<3 nunca se cumplirá dado que el valor de i se inicia en 4, por ende nunca se ingresa al ciclo y las instrucciones que está en su interior nunca serán ejecutadas.Tanto la inicialización, como la condición y el incremento, son muy flexible y permiten utiilizar una gran rango de operaciones y valores. Por ejemplo la inicialización puede ser con valores distintos de 0 y el incremento puede ser de valores diferentes a 1 , así como otras operaciones metamáticas más allá de la suma:

for(int i=1 ; i<10 ; i+=2){ //imprime los números impares del 1 al 9 println(i);} for(int i=10 ; i>0 ; i--){ //este sería un ciclo que decrece desde 10 a 1 println(i);} for(int i=1 ; i<=256 ; i*=2){ //en este los valores se duplican desde 1println(i); // hasta 256, pasando por 2,4,8,16,32,64 y 128 }

Los bucles infinitosOtro caso importante de tener en cuenta es el caso del bucle infinito, en donde la condición nunca deja de cumplirse y por ende el ciclo nunca termina. Cuando esto sucede, generalmente queda bloqueada la máquina (colgada) y a veces es necesaria apagarla y volver a encenderla:

// si no desea colgar su computadora NO EJECUTE ESTE CÓDIGO for(int i=1 ; i>0 ; i++){ println(i);}

Como se puede ver en el caso anterior, la condición de i>0 se cumple siempre, dado qie i se inicia con el valor 1 y en cada paso se incrementa, pasando por 2, 3, 4, 5, 6, ... y así hasta el infinito.

La practicidad de los parámetrosEn el primer ejemplo, la variable a que usamos para determinar la ubicación de los cuadrados, adquiere los valores 10, 60, 130, mientras que la variable del ciclo for-next pasa por los valores 0, 1 y 2. Es posible que la misma variable i del ciclo adopte los valores que necesitamos para ubicar a los cuadrados:

size(200,200);for(int i=10 ; i<=130 ; i+=60){rect( i , 75 , 50 , 50 );}

Esto es posible por que los valores se incrementan en forma fija (saltando de a 60). Cabe aclarar que la variable del ciclo for-next puede tener cualquier nombre.

Los ciclos anidadosSupongamos que queremos hacer un tablero de ajedrez, es decir un tablero de 8x8 cuadros en donde se alternan los cuadros negros y blancos. El primer problema al que nos enfrentamos es el de hacer los 8x8 cuadros, independientemente del color que tengan. Para hacer una única hilera de cuadrados podemos seguir los ejemplos anteriores:

size(200,200);for(int i=0 ; i<8 ; i++){rect( i * 25 , 0 , 25 , 25 );}

Si quisieramos repetir 8 veces esta hilera modifiando su posición vertical, entonces debemos anidar dos ciclos for-next, haciendo que un nuevo ciclo (exterior al anterior) repita 8 veces las instrucciones necesarias para hacer una hilera:

size(200,200);for(int j=0 ; j<8 ; j++){ //este ciclo repite 8 veces al otro ciclofor(int i=0 ; i<8 ; i++){rect( i * 25 , j * 25 , 25 , 25 ); //aqui se // agrego "j * 25"}}

Page 17: Processing tutorial basico

Queda pendiente la custión de la alternacia entre cuadros negros y blancos. Para estos aprovecharemos una propiedad del table: como muestra la figura siguiente, si sumamos el número de fila más el número de columna en cada cuadro, notaremos que la alternancia entre resultados pares e impares es equivalente a la de cuadros negros y blancos en una tablero:

Por lo que aprovechamos esta propiedad y utilizamos una estructura if-then-else para pintar de negro o blanco en función de la paridad de la suma entre el número de fila y el de columna. En el ejemplo que sigue, el número de fila es j, mientras que el número de columna es i, así que para evaluar si la suma de estos valores es par, verificamos que el resto de dividir dicha suma por 2 sea 0, dado que los números pares devuelven resto 0 al ser divididos por 2. Esto se traduce a preguntar si (i+j) % 2 == 0, dado que el símbolo (%) es el resto de la división entera:

size(200,200);for(int j=0 ; j<8 ; j++){for(int i=0 ; i<8 ; i++){if( (i+j) % 2 == 0 ){ //si la suma //fila+columna es par entonces pinta de negrofill( 0 );}else{fill( 255 );}rect( i * 25 , j * 25 , 25 , 25 );}}

Ejemplo: Estructuras de Control Iterativas: For-Next

size(200,200);ellipseMode(CORNER);background(230);for(int a=0;a<200;a+=20){ ellipse(a,a,18,18);} Ejemplo: Estructuras de Control Iterativas: For-Next Anidados size(200,200);ellipseMode(CORNER);background(230);for(int a=0;a<200;a+=20){ for(int b=0;b<200;b+=20){ ellipse(a,b,18,18); }} Ejemplo: Estructuras de Control Iterativas: For-Next Anidados

void setup(){ size(200,200);}void draw(){ background(230); for(int i=0;i<=200;i+=20){ for(int j=0;j<=200;j+=20){ line(i,j,mouseX,mouseY); } }}

Más ejemplosEn los siguientes ejemplos se utilizan ciclos for-next para realizar degradé pintando pixel x pixel. Para eso utiliza una instrucción especial de Processing llamada set( ), que permite establecer el color de un pixel determinado. La instrcción set( ), tiene los siguientes parámetros:

set( x , y , color );size(200,200);color c = color( 255 , 0 , 0 ); set( 10 , 20 , c );

Los dos primeros parámetros son la posición horizontal y vertical del pixel (x e y) y el tercer parámetro es un color. El color se establece con un tipo de dato color que posee Processing. Una variable de tipo color se declara con la palabra homónima y para asignarle valores es necesario usar la función, también, color( ), que posee tres parámetros, uno para cada componente color de la paleta RGB (colores primarios de la luz o paleta aditiva del color):

Page 18: Processing tutorial basico

color c;c = color( red , green , blue );

Los valores de cada canal (red, green y blue, que son rojo, verde y azul respectivamente) pueden adoptar valores entre 0 y 255. Así, en el ejemplo que sigue se puede ver que conforme la variable i aumenta de 0 a 255 (debido al ciclo for-next), el color rojo aumenta debido a la instrucción que define el color de los pixeles ( "color c = color(i,0,0)" ), en donde i está puesta en el lugar de la componente roja:

size(255,255);for(int i=0 ; i<=255 ; i++){for(int j=0 ; j<=255 ; j++){color c = color(i,0,0);set(i,j,c);}}

El que sigue es un ejemplo interactivo del anterior sólo que fue variado para que el nivel de verde aumentara horizontalmente, el nivel de azul, verticalmente, y el valor de rojo en función de la posición horizontal del mouse.

color c;void setup(){ size(255,255);}void draw(){ for(int i=0;i<=255;i++){ for(int j=0;j<=255;j++){ c= color(mouseX,i,j); set(i,j,c); } }}

Otro ejemplo, pero en este el fondo y las figuras tienen distintos degradé que responden al mouse:

color c;void setup(){ size(250,250); noStroke(); ellipseMode(CORNER);}void draw(){ for(int i=0;i<=250;i++){ for(int j=0;j<=250;j++){ c=color(mouseX,i,j); set(i,j,c); } } for(int a=0;a<250;a+=25){ for(int b=0;b<250;b+=25){ c= color(255-mouseX,a,b); fill(c); ellipse(a+2,b+2,20,20); } }} Por último, el ejemplo que sigue aprovecha este recurso expresivo, de variar en forma independiente los degradé de las figuras y los fondos, para hacer un modesto homenaje a un gran artista que se llamó Victor Vasarely.

Page 19: Processing tutorial basico

El ejemplos que sigue tiene como detalle interesante el hecho de que el límite del ciclo for-next está determinado por una variable en vez de una cosntante, lo que significa que la cantidad de veces que se repite la estructura varía en cada ejecución del ciclo. Es importante entender que Processing ejecuta todo el ciclo antes de mostrar el fotograma, recordemos que Processing procesa por defecto 30 fotogramas por segundo, con lo que toda la ejecucióndel ciclo se produce con esta tasa. En el ejemplo que sigue, la condición del ciclo está determinada por una comparación con mouseX:

void setup(){ size(250,250); noStroke(); rectMode(CORNERS); background(0,0,255);}void draw(){ for(int i=0;i<=120 && i< mouseX;i+=10){//en esta lìnea se produce la condición fill(i*2,0,250-i*2); rect(i,i,250-i,250-i); }}

Otro ejemplo:

int px,py;void setup(){ size(250,250); noStroke(); rectMode(CENTER); background(0,0,255);}void draw(){ for(int i=0;i<=240;i+=10){ px=int(mouseX/250.0*i+(250-i)/2); py=int(mouseY/250.0*i+(250-i)/2); fill(0,i,0); rect(px,py,250-i,250-i); }} El ejemplo que sigue, dibuja una grilla de cuadrados en donde sus tamaños disminuyen conforme aumenta el número de fila o columna, determinando primero cual de estos dos números es mayor:

int mayor;size(400,400);background(0);rectMode(CENTER);noStroke();for(int i=0 ; i<20 ; i++){ for(int j=0 ; j<20 ; j++){ if(i>j){ mayor=i; }else{ mayor=j; } rect( i*20+10 , j*20+10 , 20-mayor-1 , 20-mayor-1 ); }}

El ejemplo que sigue es idéntico, pero se diferencia en que es vez de ver cuál es mayor de las dos magnitudes (el número de fila o columna), ve cuál es menor:

int menor;size(400,400);background(0);rectMode(CENTER);noStroke();for(int i=0 ; i<20 ; i++){ for(int j=0 ; j<20 ; j++){ if( i<j ){ menor=i; }else{ menor=j; } rect( i*20+10 , j*20+10 , 20-menor-1 , 20-menor-1 ); }}

Page 20: Processing tutorial basico

El ejemplo que sigue es una grilla de círculos en donde su tamaño depende de la posición horizontal del mouse. (Recuerde que algunos navegadores requieren que ud. haga click en el applet para ponerlo en foco y poder interactuar con el mismo):

void setup(){ size(400,400); ellipseMode(CENTER);}void draw(){ background(255); fill(0); float ancho=mouseX/5; for(int i=0;i<=400;i+=40){ for(int j=0;j<=400;j+=40){ ellipse(i+20,j+20,ancho,ancho); } }}

En el ejemplo que sigue el criterio es similar. El tamaño está determinado por la distancia vertical al mouse. Como la posición vertical del mouse es mouseY y el ciclo que recorre las posiciones verticales de los cículos es j, la distancia vertical está determinada por la operación: abs(mouseY-j) En donde la función abs( ) significa el valor absoluto que es la magnitud de un número desprovisto de signo, es decir que el resultado siempre es positivo sin importar de que el signo del resultado de la resta mouseY-j dé negativo:

void setup(){ size(400,400); ellipseMode(CENTER);}void draw(){ background(255); fill(0); for(int j=0;j<=400;j+=40){ float ancho=abs(mouseY-j)/5; for(int i=0;i<=400;i+=40){ ellipse(i+20,j+20,ancho,ancho); } }}

Números pseudo-aleatoriosEl azar y los números pseudo-aleatoriosEn la computación no existen los números al azar dado que la computadoras son máquinas "idealmente" determinista, existen varios factores físicos que agregan un factor de aleaoriedad a las computadoras, pero en principio las computadoras son deterministas. Debido a esto y a la necesidades que surgen de disponer de valores aleatorios, existen funciones de números pseudo-aleatorios que nos permiten escapar del determinismo computacional. Estas funciones son capaces de generar secuencias de números con patrones análogos a los números aleatorios.En Processing la función que permite generar números pseudo-aleatorios se llama random( ) y puede usar uno o dos parámetros. Si usa uno, la función arroja números cada vez que se la invoca, restringiendo estos valores entre cero y el valor del parámetros. En el ejemplo siguiente la función random( ) arroja valores entre 0 y 10:

void setup(){}void draw(){float a = random(10);println( a );}

Estos valores pueden ser utilizados para obtener parámetros como la posición de un rectángulo en la pantalla:

void setup(){size(200,200);background(0);fill(100,100,255,100);}void draw(){rect( random(width) , random(height) , 20 , 20 );}void mousePressed(){background(0);}

Page 21: Processing tutorial basico

En este ejemplo las funciones random(width) y random(height) devuelven valores pseudo-aleatorios para la posición horizontal (entre cero y el ancho de la pantalla) y para la posición vertical (entre cero y el alto de la pantalla). Mientras no se presione el mouse, el draw( ) acumula cuadrados en la pantalla.

Límite superior e inferiorTambiém es posible restringir el límite inferior y superior de la función random( ) usando dos parámetros: En el ejemplo que sigue, la función random(10,20) devuelve valores pseudo-aleatorios entre 10 y 20:

void setup(){}void draw(){float a = random(10,20);println( a );}

Esto es útil en casos como el del ejemplo que sigue, en el que queremos que los números de la secuencia ronden por las valores de la posición horizontal y vertical del mouse:

int col;void setup(){size(400,400);background(0);colorMode(HSB); col = 0;}void draw(){col = (col+1) % 256;fill(col,255,255,100);ellipse(random(mouseX-30, mouseX+30) ,random(mouseY-30,mouseY+30) , 20 , 20 );}void mousePressed(){background(0);}

En este ejemplo las funciones random( mouseX-30 , mouseX+30 ) y random( mouseY-30 , mouseY+30 ) devuelven valores al pseudo-aleatorios dentro de los un rango de 30 píxeles verticales y horizontales del mouse. Cuando se presiona el botón, se ejecuta el background(0) que pinta el fondo de negro.La forma en que se suceden cíclicamente los colores es por el uso de la paleta HSB, Processing permite usar esta paleta cuya sigla significa Hue, Saturation y Brightness (Tinte, Saturación y Brillo). Con la instrucción colorMode(HSB) se determina que se usara la paleta HSB (caso contrario sería colorMode(RGB) para la paleta RGB). Usando esta paleta las instrucciones de pintado, como fill( ) usan 3 o 4 parámetros: tinte, saturación, brillo y opacidad (en caso de usar 4 parámetros). Así la variable llamada col y que tiene un incremento cíclico dada la operación "col = (col+1) % 256", permite ir cambiando el tinte.

El ruidoEl ejemplo que sigue utiliza la función random( ) para agregarle ruido de desenfoque a la imagen. Para ello, imprime la imagen pixel por pixel pero el color lo toma de otro pixel ligeramente vecino a este. Para trabajar con los pixeles de la imagen usa un tipo de datos de Processing llamado PImage que permite levantar un jpg. (con la función loadImage( ) ), imprimirla en pantalla con la instrucción image( ), así como leer el color de cada uno de sus píxeles con la función get( ). El nivel de ruido depende de la posición vertical del mouse: PImage imagen; // tipo PImage para cargar imágenesvoid setup(){ size(200,300); imagen = loadImage("rana.jpg"); //carga un jpg background(0); //pinta de negro image(imagen, 0, 0); //imprime la imagen }void draw(){ float des = (height-mouseY) / 20; //determina el nivel de desenfoque en función de la posición vertical del mouse for(int x=0 ; x<200 ; x++){ //recorre horizontalmente for(int y=0 ; y<150 ; y++){ //recorre verticalmente color este; //declara la variable este de tipo color este = imagen.get( x+int( random(-des,des) ) , y+int( random(-des,des) ) ); //toma el color de un pixel con un nivel de desenfoque set( x , y+150 , este ); //imprime el color del pixel tomado } }}

Page 22: Processing tutorial basico

El desenfoque se produce por que en vez de tomar el color del pixel que le corresponde se lo desplaza ligeramente a través de número pseudo-aleatorios, esto sucede en la instrucción:

este = imagen.get( x+int( random(-des,des) ) , y+int( random(-des,des) ) );

En donde imagen.get( x , y ) lee el color del pixel x,y. En este caso en vez de x se le pasa como parametro:

x+int( random(-des,des) )

Que combina la función int( ) que transforma los valores reales de la función random( ) en valores enteros. Cuanto más grande sea el valor de la variable llamada des, mayor será el desenfoque que produce.

La aleatoriedad como recurso expresivoEl ejemplo que sigue aprovecha el random( ) como un recurso expresivo. En cada vuelta de animación, elige un pixel al azar de la imagen, captura su color y luego imprime un rectángulo con una tamaño decidido al azar y con el mismo color (más transparente) que el pixel original. Si presiona el mouse el procedimiento se reinicia:

 PImage imagen; // tipo PImage para cargar imágenesvoid setup(){ size(400,450); imagen = loadImage("rana.jpg"); //carga un jpg noStroke(); rectMode(CENTER); background(0); //pinta de negro image(imagen, 0, 0); //imprime la imagen }void draw(){ float des = (height-mouseY) / 20; //determina el nivel de desenfoque en función de la posición vertical del mouse color este; //declara la variable este de tipo color int x = int( random(200) ); //toma una posición horizontal al azar int y = int( random(150) ); //toma una posición vertical al azar este = imagen.get( x , y ); //toma el color del pixel elegido fill( red(este) , green(este) , blue(este) , 100 ); //usa ese color como relleno dándoles cierta transparencia stroke(este); //usa ese color de contorno float lado = random(3,20); //elige el tamaño del cuadrado para pintar el pixel rect( x * 2 , y * 2 +150, lado , lado ); //pinta el pixel duplicando el tamaño del dibujo}void mousePressed(){ background(0); //pinta de negro image(imagen, 0, 0); //imprime la imagen }

 

ArreglosIntroducciónComo vimos en los apartados anteriores, las estructuras iterativas permiten repetir un proceso una gran cantidad de veces, en contraste, cuando se desea realizar un tratamiento homogéneo sobre una gran cantidad de información, las variables, como se han visto hasta aquí, son insuficientes. Esto es debido a que cuandosi desea repetir un procesos sobre una gran cantidad de variables es necesario recurrir a estas haciendo referencia a diferentes nombres, lo que imposibilita utilizar una estructura repetitiva. Por ejemplo, el siguiente es un programa para realizar un promedio de un alumno: float calificacion1 = 9.5;float calificacion2 = 7;float calificacion3 = 5;float total = 0;int cantidad = 3;total += calificacion1;total += calificacion2; total += calificacion3; float promedio = total/cantidad;

Si la cantidad de calificaciones a ser promediadas fuesen muchas (por ejemplo 500) el anterior procedimiento no sería aplicable. En una caso como este sería deseable contar con algún tipo de variable que a partir de un único identificador

Page 23: Processing tutorial basico

(nombre de la variable) permitiese acceder a gran cantidad de información para der el mismo tratamiento a toda esta información.

Los arreglosLos arreglos (ver definición en wikipedia) son variables que permiten acceder a una gran cantidad a partir de una único identificador y un índice. Los arreglos pueden ser de varias dimensiones en función de la cantidad de índices que utilizan. Los arreglos de una dimensión son llamados vectores, los de dos dimensiones se llaman matrices, los de tres o más dimensiones se llaman tensores. Los arreglos además de ser inicializados, deben ser dimensionados, asignándoles una extensión, es decir la cantidad de celdas de memoria que utilizará: float[] calificacion; //inicializacion del arreglocalificacion = new float[100]; //dimensión del arreglocalificacion[0] = 9.5; //asignacion de la primer celda calificacion[1] = 7.0; //asignacion de la segunda celda …

También es posible dimensionar y asignar datos en un mismo paso, como se muestra en el siguiente ejemplo: // inicializacion, dimensión// y asignaciones del arreglofloat[] calificacion = { 9.5 , 7 , 6.5 , 8 , 10 }; float total = 0;int cantidad = calificacion.length();for( int i=0 ; i<cantidad ; i++ ){ • total += calificacion[ i ];}float promedio = total/cantidad;println( "El promedio es " + promedio );

En la tercer línea del ejemplo anterior, se declara el arreglo al mismo tiempo que se le asignan 5 datos ( 9.5 , 7 , 6.5 , 8 y 10 ) lo que determina la extensión de este arreglo ( 5 ). La función length (en la quinta línea) retorna la cantidad de celdas que tiene el arreglo, en este caso, obviamente 5. Las celdas en el arreglo se numeran desde el índice 0 (cero) hasta la cantidad menos uno (4 en este caso), que son justamente los valores que adquiere la variable i en el ciclo for.

Un ejemplo interactivoEl ejemplo que sigue permite generar círculos con el mouse, haciendo click en el fondo se genera un nuevo círculo, y cuando se hace click sobre un círculo ya creado, se le modifica el color y se lo arrastra. float[] x , y , tinta , radio ; //declaracion de los arreglos// necesarios para dibujar los círculos: la posición -x,y-// el color -la tinta- y el tamaño -radio-int limite; //variable para definir el limite de los arreglosint cantidad; //variable para contar los circulosvoid setup(){ size(400,400); // INICIALIZAR LA MEMORIA limite = 50; //se define que la cantidad limite de circulos es de 50 cantidad = 0; //se inicia la cantidad de circulos en cero x = new float[limite]; //declara los arreglos con 50 posiciones de memoria cada uno y = new float[limite]; tinta = new float[limite]; radio = new float[limite]; colorMode(HSB); noStroke(); smooth();}void draw(){ background(240); if( mousePressed ){ //verifica si se presionó el mouse boolean tocoAlguno = false; //se declara esta variable para verificar si el mouse toco // algún círculo // VERIFICA SI SE HIZO CLICK SOBRE UN CÍRCULO YA EXISTENTE for( int i=0 ; i<cantidad ; i++ ){ //recorre los círculos existentes if( dist( x[i] , y[i] , mouseX , mouseY ) < radio[i] ){ //revisa en cada círculo // para ver si el cursor está dentro del círculo //CAMBIAR EL ASPECTO DEL CÍRCULO SELECCIONADO x[i] = mouseX; // entonces actualiza la posición del círculo en función del mouse y[i] = mouseY; tinta[i] = ( tinta[i] + 1 ) % 255; // incrementa la tinta tocoAlguno = true; // pone la variable en "true" para especificar que un círculo // fue tocado break; // rompe el ciclo for

Page 24: Processing tutorial basico

} }

//SI NO TOCÓ NINGÚN CÍRCULO if( ! tocoAlguno && cantidad<limite ){ // si no tocó ningún círculo // y todavía existen lugares pendientes entonces crea uno nuevo //ALMACENAR EN MEMORIA UN NUEVO CÍRCULO x[cantidad] = mouseX; // crea el círculo en la posicion del mouse y[cantidad] = mouseY; tinta[cantidad] = random(255); // le asigna una tinta al azar radio[cantidad] = random(20,80); // le asigna un tamaño al azar cantidad++; // incrementa la cantidad de círculos } } // DIBUJAR LOS CÍRCULOS ALMACENADOS EN MEMORIA for( int i=0 ; i<cantidad ; i++ ){ // recorre cada círculo creado para dibujarlo fill( tinta[i] , 255 , 255 , 100 ); ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 ); }}

Para poder realizar esta aplicación, se necesita algún tipo de memoria que guarde las posiciones, colores y tamaños de cada uno de los círculos que son creados para luego poder dibujarlos en forma actualizada. La estructura general de esta aplicación en pseudocodigo es la siguiente: void setup(){Inicializar la memoria}void draw(){if( mousePressed ){if( Hizo clik sobre un círculo ya existente ){Cambiar el aspecto del círculo seleccionado}if( No toco ningún circulo ){Almacenar en memoria un nuevo círculo}} Dibujar los círculos almacenados en memoria}

El esquema anterior no es código ejecutable, sino un esquema que combina código ejecutable y explicaciones literales para mostrar la estructura del programa. Luego veremos que las explicaciones literales serán reemplazadas por código ejecutable, de hecho, en el código fuente del ejemplo hay comentarios que indícan las partes correspondientes a estos literales. Si revisamos con atención el esquema anterior veremos que la idea es crear y actualizar una memoria donde se almacenan las posiciones, colores y tamaño de los círculos que hay en pantalla. Luego un parte de la estructura se encarga de dibujar en cada ciclo del void draw() a los círculos que hay almacenados hasta el momento.Cabe aclarar que la instrucción if( mousePressed ){ está preguntando "si el mouse está siendo precionado", dado que mousePressed es una variable de estado que permite saber si el mouse está siendo presionado o no. Esta variable es boolean y devuelve true cuando el mouse está siendo presionado, y false cuando no lo está.La forma en que se implementa esta memoria es utilizando arreglos. Para la realización de esta aplicación es necesario crear cuatro arreglos que sirven para almacenar la posición, color y tamaño de los círculos. Estos arreglos se declaran fuera del void setup() y del void draw() para que sean globales, es decir, para que puedan ser visto desde cualquier parte del algoritmo. Si por el contrario, fueran declarados dentro de alguna de estas estructuras (por ejemplo el void setup() ) no podrían ser accedidos desde fuera de dicha estructura. También se declaran dos variables: limite y cantidad, que son utilizadas para especificar la cantidad límite de círculos que se pueden crear (imite) y la cantidad creada hasta el momento (cantidad). El código a continuación es el necesario para inicializar la memoria : float[] x , y , tinta , radio ; int limite; int cantidad;void setup(){ size(400,400); limite = 50; cantidad = 0; x = float[limite]; y = new float[limite]; tinta = new float[limite]; radio = new float[limite]; …

La variable cantidad funciona de la siguiente manera: cuando inicia la aplicación la variable tiene valor igual a cero. Cuando el usuario hace click, si no se ha tocado ningún círculo, se genera un nuevo círculo. Se le asigna la posición tomando las coordenadas del cursor y cargándola en los arreglos x e y. El color y el tamaño se establecen asignandoles valores al azar a los arreglos tinta y radio, respectivamente. Cuando el círculo que se agrega es el primero, el valor de

Page 25: Processing tutorial basico

cantidad es cero y por lo tanto los valores del primer círculo se carga en la primer celda de los arreglos, es decir en la que tiene índice igual a cero. Pero inmediatamente después se incrementa el valor de de la variable cantidad, esto se hace con dos fines: para registrar la cantidad de círculos almacenados y para saber el siguiente lugar disponible para cargar un círculo. El siguiente código es el que sirve para almacenar en memoria un nuevo círculo : ...if( mousePressed ){ ... if( ! tocoAlguno && cantidad<limite ){ x[cantidad] = mouseX; y[cantidad] = mouseY; tinta[cantidad] = random(255); radio[cantidad] = random(20,80); cantidad++; ...

Para ilustrar lo que hace el anterior código, imaginemos el sguiente proceso: cuando la aplicación se inicia por primera vez, la variable cantidad vale cero y aún no fue ingresado ningún dato a los arreglos. El sguiente gráfico muestra los cuatro arreglos vacios y la variable cantidad con el valor cero:

Cuando el usuario hace click y no se ha tocado ningún círculo, entonces se ingresan los valores de la posición, color y tamaño en los arreglos, usando el valor de cantidad como índice, es decir se carga el índice cero de cada uno de los arreglos. Por lo que x[cantidad]=mouseX se traduce como x[0]=mouseX, y se carga el valor de la posición horizontal del mouse en la primer celda (la celda con índice cero) de X:

Luego se incrementa en uno a la variable cantidad, por lo que pasa a valor uno. En este momento la variable cantidad indica exactamente la cantidad de datos cargados por arreglo, pero también indica el valor del siguiente índice donde se cargaran los nuevos datos:

Cuando el usuario vuelve a hacer click, vuelve a cargar los datos en el índice que indica la variable cantidad, pero en este caso x[cantidad]=mouseX se traduce como x[1]=mouseX, dado que ahora el valor de cantidad es uno:

Luego vuelve a incrementar la variable cantidad que pasa a valer dos, y nuevamente muestra la cantidad de datos cargados y el próximo índice a utilizar.Dado que la variable cantidad sirve para saber, justamente, la cantidad de círculos almacenados hasta el momento, esta información es útil para recorrer los arreglos con un ciclo for a la hora de imprimir los círculos en pantalla, como muestra el código para dibujar los círculos almacenados en memoria : ...for( int i=0 ; i<cantidad ; i++ ){fill( tinta[i] , 255 , 255 , 100 ); ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 );} ...

En el código anterior la variable que recorre los índices de los arreglos, es la variable i del ciclo for. En este momento, cómo cantidad vale dos, el ciclo for le asigna a la variable i los valores cero y uno, que son casualmente los índice que estan cargados en los arreglos. Así en la instrucción ellipse( x[i] , y[i] , radio[i]*2 , radio[i]*2 ) la cuando la variable

Page 26: Processing tutorial basico

i vale cero, se traduce como ellipse( x[0] , y[0] , radio[0]*2 , radio[0]*2 ). Y dado que x[0], y[0] y radio[0] valen 56, 108 y 30, respectivamente, entonces la instrucción queda finalmente así: ellipse( 56 , 108 , 30*2 , 30*2).Por último, queda por ver cómo es que se selecciona un círculo ya existente. La forma en que se realiza esto es recorrer uno por uno los círculos y verificar si la distancia entre el mouse y el centro del círculo es menor al radio:

Para revisar la distancia, Processing tiene una función llamada dist(), a la que se le pasa 4 parámetros que son las posiciones X e Y de los dos puntos entre los que se quiere medir la distancia:

Así para revisar uno por uno las distancia del mouse a cada uno de los centros de los círculos, se usa un ciclo for que recorre con el índice i cada uno de los círculo y preguntar por la distancia al mouse: dist( x[i] , y[i] , mouseX , mouseY ) < radio[i] El código que sigue sirve para verificar si hizo clik sobre un círculo ya existente y en caso de ser así, entonces cambiar el aspecto del cículo seleccionado : ...boolean tocoAlguno = false;for( int i=0 ; i<cantidad ; i++ ){if( dist( x[i] , y[i] , mouseX , mouseY ) < radio[i] ){x[i] = mouseX;y[i] = mouseY; tinta[i] = ( tinta[i] + 1 ) % 255; tocoAlguno = true; break;}} ...

Dado que deseamos modificar un círculo por vez, es necesario cortar el cíclo for una vez que se encuentra un cículo. Esto lo hace la instrucción break. Esta instrucción interrumpe el ciclo for, por eso se ejecuta cuando el mouse cae dentro de un círculo y se actualizan los datos del círculo seleccionado.La variable tocoAlguno sirve para verificar si algún círculo fue tocado por el mouse, en principio se le asigna un valor false, que sólo es cambiado si alguno de los círculos es tocado, en cuyo caso se le asigna el valor true. Esta variable sirve para la parte que almacenar en memoria un nuevo círculo, dado que sólo crea un nuevo círculo si el mouse no toco ninguno de los existentes, esto lo puede preguntar de la siguiente manera: if( ! tocoAlguno ){

EjemplosEl siguiente ejemplo permite grabar la huella que se deja cuando se mueve el mouse. Para eso usa dos vectores llamados X e Y que son recorridos por dos contadores llamados cont e i, que sirven para mover la cabeza grabadora y la cabeza de reproducción, respectivamente:

boolean grabando; //variable que indica el estadoint[] x,y; //vectores donde se cargan las posiciones del mouseint cont,i;int contColor;

void setup(){ size(400,400); noStroke(); colorMode(HSB); grabando = false; //se inicia en modo reproducción x = new int[100000]; y = new int[100000]; cont = 0; i = 0; contColor = 0;}

void draw(){ contColor = (contColor+1) % 256; //incrementa cíclicamente de 0 a 255 fill(0,0,0,10); //pinta el fondo de color rect(0,0,width,height);//negro transparente fill(contColor,255,255,60); //pone el color de relleno de los círculos

grabando = mousePressed; //si el mouse está siendo presionado pasa a modo grabación if(grabando){

Page 27: Processing tutorial basico

ellipse(mouseX,mouseY,10,10); x[cont]=mouseX;//guarda un nuevo dato y[cont]=mouseY; cont++; //incrementa el puntero } ellipse(x[i],y[i],50,50); i++; //con esta variable recorre el reproductor if(i>=cont){ i=0; }}

El siguiente ejemplo permite dibujar rectánguloas presionando y arrastrando el mouse.

int estado,cont;int[] x1=new int[1000];int[] x2=new int[1000];int[] y1=new int[1000];int[] y2=new int[1000];int actualX1,actualY1;

void setup(){ size(400,400); rectMode(CORNERS); estado=0; cont=0;}

void draw(){ background(0); stroke(0,255,0); noFill();

rect(375,1,398,25); //dibuja line(375,1,398,25); //el boton de la esquina line(375,25,398,1); //superio derecha

fill(0,255,0,30);

for(int i=1;i<=cont;i++){ //imprime todos los rectangulos ya grabados, de color verde rect(x1[i],y1[i],x2[i],y2[i]); } if(estado==1){ //si el botón del mouse está presionado (es decir que está generando un rectangulo) stroke(0,0,255); //pone color rojo para el que se está generando fill(0,0,255,30); rect(actualX1,actualY1,mouseX,mouseY); }}

void mousePressed(){ if(mouseX>357 && mouseY<25){//si el mouse fue presionado en el cuadrado de la esquina entonces cont=0; //borra todo estado=0; } else{ estado=1; //cuando se presiona el boton estado pasa a 1 (generación) actualX1=mouseX; //guarda los datos de la actualY1=mouseY; //primer esquina del rectangulo }}

void mouseReleased(){ if(!(mouseX>357 && mouseY<25)){//si el mouse no fue presionado en el cuadrado de la esquina entonces estado=0; cont++; //cuenta un nuevo rectangulo x1[cont]=actualX1; //y agrega el nuevo rectangulo y1[cont]=actualY1; x2[cont]=mouseX; y2[cont]=mouseY; }}