Processing es un lenguaje de programación y entorno de desarrollo integrado de código abierto basado en Java, de fácil utilización, y que sirve como medio para la enseñanza y producción de proyectos multimedia e interactivos de diseño digital. Fue iniciado por Ben Fry y Casey Reas, ambos miembros de Aesthetics and Computation Group del MIT Media Lab dirigido por John Maeda.
Uno de los objetivos declarados de Processing es el de actuar como herramienta para que artistas, diseñadores visuales y miembros de otras comunidades ajenos al lenguaje de la programación, aprendieran las bases de la misma a través de una muestra gráfica instantánea y visual de la información. El lenguaje de Processing se basa en Java, aunque hace uso de una sintaxis simplificada y de un modelo de programación de gráficos.
El entorno de Processing es minimalista y muy fácil de utilizar. Cada programa de Processing se denomina Sketch. Para ejecutarlo, debemos hacer clic sobre el botón "Play".
Para comprobar cómo es un programa con Processing, podemos abrir un archivo de ejemplo y ejecutarlo. Para ello, nos vamos a "Archivo/Ejemplos" y abrimos alguno de los ejemplos incluidos con Processing. Al ejecutarlo, podemos ver el resultado del programa.
Puedes ver algunos trabajos que hicieron compañeros de otros años:
Si queremos ver el aspecto que un Sketch, podemos utilizar el menú "Sketch/Presentar" y presiotar el botón ESC cuando queremos que termine.
La carpeta donde se guardan los sketches, se llama sketchbook. La primera vez que ejecutamos Processing, se crea una carpeta donde se guardan todos los Sketches. Esta carpeta está definida en "Archivo/Preferencias". El valor que viene por defecto se puede modificar, para que aparezcan otros directorios si queremos.
Si creamos un nuevo programa con Processing, y lo guardamos con un nombre, veremos que se crea una carpeta con ese nombre dentro de la carpeta sketchbook.
Como se puede apreciar en la imagen anterior, se ha creado una carpeta para mi proyecto: mi_primer_sketch
Actividad 1. Crea un nuevo Sketch y guárdalo con tu nombre. Por ejemplo, PedroRodriguez. Después, comprueba que se ha creado la carpeta con el mismo nombre dentro de la carpeta sketchbook. Comprueba el contenido de la carpeta y deberías encontrar un archivo con extensión .pde.
Es importante que quede esto claro, ya que en muchos ejercicios deberás entregar un .pde.
Toma una captura y entrégala en la actividad Actividad 1.1: Encontrando un .PDE de Classroom
ACTIVIDAD EVALUABLE NO CALIFICABLE.
Las funciones nos permiten llevar a cabo una tarea concreta. Processing tiene muchas funciones que nos permitirán hacer crear nuestra composición. Todas las funciones tienen la siguiente forma:
nombre_función(parámetro1, parámetro2)
Una función muy importante es size. Permite indicar cuál será el tamaño de la ventana de reproducción del sketch. Podemos probar a poner un tamaño y ejecutar el sketch.
Como se puede ver, el tamaño de la ventana se corresponde con lo indicado mediante la instrucción size.
La función println es similar a la llamada System.out.println() de Java. Permite mostrar por consola mensajes para comprobar el valor de una cierta variable o un texto de control.
Los comentarios permiten escribir texto que sirve de guía al programador, para no olvidar qué se está haciendo en una parte del código. Los comentarios, al igual que en Java, pueden ser simples o multilínea.
// Ejemplo de comentario simple
/* Ejemplo de comentario
de varias líneas */
Cuando los parámetros pasados a una función no son correctos, se generará un error. También podemos cometer errores tipográficos. En cualquier caso, se generará un error y no se abrirá un mensaje de dibujo.
Por ejemplo, si escribimos lo siguiente:
Size(200,200);
se producirá un error, ya que Processing es Case-Sensitive (distingue mayúsculas de minúsculas), y la función size se escribe con minúsculas.
También se puede producir un error cuando los parámetros introducidos no son correctos. Por ejemplo:
size("a",200);
generará un error, ya que la función size espera números enteros, no caracteres.
Cuando hay varios errores en un sketch, se muestra sólo el primero.
Actividad 2. Crea un Sketch que haga las siguientes cosas:
Crear una ventana de tamaño 400x600px.
Mostrar por consola un mensaje por cada miembro del grupo, indicando vuestro nombre.
Crear un comentario al inicio del código con el nombre del/la autor/a
Toma una captura llamada Actividad 1.2: crear una ventana donde se puedan ver ambas cosas. Entrégala en Classroom
ACTIVIDAD EVALUABLE NO CALIFICABLE
CritEv 1.1. Conocer las estructuras básicas empleadas en la creación de programas informáticos.
Processing tiene una referencia muy extensa sobre las funciones que se pueden utilizar. En https://processing.org/reference/ podemos encontrar las funciones clasificadas por tipo. Por ejemplo, si eliges la categoría Shape, podrás ver el conjunto de funciones 2d Primitives.
Cuando hacemos clic sobre una de las funciones (por ejemplo, arc), vermos una página como la siguiente:
En la sección Syntax, nos indican de cuántas maneras diferentes se puede utilizar la función. En este caso hay dos formas:
arc(a, b, c, d, start, stop)
arc(a, b, c, d, start, stop, mode)
Si nos fijamos en la sección Parameters, veremos que nos indican qué clase de información son los parámetros a, b, c, d, start y stop.
a, es la coordenada X del arco. Hay que tener en cuenta que la coordenada X = 0, está a la izquierda.
b, es la coordenada Y del arco. Hay que tener en cuenta que la coordenada Y = 0, está arriba.
c, es el ancho de la elipse.
d, es la altura de la elipse.
start, indica en qué ángulo empieza a dibujarse la elipse. Si queremos podemos utilizar palabras predefinidas que se describen aquí: constantes de Processing
stop, indica en qué ángulo termina de dibujarse la elipse. Si queremos podemos utilizar palabras predefinidas que se describen aquí: constantes de Processing
Vamos a probar a escribir el siguiente programa y a ejecutarlo:
Si revisamos el código, el significado de los parámetros es el siguiente.
Por ello, en la ventana resultante obtenemos exactamente eso:
Si nos fijamos en la sección Syntax, hay un parámetro adicional llamado mode que no aparece en la lista de parámetros. A veces ocurre esto, ya que la documentación no es perfecta. Sin embargo, si nos fijamos en la descripción, veremos que indica que existen varios modos:
Si probamos añadiendo este parámetro adicional, podemos obtener diferentes resultados:
Resultado al ejecutar:
arc(0,0,200,100,0,PI+HALF_PI)
Resultado al ejecutar:
arc(0,0,200,100,0,PI+HALF_PI,PIE)
Resultado al ejecutar:
arc(0,0,200,100,0,PI+HALF_PI,OPEN);
Resultado al ejecutar:
arc(0,0,200,100,0,PI+HALF_PI,CHORD);
Actividad 3. Con lo que has entendido sobre la función arc, intenta obtener los siguientes arcos en una ventana de tamaño 600x600:
Una figura de Pacman (comecocos), generado a partir de un círculo en el centro de la imagen de radio 100px.
Un cuenco sin borde en la parte superior, generado a partir de una elipse en el centro de la imagen de 200px de ancho y 100px de alto.
Un sol poniéndose (sin bordes), generado a partir de un círculo en el centro de la imagen de radio 100px.
Toma una captura de cada uno de los programas y entrégalos en la actividad Actividad 3: pintando arcos
ACTIVIDAD EVALUABLE NO CALIFICABLE
CritEv 1.2. Construir programas informáticos aplicados al procesamiento de datos multimedia
Existen varias funciones para dibujar elementos gráficos simples de 2 dimensiones:
ellipse
arc
circle
line
point
quad
rect
square
triangle
Consulta la referencia de Processing (2d Primitives) y comprueba cómo se utiliza cada una de estas funciones.
Averigua cómo dibujar las siguientes figuras en una ventana de 600x600:
un círculo con centro en (300,200) y radio 100
un triángulo con los vértices en (300,400), (400,300) y (500,400)
un rectángulo con la esquina superior izquierda en (300,400) y un ancho de 200 y un alto de 100.
una línea con los extremos en (0,500) y (600,500)
un cuadrado con la esquina superior izquierda en (375,450) y un lado de 50
una elipse con centro en (150, 350) y un ancho de 200 y un alto de 150
Completa el dibujo.
Actividad 4. El eje de coordenadas en Processing es diferente al eje de coordenadas usado en matemáticas:
A ver qué tal te las arreglas sol@. Intenta una de las siguientes figuras dibujando varias líneas (las flechas de cota son sólo indicaciones).
Si sois dos miembros en tu grupo, elegid cada un@ dos de las figuras (diferentes).
Entrega una captura llamada Actividad 1.4: dibujando polígonos, donde se pueda ver el código fuente empleado, y la figura obtenida.
Criterios de evaluación implicados: Crit1.2
Actividad 5. Utiliza las funciones de dibujo 2D de Processing, para crear la siguiente imagen, en un panel de dibujo de 600x600:
Ten en cuenta las siguientes indicaciones:
Entrega una captura llamada Act1.5: retrato de Confucio , donde se pueda ver el código fuente y el resultado obtenido.
Criterios de evaluación implicados: C1.2. y C1.3
Todas las formas tienen un relleno gris claro de forma predeterminada. Si queremos cambiar el color de las formas (en escala de grises), podemos utilizar las siguientes funciones:
background: establece el color de fondo
fill: establece el color de relleno
stroke: establece el color de la línea
strokeWeight: establece el grosor de la línea
El color se puede indicar de dos maneras:
Un único número: El parámetro indicado corresponde a una escala de gris, donde el negro es 0 y el blanco 255. Por ejemplo:
fill(128);
Tres números (RGB): Se trata de tres números que pueden ir desde 0 hasta 255. El primero es el rojo (R), el segundo es el verde (G) y el tercer es el azul (B). Por ejemplo:
fill(255,0,0); // significa: rójo al máximo, y nada de verde y azul.
Parea elegir un color, siempre podemos utilizar un Color Picker.
Actividad 6. Utiliza las funciones anteriores para obtener una imagen como la siguiente. Ten en cuenta los siguientes detalles:
El triángulo del sombrero, la cabeza y el cuerpo tienen un trazo más grueso (de 4 píxeles).
Cualquier color que necesites puedes encontrarlo en https://g.co/kgs/pNRs7s
Entrega una captura llamada Actividad 1.6: confucio a color, donde se pueda ver el código fuente y el resultado obtenido.
Actividad extra 1. Crea un dibujo similar al siguiente utilizando lo que conoces hasta ahora:
Figuras 2D, como el arco, el círculo, la recta, el cuadrilátero, el rectángulo
El color de relleno
El color del trazo
El grosor del trazo
Entrega una captura llamada Actividad 1.Extra1: pista de baloncesto, donde se pueda ver el código fuente y el resultado obtenido.
El canal alpha permite establecer la transparencia del relleno y del contorno. Se establece con un parámetro adicional en las funciones fill y stroke.
El segundo parámetro es un número que va de 0 a 255, donde 0 es transparencia y 255 es opacidad total.
Por ejemplo:
fill(0,127) establece rellenos transparentes al 50%.
stroke(255,60) establece bordes opacos al 16%
Para practicar. El siguiente muestra tres elipses, donde todas ellas tienen nivel de gris 60 y transparencias diferentes:
una elipse opaca
una elipse con alpha 127
una elipse con alpha 50
El color se crea introduciendo tres parámetros. Las funciones utilizadas son las mismas que hasta ahora:
background(r,g,b)
fill(r,g,b)
stroke(r,g,b)
Los colores RGB también se pueden expresar como números hexadeciamales, como por ejemplo #3faa55
El canal alpha también se puede aplica sobre color.
fill(v1, v2, v3, alpha)
Para practicar. Basándonos en el ejemplo anterior, podemos obtener algo parecido a lo siguiente:
Actividad 7. Observa la siguiente imagen.
En ella puedes encontrar cuatro círculos de radio 200 con fondo de color rojo y sin bordes, sobre un fondo azul. El sketch está elaborado sobre una ventana de 600x600.
Crea un sketch similar utilizando el canal alfa. Ajusta el valor del canal alfa para conseguir un resultado lo más parecido posible.
Entrega una captura llamada Act2.7, donde se pueda ver el código fuente y el resultado obtenido.
Criterios de evaluación implicados: C1.2 y C1.3
Actividad Extra 2 (Subida de nota (+0,1)). Busca información sobre los métodos beginShape, endShape, vertex y curveVertex. Después, de entender cómo funciona, confecciona un dibujo donde se puedan apreciar los siguientes elementos:
Montañas en primer plano, de color marrón.
Montañas en segundo plano, de color marrón claro.
Un sol, que muestre un brillo degradado.
Un cielo azul degradado
Una nube de color blanco.
La siguiente imagen puede servirte de guía.
En programación existen las variables. Son palabras a las que podemos asociar un valor. Por ejemplo, podrían ser variables las siguientes:
posicionJugadorX
posicionJugadorY
anchoTanque
nombreCiudad
Leyendo el nombre de la variable, sabremos que tipo de información queremos guardar en ella.
Definición de variables
Para poder usar una variable, primero tenemos que definirla. Para definir una variable, hay que decir dos cosas:
El tipo de información que contiene (por ejemplo, puede ser de tipo numérico, textual, etc.)
Su nombre
En la siguiente línea se define una variable de tipo entero (int) llamada posicionJugadorX
int posicionJugadorX;
Las cosas que podemos hacer con una variable numérica son:
Asignarle un valor
posicionJugadorX = 100;
Realizar operaciones numéricas:
posicionJugadorX = posicionJugadorX + 1; // incrementando en 1
posicionJugadorY = posicionJugadorX + 20; // asignando a posicionJugadorY
// el valor de posicionJugadorX
// más 20
Utilizarla para dibujar:
rect(posicionJugadorX, posicionJugadorY, anchoJugador, altoJugador);
En Java (el lenguaje que usamos en Processing) hay varios tipos de datos elementales:
int (es un número entero)
float (es un número con decimales)
boolean (sólo puede tomar los valores true o false)
char (es una única letra)
String (es un texto, con varias letras)
De momento, vamos a utilizar int y float. Un número de tipo float es decimal. Observa el siguiente ejemplo:
float incrementoVelocidad = 1.1; // Definición de la variable incrementoVelocidad y asignándole 1.1
float posicionX = 100; // Definiendo la variable posicionX y asignándole 100
float posicionY = 100; // Definiendo posicionY y asignándole 100
posicionX = posicionX * incrementoVelocidad; // Multiplicando
// posicionX por incrementoVelocidad
// y asignándolo a
// posicionX
Los nombres de las variables empiezan en minúscula. Cada palabra que compone la variable deben ponerse en mayúsculas. Ejemplo: temperaturaHabitacion
Para practicar.
Ejercicio propuesto. Crea cuatro variables de tipo entero:
diametro (vale 120)
circuloX (vale 200)
circuloY (vale 360)
desplazamiento (vale 260)
Dibuja tres círculos separados horizontalmente por una distancia desplazamiento. Por ejemplo, la coordenada X del primer círculo sería (circuloX - desplazamiento), el del segundo (circuloX) y el del tercer círculo sería (circuloX + desplazamiento).
Los bucles en Processing nos permiten repetir una misma cosa muchas veces. Recuerda la actividad 8. El mismo código, se puede escribir así:
size(600,600);
noStroke();
fill(28, 10, 79,30);
int x = 0;
int y = 0;
int ancho = 600;
int alto = 600;
int repeticion = 1;
while (repeticion < 24){
x = x + 25;
rect(x,y,ancho,alto);
repeticion = repeticion + 1;
}
Copia el siguiente código, ejecútalo para ver el resultado.
size(600,600);
noStroke();
int red = 0;
int x = 0;
int y = 0;
int radio = 10;
int repeticion = 1;
while (repeticion < 120){
x = x + 5;
y = y + 5;
radio=radio+4;
red = red + 2;
fill(red,10,79,30);
circle(x,y,radio);
repeticion = repeticion + 1;
}
size(600,600);
int x1 = 0;
int y1 = 0;
int x2 = 600;
int y2 = 600;
int repeticion = 1;
while (repeticion < 120){
y1 = y1 + 5;
y2 = y2 - 5;
line(x1,y1,x2,y2);
repeticion = repeticion + 1;
}
Para paracticar:
Escribe un programa que haga lo siguiente:
Dibujar una línea con las coordenadas (100,100,100,500);
El color RGB inicial debe ser (28,10,79)
Vuelve a dibujar la línea 400 veces, de forma que cada vez que la dibujes esté un punto en X a la derecha. También, cambia el color de cada nueva línea de forma que se incremente la componente roja (R) en 1. El resultado es como sigue:
Actividad 8. Utiliza un bucle while como los anteriores para hacer lo siguiente:
Define las variables siguiente:
centroX (inicialmente vale 0)
centroY (inicialmente vale 0)
diametro (inicialmente vale 10)
Utiliza un bucle que se repita 220 veces. En cada iteración:
Se dibuja un círculo con centro (xentroX, centroY) y diámetro diametro
La posición del centro se mueve 10 puntos a la derecha y 10 puntos hacia abajo.
El diámetro se incrementa en 20 puntos.
El resultado será algo parecido a lo siguiente.
Entrega una captura donde se pueda ver el código fuente y y el resultado obtenido.
Criterios de Evaluación implicados: C1.1 y C1.2
Actividad extra 3 (subida de nota (+0.1)). Idea tu propio diseño. En este diseño debes combinar los dibujos que crean 2 figuras geométricas 2D, y emplear el bucle para modificar su posición, así como su color. Realiza pruebas hasta obtener un resultado que consideres interesante desde el punto de vista estético.
Entrega una captura donde se pueda ver el código fuente y el resultado obtenido.
Criterios de Evaluación implicados: C1.1 y C1.3
Por ejemplo:
Las funciones Setup y Draw sirven para:
Setup: inicialización de variables, tamaño de pantalla, etc.
Draw: código que se ejecuta una y otra vez (con lo que conseguimos movimiento).
Observa el siguiente ejemplo:
int x;
int y;
void setup(){
size(400,400);
x = 0;
y = 100;
}
void draw(){
background(0);
ellipse(x,y,20,20);
x++;
}
Para capturar el movimiento del ratón, podemos utilizar las siguientes variables:
mouseX
mouseY
De forma que si en el código anterior, en lugar de x e y utilizamos mouseX y mouseY, conseguimos que la elipse se dibuje donde está el ratón.
Por otra parte, la variable mousePressed nos permite saber si el botón izquierdo del ratón está pulsado. La variable mousePressed sólo puede devolver true o false. De este modo, utilizando una sentencia condicional (if) podemos conseguir hacer cosas sólo cuando el ratón está pulsado.
Para practicar. Modifica el ejercicio anterior, para poder hacer un dibujo como el siguiente:
Una sentencia condicional te permite definir condiciones que se deben cumplir para que algo se ejecute. Esto se hace con if. Observa el siguiente ejemplo:
void setup(){
size(600,600);
}
void draw(){
if (mouseX > 300){
cirecle(mouseX,mouseY,50);
}
}
También podemos especificar qué botón se está pulsando con la siguiente variable:
mouseButton
Esta variable puede devolver los valores LEFT, CENTER y RIGHT. Así, podemos hacer una comparación como la siguiente, para saber si el botón pulsado fue el derecho:
if (mouseButton == RIGHT){
...
}
if (mouseButton == CENTER){
...
}
if (mouseButton == LEFT){
...
}
Por ejemplo: escribe un programa, que dependiendo del botón del ratón pulsado, dibuje uno los siguientes elementos:
Un cuadrado
Un triángulo
Un cíuculo
Los operadores lógicos en Java son:
&& - para el operador Y
|| - para el operador O
! - para el operador NO
En ocasiones nuestras condiciones pueden ser más complejas que una comparación. Por ejemplo, imagina la siguiente especificación:
"Si el ratón está en la mitad derecha de la pantalla, y se está pulsando el botón izquierdo, entonces dibujar un círculo"
Para poder escribir esta condición necesitamos el operador lógico Y:
((mouseX > 300) Y (botón izquierdo pulsado))
El código necesario sería como sigue:
if ((mouseX > 300) && (mouseButton == LEFT)){
circle(mouseX,mouseY,30);
}
Draw es una función que se ejecuta una y otra vez. Es similar a While (de hecho, internamente, la función draw ejecuta un while que nunca termina). Imagina que quieres pintar círculos sólo cuando pulsas el botón izquierdo:
int radio;
void setup(){
size(600,600);
radio = 50;
}
void draw(){
if (mouseButton == LEFT)
circle(mouseX, mouseY, radio);
}
Actividad 9. Utilizando la función setup, draw, y las variables mouseX y mouseY realiza una composición basada en círculos. Debes dibujar un círculo en la posición del ratón que vaya aumentando su radio en 1 en cada iteración de draw. El radio debe seguir aumentando en cada nuevo círculo, hasta llegar un diámetro de 600. Cuando el diámetro llegue a 600, dejará de pintar círculos.
Entrega una captura donde se pueda ver el código fuente y y el resultado obtenido.
Criterios de Evaluación implicados: C1.1 y C1.2
Ya hemos visto el bucle while. También tenemos el bucle for. La diferencia entre ambos es la siguiente:
While: se usa cuando queremos repetir mientras se de una condición.
For: se usa cuando queremos repetir un número de veces exacto
Hasta ahora hemos usado while cuando hemos querido repetir un número de veces, pero para eso, for es más eficaz. Observa los siguientes códigos:
int contador = 0;
while (contador < 100){
x = x +10;
contador++; // es lo mismo que contador = contador + 1
}
for (int i=0; i < 100; i++){
x = x + 10;
}
Estos códigos son exactamente iguales. La diferencia es que con while usamos la variable "contador", y con for usamos la variable "i".
En la condición del for puedes ver lo siguiente: (int i = 0; i < 100; i++). Esto significa:
int i = 0 -> se declara la variable i, que valdrá inicialmente 0
i < 100 -> es la condición, y mientras i sea menor que 100, el bucle se seguirá repitiendo.
i++ -> es equivalente a i = i + 1
Acitividad 9 (bis). Si lo anterior te pareció muy fácil, prueba colorear el fondo con un degradado.
Ahora que ya sabemos leer la posición del ratón y detectar pulsaciones de botones, vamos a ver cómo utilizar esta información para crear líneas y puntos a mano alzada.
Vamos a dibujar líneas. Para ello contamos con la siguiente información:
mouseX y mouseY (posición actual del ratón).
Coordenadas (x, y) del ratón durante el fotograma anterior.
El código de partida es el siguiente:
int x, y;
void setup(){
size(600,600);
x = 0;
y = 0;
}
void draw(){
line(x,y,mouseX,mouseY);
x = mouseX;
y = mouseY;
}
Podemos detectar si una tecla ha sido pulsada mediante la variable keyPressed que valdrá true o false dependiendo de si hay una tecla pulsada. También podemos saber qué tecla se ha pulsado mediante la variable key. Observa el siguiente código:
Cuando la tecla pulsada es una flecha, el modo de detectarla el siguiente:
Actividad para practicar. Crea un programa que sólo pinte líneas cuando pulses el botón izquierdo del ratón. Controla el grosor de la línea al pulsar las teclas siguientes:
'a' - incrementa el grosor del trazo en 1
'z' - decrementa el grosor del trazo en 1
Realiza un dibujo libre.
Entrega una actividad donde se pueda ver el código fuente y el resultado obtenido.
Actividad 10. Además de lo que se propone en la actividad para practicar anterior, intenta lo siguiente: además de modificar el grosor del trazo, modifica los colores del siguiente modo:
'r' - incrementa el color rojo del trazo en 5 tonos.
't' - reduce el color rojo del trazo en 5 tonos.
'g' - incrementa el color verde del trazo en 5 tonos.
'h' - reduce el color verde del trazo en 5 tonos.
'b' - incrementa el color azul del trazo en 5 tonos.
'n' - reduce el color azul del trazo en 5 tonos.
Crea un dibujo de tema libre, combinando diferentes grosores y colores. El dibujo debe ser figurativo, es decir, debe poder interpretarse y deducir qué hay en él.
Actividad 11. El juguete Telesketch fue muy popular durante los años 80 y 90. Observa el siguiente anuncio:
Crea un programa similar, donde controles la posición del lápiz mediante las flechas "arriba", "abajo", izquierda" y "derecha".
Crea una obra artística, que tenga cierta similitud a lo que se ve en el anuncio.
NOTA: Introduce todas las mejoras que quieras (basándote en los ejercicios anteriores).
Algunas funciones que podemos hacer con Processing son las siguientes:
fill(color); // Asigna el color a la letra
textSize(tam); // Configura la fuente a tamaño tam
text("Un texto a escribir",x,y); // Escribe un texto en un área con esquina superior izquierda (x,y)
text("Un texto a escribir", x, y, w, h); // Escribe un texto en la caja definida por los puntos (x,y) y (x+w,y+h).
Los números aleatorios se pueden obtener mediante la función siguiente:
float numeroAleatorio = random(-5.0, 10.2);
Mediante números aleatorios, podemos obtener comportamientos impredecibles. Observa el siguiente código:
PVector origen;
PVector destino;
PVector sentido;
void setup(){
size(400,400);
background(0);
origen = new PVector(width/2,0);
destino = new PVector(width/2,0);
sentido = new PVector(1,1);
}
void draw(){
if (destino.x > width){
sentido.x = -1;
ellipse(destino.x,destino.y,50,50);
}
if (destino.x < 0){
ellipse(destino.x,destino.y,50,50);
sentido.x = 1;
}
if (destino.y > height){
ellipse(destino.x,destino.y,50,50);
sentido.y = -1;
}
if (destino.y < 0){
ellipse(destino.x,destino.y,50,50);
sentido.y = 1;
}
origen.set(destino);
destino.x += sentido.x*int(random(0,30));
destino.y += sentido.y*int(random(10,30));
fill(0,10);
noStroke();
rect(0,0,400,400);
stroke(100,200,250);
strokeWeight(10);
fill(100,200,250);
line(origen.x,origen.y,destino.x,destino.y);
println("("+origen.x+","+origen.y+") - ("+destino.x+","+destino.y+")");
}
Para rotar y escalar elementos, utilizaremos las siguientes funciones:
rotate(angulo); // rota los dibujos el ángulo en radianes, como por ejemplo PI/4 (45º)
scale(s); // escala los dibujos s veces. Por ejemplo scale(2.0). ¡Ojo, que también desplaza el objeto! Ver la siguiente función
translate(x,y); // nos asegura que la rotación y el escalado no desplazará el objeto
Observa el siguiente código:
float angulo;
int rojo, verde, azul;
int incrementoRojo, incrementoVerde, incrementoAzul;
void setup(){
size(1000,1000);
angulo = 0;
rojo = 0;
verde = 0;
azul = 0;
incrementoRojo = 1;
incrementoVerde = 2;
incrementoAzul = 3;
}
void draw(){
// Cambio de color
rojo += incrementoRojo;
verde += incrementoVerde;
azul += incrementoAzul;
if ((rojo > 255) || (rojo < 0))
incrementoRojo *= -1;
if ((verde > 255) || (verde < 0))
incrementoVerde *= -1;
if ((azul > 255) || (azul < 0))
incrementoAzul *= -1;
fill(rojo,verde,azul);
// Nos aseguramos de que el objeto se dibujará en esta posición
translate(mouseX,mouseY);
// Escalamos (usando la función seno, conseguimos que sea cíclico)
scale(sin(angulo)+2);
// Rotamos el dibujo
rotate(angulo);
// Dibujamos el rectángulo. El origen es negativo para que el centro del rectángulo coincida con la posición del ratón)
rect(-30,-30,60,60);
angulo += 0.1;
}
Actividad 12. Utilizando el código fuente anterior, modifícalo para que cumpla las siguientes condiciones:
Solo dibujará cuando pulses el botón izquierdo del ratón.
Si pulsas la letra 'e' dibujará elipses.
Si pulsas la letra 'c' dibujará cuadrados.
AYUDA: para recordar si debes dibujar elipses o cuadrados, puedes utilizar una variable llamada figura que contenta 0 cuando tengas que dibujar elipses y que contenga 1 cuando tengas que dibujar cuadrados.
Un ejemplo:
Entrega el código fuente con el nombre Act1.12, y una captura con el resultado obtenido.
Actividad extra 4 (subida de nota +0.1). Repite la actividad 9, pero utilizando la rotación automática, para obtener algo como lo siguiente:
Actividad Extra 5 (subida de nota +0.1). Estudia la forma de crear un mandala de 4 secciones utilizando los giros y las traslaciones de Processing. A continuación tienes un ejemplo:
Añade todo lo que se te ocurra:
Colores
Grosor
Control con el ratón
Los patrones son esquemas repetitivos que crean una cierta textura. Prueba el siguiente código:
size(600, 600);
background(20, 131, 34);
stroke(255, 155);
strokeWeight(2);
for (int y = -30; y <= height; y += 40) {
println("-----------------------------");
println(">>>> y = " + y);
for (int x = -30; x <= width; x += 50) {
println("x = " + x);
fill(255, 120);
triangle(x, y, x-30, y+90, x+30, y+90);
}
}
Como se puede ver, la clave está en utilizar un bucle donde los elementos se repitan a lo largo de la pantalla.
Otro ejemplo hecho con círculos:
int diametro;
size(600,600);
diametro = 50;
background(255);
noFill();
for (int j=0; j<=height/diametro; j++){
println("--------------------------");
println(" >>> j = " + j);
for (int i=0; i<=width/diametro; i++){
println("i = " + i);
fill(255,0,0,120);
circle(i*diametro+diametro/2,j*diametro+diametro/2,diametro);
fill(0,0,255,60);
circle(i*diametro,j*diametro,diametro);
}
}
El ejemplo anterior, con algunas modificaciones para ser algo más interactivo:
int diametro;
float grosor;
float color1, color2, color3;
void setup(){
size(600,600);
diametro = 50;
}
void draw(){
background(255);
noFill();
for (int j=0; j<=height/diametro; j++)
for (int i=0; i<=width/diametro; i++){
grosor = map(sqrt(pow(j*diametro - mouseY,2) + pow(i*diametro - mouseX,2)),0,width,0,20);
color1 = map(mouseX,0,width,0,255);
color2 = map(mouseY,0,height,0,255);
color3 = map(mouseX,0,width,0,255);
strokeWeight(grosor);
fill(color1,0,color2,30);
circle(i*diametro+diametro/2,j*diametro+diametro/2,diametro);
fill(0,color3,0,30);
circle(i*diametro,j*diametro,diametro);
}
}
Actividad para practicar. Empieza por intentar crear el siguiente patrón:
Actividad 13. Únete a otr@ compañer@ y pensad junt@s un patrón. Puedes utilizar líneas, cuadrados, círculos, elipses, etc. Dibujad en un papel el esquema que quieres pintar, y pensad cómo debe ser vuestr@ bucle for para conseguir el efecto deseado.
NOTA: Pide ayuda si no ves claros los límites del bucle for.
Criterios de evaluación implicados: C1.3 y C1.4
Antes de entrar en la parte de aplicar filtros, es necesario entender qué es un array. Un array es una variable que puede contener muchos valores (no sólo uno como hasta ahora). Podemos ver un array como una cajonera, donde cada cajón contiene un valor. La siguiente imagen representa un array de valores float:
Cada uno de los cajones tiene una etiqueta, para saber qué "cajón" quiero abrir. Los cajones son llamados posiciones del array. Vamos a crear el array de la imagen anterior:
float miArray = new float[4]; // este array tiene 4 posiciones
miArray[0] = 10.5; // Hemos insertado 10.5 dentro de la primera posición del array
// (la primera posición es la 0)
miArray[1] = 50.2; // Hemos insertado 50.2 dentro de la segunda posición del array
// (la segunda posición es la 1)
miArray[2] = 21.3; // Hemos insertado 21.3 dentro de la primera posición del array
// (la tercera posición es la 2)
miArray[3] = 12.2; // Hemos insertado 12.2 dentro de la segunda posición del array
// (la cuarta posición es la 3)
Para mostrar el valor en la posición 2, tendríamos que escribir:
println(miArray[2]); // Escribe 21.3
Para mostrar el valor en la posición 0, tendríamos que escribir:
println(miArray[0]); // Escribe 10.5
Podemos utilizar un array como cualquier otra variable. Por ejemplo:
numeros[3] = numeros[0] + 5; // Almacena en numeros[3] el valor 15.5
Para recorrer todas las posiciones de un array, lo mejor es utilizar un bucle for. Por ejemplo, supongamos que queremos sumar 10 a todos los números en un array llamado "valores":
for (int i = 0; i < valores.length; i++)
valores[i] = valores[i] + 10;
int [] xpos = new int[50];
int [] ypos = new int[50];
void setup(){
size(600,600);
for (int i = 0; i < xpos.length; i++){
xpos[i] = 0;
ypos[i] = 0;
}
}
void draw(){
background(255);
for (int i = 0; i < xpos.length - 1; i++){
xpos[i] = xpos[i+1];
ypos[i] = ypos[i+1];
}
xpos[xpos.length-1] = mouseX;
ypos[ypos.length-1] = mouseY;
for (int i = 0; i < xpos.length; i++){
noStroke();
fill(255-i*5);
ellipse(xpos[i], ypos[i], i, i);
}
}
Supongamos que queremos mostrar la tabla de multiplicar del número 6. Utilizando arrays haríamos lo siguiente:
int[] tablaDeMultiplicar = new int[10];
tablaDeMultiplicar[0] = 6*1;
tablaDeMultiplicar[1] = 6*2;
tablaDeMultiplicar[2] = 6*3;
...
tablaDeMultiplicar[9] = 6*10;
Finalmente, mostraríamos el resultado del siguiente modo:
for (int i=0; i<tablaDeMultiplicar.length; i++){
println(tablaDeMultiplicar[i]);
}
Las imágenes son matrices de píxeles, es decir, un cuadro de puntos. En la siguiente imagen podemos ver una imagen de cerca donde se apreciará mejor:
En una imagen, cada píxel incluye tres números:
la cantidad de rojo
la cantidad de verde
la cantidad de azul
Cada píxel tiene una ubicación, que viene en forma de fila y columna. A partir del número de fila y el número de columna, podemos saber el número a través del que acceder a ese píxel mediante la siguiente fórmula:
nº de píxel = columna + ancho_imagen * fila
Cuando creamos un nuevo programa con Processing, una de las cosas que hacemos es determinar el ancho y alto de la ventana. La ventana está también compuesta de píxeles, a los que accedemos normalmente mediante funciones como rect, ellipse o line.
Para cargara la matriz de píxeles de la ventana (que inicialmente es de color gris), debemos ejecutar la función siguiente:
loadPixels()
Esta función carga la matriz pixels con los píxeles de la ventana. Si queremos modificar el pixel (x,y) para asignarle el color color(255,0,0), podemos hacer lo siguiente:
loadPixels();
pixels[x + y * anchoVentana] = color(255,0,0);
Finalmente debemos ejecutar updatePixels() para que la matriz se actualice.
Por ejemplo vamos a probar este ejemplo:
void setup(){
size(500,500);
loadPixels();
}
void draw(){
int numeroPixel = mouseX + width*mouseY;
pixels[numeroPixel] = color(0,0,0);
updatePixels();
}
Al pasar por una cierta posición, vamos pintando píxeles de color negro. Parece poca cosa, pero es la base para lo siguiente.
Descarga la siguiente imagen de un león: leon.jpg
Una vez descargada, crea un proyecto, añádela y escribe el siguiente código:
PImage leon;
void setup(){
size(780,407);
leon = loadImage("leon.jpg");
loadPixels(); // Hay que hacer esto para acceder a los píxeles de la pantalla
for (int i=0; i<leon.width; i++)
for (int j=0; j<leon.height; j++)
pixels[i+leon.width*j] = leon.pixels[i+leon.width*j];
updatePixels();
}
los filtros toman cada pixel de una imagen y bajo ciertas condiciones, lo modifican. Existen muchos filtros (tantos como se nos ocurran). Por ejemplo, vamos pensar en diferentes filtros:
PImage leon;
void setup(){
size(780,407);
leon = loadImage("leon.jpg");
loadPixels();
for (int i=0; i<leon.width; i++)
for (int j=0; j<leon.height; j++){
float r = red(leon.pixels[i+leon.width*j]);
float g = green(leon.pixels[i+leon.width*j]);
float b = blue(leon.pixels[i+leon.width*j]);
if (r > 200)
pixels[i+leon.width*j] = color(255,255,255);
else
pixels[i+leon.width*j] = color(r,g,b);
}
updatePixels();
}
PImage leon;
void setup(){
size(780,407);
leon = loadImage("leon.jpg");
loadPixels();
for (int i=0; i<leon.width; i++)
for (int j=0; j<leon.height; j++){
float r = red(leon.pixels[i+leon.width*j]);
float g = green(leon.pixels[i+leon.width*j]);
float b = blue(leon.pixels[i+leon.width*j]);
pixels[i+leon.width*j] = color(g,r,b);
}
updatePixels();
}
PImage leon;
void setup(){
size(780,407);
leon = loadImage("leon.jpg");
loadPixels();
for (int i=0; i<leon.width; i++)
for (int j=0; j<leon.height; j++){
float r = red(leon.pixels[i+leon.width*j]);
float g = green(leon.pixels[i+leon.width*j]);
float b = blue(leon.pixels[i+leon.width*j]);
float brillo = (r+g+b)/3;
if (brillo > 100)
pixels[i+leon.width*j] = color(r,g,b);
else
pixels[i+leon.width*j] = color(0);
}
updatePixels();
}
Podemos redimensionar una imagen mediante la función resize:
...
imagen.resize(600,600);
...
Actividad 24. Crea un programa que aplique el filtro Threshold, ajustando el umbral según la posición Y del ratón. El siguiente vídeo muestra lo que tienes que conseguir:
Para resolver este problema debes tener en cuenta las siguietes cosideraciones:
Debes utilizar la función Draw, ya que con la función Setup no te bastará.
Cuando un pixel tiene un valor de brillo superior al umbral, debes pintar el pixel de color blanco y cuando sea inferior de color negro.
Para saber la ubicación del ratón, puedes usar la variable mouseX o mouseY. Estas variables toman valores muy superiores al brillo. Por ello puedes utilizar la función map del siguiente modo:
map(mouseX, 0, width, 0, 255)
Esta función devuelve un número acotado entre 0 y 255, dependiendo de la posición del ratón, lo que puedes usar como umbral.
Entendiendo cómo se accede a una imagen píxel a píxel, es posible crear obras de puntillismo y otras técnicas. La idea es la siguiente: imagina que tenemos la siguiente imagen:
Si leemos píxel a píxel la imagen, podemos leer su color, y reescribirlo en la ventana como otra cosa, como un punto Point o una línea Line o una letra Text, un rectángulo Rect, etc. Las posibilidades son muy variadas. La siguiente imagen muestra la idea.
Si a esta idea le añadimos aleatoriedad, escaneando aleatoriamente distintas ubicaciones de la imagen, podemos obtener algo como lo siguiente:
Después de 30 segundos
Después de 1 minuto
Después de 2 minutos
Esto mismo lo podemos hacer con cualquier otro elemento de dibujo, como puntos, letras, palabras. En el siguiente ejemplo, se ha utilizado la palabra Blade.
Después de 10 segundos
Después de 30 segundos
Después de 1 minuto
Si quieres guardar tu imagen cuando pulses (por ejemplo) la letra "g", basta con que añadas el siguiente fragmento de código al final de tu programa:
void keyPressed(){
if (key == 'a')
save("blade_puntillismo.jpg");
}
La imagen generada podrás encontrarla en la carpeta de tu proyecto.
Actividad 14. Elige una imagen sobre la que trabajar. Asegúrate de redimensionar la imagen para que no sea más grande que tu pantalla (esto lo puedes hacer con Gimp). Crea una obra a partir de la imagen, empleando para ello líneas oblícuas.
Por petición popular, vamos a escribir el minijuego de la serpiente y la manzana. Para ver cómo puedes hacerlo, sigue las siguientes indicaciones: https://docs.google.com/document/d/1Nqja_9CC3zR-JNzR1lqRqFtelWEvV33Vp1WivftmS-0/edit?usp=sharing
Actividad 15. Partiendo del código del juego de la serpiente y la manzana, amplía el código para que hayan dos serpientes. Ten en cuenta que...
La segunda serpiente se debe mover con las teclas a, w, s y d.
Si una serpiente toca a la otra, o bien a sí misma, el juego termina.
Entrega el archivo .pde en tu cuenta de Classroom.
Actividad 16. Si has terminado el juego de la serpiente, el juego LightCycle te resultará muy fácil de escribir. Este juego aparece en la película Tron. En la película, dos motos de luz (lightcycle) deben crear muros de luz, y conseguir que el oponente choque contra ellos. En el siguiente enlace tienes un vídeo donde puedes ver en qué consiste el juego: https://www.youtube.com/watch?v=cFuRPMjYKhs
Algunas modificaciones son:
En lugar de una serpiente y una manzana, hay dos serpientes (lightcycles).
Ambas serpientes crecen en cada iteración del bucle principal.
Las dos serpientes se comportan con la otra como si fuesen manzanas. Es decir, si la cabeza de una serpiente (lightcycle 1) toca alguna parte del cuerpo de la otra serpiente (lyghtcycle 2), entonces muere.
Intenta codificar este problema.
Entrega el resultado en la actividad de Classroom correspondiente.
existe una relación conceptual entre Snake y Light Cycle de Tron, aunque su desarrollo ocurrió de manera independiente.
El juego Snake tiene sus raíces en un juego de arcade de 1976 llamado Blockade, desarrollado por Gremlin industries. En Blockade, dos jugadores controlaban líneas en crecimiento que dejaban un rastro y debían evitar chocar contra ellas. La mecánica evolucionó y se popularizó como Snake, especialmente con su versión en los teléfonos Nokia a finales de los 90.
Light Cycle apareció en la película Tron (1982) y en los videojuegos derivados. En esta mecánica, los jugadores controlan motocicletas que dejan un rastro sólido detrás de ellas, similar a Blockade. El objetivo es forzar al oponente a chocar contra estos rastros.
Ambos juegos comparten la idea de un movimiento continuo en el que el jugador debe evitar chocar con obstáculos creados por sí mismo o por otros. Light Cycle claramente toma inspiración de Blockade, al igual que Snake. Sin embargo, Snake se centró en la recolección de ítems y el crecimiento de la serpiente, mientras que Light Cycle se enfocó en una mecánica competitiva de duelos.
Realizar uno o varios carteles explicativos sobre la historia del videojuego que hemos desarrollado en clase. Este cartel debe cumplir los siguientes requisitos:
Debe ser atractivo.
Debe mostrar imágenes de los videojuegos Snake, Light Cycle y Blockade.
Debe contener explicaciones que ilustren la relación entre los tres juegos.
Debe mostrar imágenes de la película Tron.
Debe contener información con parte del análisis del problema (como el uso de arrays, movimiento de la serpiente, el dibujo de un bloque, etc.) en un lenguaje que puede entender alguien que no ha programado el problema.
La realización positiva de esta presentación:
Asigna 1 punto extra a la nota trimestral.