Unidad 1
Introducción
La aleatoriedad es un concepto fundamental en la simulación de sistemas interactivos, ya que permite modelar comportamientos impredecibles y variabilidad en los sistemas. En esta unidad, explorarás cómo generar y utilizar números aleatorios en tus simulaciones, comprendiendo su importancia y aplicaciones. A través de ejemplos como los paseos aleatorios, aprenderás a implementar movimientos y comportamientos que emulan la aleatoriedad presente en la naturaleza. Este conocimiento te proporcionará las herramientas necesarias para desarrollar simulaciones más realistas y dinámicas.
¿Qué aprenderás en esta unidad?
Vas a explorar la aleatoriedad como una herramienta fundamental en la simulación de sistemas interactivos. Esta herramienta te permitirá producir comportamientos impredecibles y variabilidad.
Actividad 01
Arte generativo
Enunciado: vas a observar con detenimiento los siguientes videos y vas a reflexionar la relación que esto podría tener con tu perfil profesional:
- Generative Art Exploration Chapter I Tracing the Roots: The History of Generative Art
- Generative Art Exploration Chapter V: The Life and Work of Vera Molnár
- How To Draw With Code | Casey Reas
- Artist Spotlight | Who is Refik Anadol?
Entrega: escribe un texto corto donde expliques qué potencial crees que pueda tener el arte generativo y algorítmico en tu perfil profesional.
🚀 Tu solución:
Mi perfil profesional y el arte generativo
Mi enfoque como Ingeniera en Diseño de Entretenimiento Digital está dirigido hacia el área estética y comunicativa de las experiencias interactivas. Soy fiel creyente de que una parte fundamental del proceso creativo detrás del desarrollo de un proyecto es permitirte experimentar con ideas divertidas que te permitan conectar con lo que haces. Por ello, el arte generativo y algorítmico me llama la atención.
Aunque la idea de comunicar mis ideas a través de código no es mi mayor fortaleza, las dinámicas detrás de la creación y cómo, a partir de parámetros, fórmulas matemáticas y curiosidad se pueden construir cosas tan locas y atrayentes me emociona.
Como diseñadora, contar con conocimientos en esta área es una gran ventaja, ya que me permite ser más versátil al plantear soluciones para las necesidades de los usuarios. Además, es una fuente de inspiración para desarrollar proyectos personales que me permitan explorar mis hobbies desde nuevas perspectivas.
Actividad 02
Diseño generativo
Enunciado: vas a observar con detenimiento el siguiente video que habla acerca del diseño generativo
Recursos:
Entrega: escribe un texto corto donde reflexiones acerca de esta pregunta ¿Cómo se conecta lo anterior como mis intereses? O tal vez ¿Esto abre la puerta a la exploración de otras posibilidades?
🚀 Tu solución:
¿Cómo se conecta lo anterior con mis intereses? O tal vez ¿Esto abre la puerta a la exploración de otras posibilidades?
Bueno, mis intereses son muy variados, pero siento que, de alguna u otra manera, puedo conectarlos con proyectos creativos que involucren arte generativo. Me gusta mucho el arte abstracto y también quiero mejorar mis habilidades de ilustración. Sería increíble poder retratar animales o momentos específicos de mi vida a partir de código.
Además, me encanta la cocina, así que un recetario colaborativo no sería una mala idea. También he pensado en retomar el crochet, y sería genial recrear la textura de los tejidos de una manera divertida. Incluso podría volver a diseñar pósters, pero esta vez enfocándome en series y trabajando mejor la jerarquía del diseño.
Genuinamente veo muchas posibilidades. Aunque el código no sea mi especialidad, me encantaría experimentar con proyectos como estos, que están alineados con algunos de mis hobbies.
Investigación
Vas a indagar y a experimentar con los conceptos fundamentales de la unidad 0 del texto guía.
Actividad 03
🚀 Tu solución:
Caminatas aleatorias
-
Describe el experimento que vas a realizar.
- Qué pasaría si se crearan 2 walkers que inician en lados opuestos del lienzo de manera simultánea y son un poco más visibles que el original.
- Qué pasaría si estos dos walkers tienden a reunirse en el centro del canvas.
- Qué pasaría si después de reunirse en el centro emprenden de nuevo su camino aleatorio.
- Qué pasaría si todo lo anterioor ocurre con 8 walkers de diferentes colores.
-
¿Qué pregunta quieres responder con este experimento?
- ¿Cómo a partir de una base de código sencilla puedo crear un sistema de random walks?
-
¿Qué resultados esperas obtener?
- Espero que se forme una reunión divertida de random walks en torno al centro del canvas.
-
¿Qué resultados obtuviste?
Código modificado
let walker1, walker2, walker3, walker4, walker5, walker6, walker7, walker8;
let walker1Reversed = false;let walker2Reversed = false;
function setup() { createCanvas(640, 640); walker1 = new Walker(100, 100, color(0, 134, 255)); walker2 = new Walker(540, 540, color(255, 201,0)); walker3 = new Walker(540, 100, color(255, 251, 0)); walker4 = new Walker(100, 540, color(255, 0, 255)); walker5 = new Walker(100, 350, color (0, 255, 572)); walker6 = new Walker(540, 350, color (229,36,36)); walker7 = new Walker(350, 100, color (255, 0, 193)); walker8 = new Walker(350, 540, color (124,255,0)); background(0);}
function draw() { walker1.step(); walker1.show();
walker2.step(); walker2.show();
walker3.step(); walker3.show();
walker4.step(); walker4.show();
walker5.step(); walker5.show();
walker6.step(); walker6.show();
walker7.step(); walker7.show();
walker8.step(); walker8.show();}
class Walker { constructor(x, y, col) { this.x = x || width / 2; this.y = y || height / 2; this.color = col || color(0); this.reversed = false; }
show() { stroke(this.color); strokeWeight(5); point(this.x, this.y); }
step() { const centerX = width / 2; const centerY = height / 2; const threshold = 5; // Umbral de proximidad al centro
// Detectar si el "walker" llega al centro if (!this.reversed && abs(this.x - centerX) <= threshold && abs(this.y - centerY) <= threshold) { this.reversed = true; // Cambiar a modo de movimiento opuesto }
// Movimiento aleatorio opuesto después de llegar al centro if (this.reversed) { const choice = floor(random(4)); if (choice === 0) { this.x += 2; // Movimiento más rápido } else if (choice === 1) { this.x -= 2; } else if (choice === 2) { this.y += 2; } else { this.y -= 2; } } else { // Movimiento hacia el centro con un pequeño desvío aleatorio if (this.x < centerX) this.x += floor(random(1, 3)); else if (this.x > centerX) this.x -= floor(random(1, 3));
if (this.y < centerY) this.y += floor(random(1, 3)); else if (this.y > centerY) this.y -= floor(random(1, 3)); } }}
- ¿Qué aprendiste de este experimento?
- La construcción del resultado final fue progresiva, fui abordando una a una las curiosidades que se me presentaron y así pude entender cada una de las modificaciones que le realicé al código original. Como esta metodología me funcionó la seguiré implementando en las demás actividades
Actividad 04
Distribuciones de probabilidad
Enunciado: analiza detenidamente este ejemplo.
En tus palabras cuál es la diferencia entre una distribución uniforme y una no uniforme de números aleatorios. Modifica el código de la caminata aleatoria para que utilice una distribución no uniforme, favoreciendo el movimiento hacia la derecha.
Entrega:
- Explicación de la diferencia entre distribuciones uniformes y no uniformes.
- Código modificado y captura de pantalla de la caminata con distribución no uniforme.
🚀 Tu solución:
- Diferencia entre distribuciones uniformes y no uniformes.
- Las distribuciones uniformes hacen que las probabilidades sean constantes, mientras que con las distribuciones no uniformes, las probabilidades son variables y tiendan hacia algunos valores más que hacia otros.
Distribuciones uniformes | Distribuciones no uniforme |
---|---|
Todos los valores dentro de un rango tienen la misma probabilidad de ser generados. | Los valores se generan con diferentes probabilidades, siguiendo una función de distribución específica. |
Ejemplo: Usar random(0, 1) en p5.js genera valores donde cada número entre 0 y 1 tiene igual probabilidad. | Ejemplo: randomGaussian() en p5.js genera valores según una distribución normal (gaussiana), donde los números cercanos al promedio son más probables que los números extremos. |
Código modificado
Enlace de la simulación aquí
Después de converger en el centro tienden hacia la derecha.
let walker1, walker2, walker3, walker4, walker5, walker6, walker7, walker8;
function setup() { createCanvas(640, 640); walker1 = new Walker(100, 100, color(0, 134, 255)); walker2 = new Walker(540, 540, color(255, 201, 0)); walker3 = new Walker(540, 100, color(255, 251, 0)); walker4 = new Walker(100, 540, color(255, 0, 255)); walker5 = new Walker(100, 350, color(0, 255, 127)); walker6 = new Walker(540, 350, color(229, 36, 36)); walker7 = new Walker(350, 100, color(255, 0, 193)); walker8 = new Walker(350, 540, color(124, 255, 0)); background(0);}
function draw() { walker1.step(); walker1.show();
walker2.step(); walker2.show();
walker3.step(); walker3.show();
walker4.step(); walker4.show();
walker5.step(); walker5.show();
walker6.step(); walker6.show();
walker7.step(); walker7.show();
walker8.step(); walker8.show();}
class Walker { constructor(x, y, col) { this.x = x || width / 2; this.y = y || height / 2; this.color = col || color(0); this.reversed = false; }
show() { stroke(this.color); strokeWeight(5); point(this.x, this.y); }
step() { const centerX = width / 2; const centerY = height / 2; const threshold = 5; // Umbral de proximidad al centro
// Detectar si el "walker" llega al centro if (!this.reversed && abs(this.x - centerX) <= threshold && abs(this.y - centerY) <= threshold) { this.reversed = true; // Cambiar a modo de movimiento opuesto }
// Movimiento aleatorio no uniforme if (this.reversed) { // Favorecer el movimiento hacia la derecha usando randomGaussian() let dx = floor(randomGaussian(2, 1)); // Media de 2, desviación estándar de 1 let dy = floor(randomGaussian(0, 1)); // Movimiento vertical más distribuido this.x += dx; this.y += dy; } else { // Movimiento hacia el centro con ajuste no uniforme let dx = randomGaussian(0, 1); // Distribución centrada en 0 let dy = randomGaussian(0, 1);
// Movimiento horizontal hacia el centro if (this.x < centerX) this.x += max(1, dx); // Asegurar un mínimo movimiento else if (this.x > centerX) this.x -= max(1, -dx);
// Movimiento vertical hacia el centro if (this.y < centerY) this.y += max(1, dy); else if (this.y > centerY) this.y -= max(1, -dy); } }}
Actividad 05
Distribución Normal
Enunciado: implementa un ejemplo que genere números aleatorios con una distribución normal (gaussiana). Visualiza la distribución utilizando figuras geométricas.
Entrega:
- Código del ejemplo
- Captura de pantalla
- Una breve explicación de cómo se refleja la distribución normal en la visualización.
🚀 Tu solución:
Simulación aquí
Código de ejemplo
let burbujas = [];let ancho, alto;
function setup() { createCanvas(800, 400); ancho = width; alto = height; noStroke(); background(255);}
function draw() { background(240, 220); // Fondo con transparencia para efecto de desvanecimiento
// Generar un número aleatorio con distribución normal let num = randomGaussian(); let desviacion = 100; let media = width / 2; let x = num * desviacion + media;
// Crear una nueva burbuja let nuevaBurbuja= { x: x, y: height, radio: random(6, 12), velocidad: random(1, 3), color: color(random(100, 255), random(10, 255), random(200, 255), 120) }; burbujas.push(nuevaBurbuja);
// Actualizar y dibujar burbujas for (let i = burbujas.length - 1; i >= 0; i--) { let b = burbujas[i]; fill(b.color); ellipse(b.x, b.y, b.radio * 2);
// Movimiento hacia arriba b.y -= b.velocidad;
// Desaparecer si salen del lienzo if (b.y + b.radio < 0) { burbujas.splice(i, 1); } }}
Reflejo de la distribución normal en la visualización
- Las burbujas representan números aleatorios generados con una distribución normal (gaussiana). Su posición horizontal (x) refleja esta distribución: la mayoría de las burbujas se agrupan cerca del centro del lienzo, donde está la media, mientras que menos burbujas aparecen en los extremos, ya que los valores alejados de la media son menos frecuentes.
Actividad 06
Distribución personalizada: Lévy flight
Enunciado: realiza una simulación donde visualices un salta de Lévy.
Entrega:
- En qué consiste el concepto de Lévy flight y en qué caso sería interesante usarlo.
- Código de la simulación.
- Captura de pantalla.
🚀 Tu solución:
Lévy flight
El concepto de Levy Flight es una forma de movimiento aleatorio que combina pasos cortos frecuentes con pasos largos ocasionales. Este comportamiento es muy diferente del movimiento aleatorio clásico (como un paseo aleatorio o random walk) porque incluye “saltos largos” que ocurren de forma menos frecuente pero tienen un impacto significativo en el desplazamiento total.
🫧 Casos interesantes para usarlo:
-
Arte generativo
-
Patrones de Partículas Orgánicas: Crear simulaciones de enjambres o nubes de partículas con trayectorias impredecibles. Ejemplo: Representar un enjambre de luciérnagas donde algunas se alejan del grupo de manera ocasional.
-
Diseño de Paisajes Naturales: Generar distribuciones de árboles, rocas o elementos naturales en un terreno. Ejemplo: En un bosque generado proceduralmente, los árboles podrían agruparse en ciertas áreas con dispersos puntos lejanos que simulan rarezas naturales.
-
Pinturas Digitales Abstractas: Utilizalo para determinar la posición de trazos de pintura o gotas en un lienzo virtual. Ejemplo: Crear obras que imiten el comportamiento de tinta dispersa en papel húmedo, con salpicaduras ocasionales más grandes.
-
-
Sistemas Interactivos
-
Comportamiento de Enemigos en Videojuegos: Usalo para que enemigos en un videojuego tengan patrones de movimiento impredecibles, dificultando al jugador anticipar su trayectoria. Ejemplo: Un jefe final que combina ataques cercanos frecuentes con movimientos rápidos y lejanos para sorprender al jugador.
-
Sistemas de Dibujo Colaborativo: Implementar herramientas de dibujo digital donde las trayectorias de los pinceles tengan comportamientos orgánicos. Ejemplo: Una aplicación donde el usuario puede dibujar, pero las líneas ocasionalmente saltan a zonas inesperadas para fomentar la creatividad.
-
🌕 SIMULACIÓN
Enlace de la simulación aquí
Código
let fireflies = [];let moon;let attractToMoon = false; // Control booleano
function setup() { createCanvas(800, 800); moon = new Moon(width / 2, height / 2, 50); for (let i = 0; i < 20; i++) { fireflies.push(new Firefly(random(width), random(height))); }}
function draw() { background(10, 10, 30); moon.display();
for (let firefly of fireflies) { firefly.update(); firefly.display(); }}
// Cambiar el estado del booleano cuando el cursor esté sobre el Solfunction mouseMoved() { let d = dist(mouseX, mouseY, moon.x, moon.y); attractToMoon = d < moon.r; // Se activa si el cursor está dentro del radio del Sol}
class Moon { constructor(x, y, r) { this.x = x; this.y = y; this.r = r; }
display() { noStroke(); fill(255, 204, 0); ellipse(this.x, this.y, this.r * 2); // Simulated glow effect for (let i = 1; i < 10; i++) { fill(255, 255, 255, 100 / i); ellipse(this.x, this.y, this.r * 2 + i * 10); } }}
class Firefly { constructor(x, y) { this.pos = createVector(x, y); this.vel = createVector(0, 0); this.acc = createVector(0, 0); this.radius = random(5, 8); // Tamaño de la luciérnaga this.maxSpeed = random(2, 4); // Velocidad máxima this.color = color(0, random(200, 255), random(10, 250), 200); // Amarillo verdoso }
update() { // Aplicar Levy Flight let angle = random(TWO_PI); let step = this.levyFlight(); this.acc = p5.Vector.fromAngle(angle).mult(step);
// Aplicar fuerza central solo si attractToMoon es verdadero if (attractToMoon) { let moonForce = p5.Vector.sub(createVector(moon.x, moon.y), this.pos); moonForce.setMag(0.02); // Magnitud de la atracción al Sol this.acc.add(moonForce); }
// Actualizar velocidad y posición this.vel.add(this.acc); this.vel.limit(this.maxSpeed); this.pos.add(this.vel);
// Envolver bordes (toroidal) if (this.pos.x > width) this.pos.x = 0; if (this.pos.x < 0) this.pos.x = width; if (this.pos.y > height) this.pos.y = 0; if (this.pos.y < 0) this.pos.y = height; }
levyFlight() { let r = random(); if (r < 0.2) { // Pasos largos (ocasionales) return random(20, 50); } else { // Pasos cortos (frecuentes) return random(1, 5); } }
display() { noStroke(); fill(this.color); ellipse(this.pos.x, this.pos.y, this.radius);
// Efecto de brillo fill(this.color, random(100, 150)); ellipse(this.pos.x, this.pos.y, this.radius * 2); }}
Las “luciérnagas” se se sienten atraídas hacia la luna, así que si el cursor se ubica sobre esta habrá una fuerza externa que las atraiga a ella.
Actividad 07
Ruido Perlin
Enunciado: utiliza el ruido Perlin para generar variaciones aleatorias pero suaves. Construye una aplicación que permita visualizar lo anterior.
Entrega:
- Explica en tus propias palabras la figura 0.4: “A graph of Perlin noise values over time (left) and of random noise values over time (right)”
- Explica cómo usaste el ruido Perlin para generar las variaciones.
- El código.
- Una captura de pantalla que muestre la visualización generada.
🚀 Tu solución:
La imagen de la izquierda, que representa el ruido de Perlín, muestra un gráfico más agradable a la vista, con variaciones ligeras entre sus trazos que generan una sensación de coherencia, fluidez y suavidad, por otro lado, la imagen de la derecha representa un gráfico generado con números aleatorios, que varían con mayor frecuencia creando esta sensación de acumulación de información en la que los datos varían drásticamente entre ellos.
🌻Jardín interactivo
Enlace a la simulación aquí
Empleé el ruido de Perlin para crear un jardín interactivo. Lo primero que se presenta es un canvas con algunos insectos revoloteando, la posición de cada insecto se calcula a partir de dos valores de ruido (uno para cada eje), noise(this.noiseX) y noise(this.noiseY) que generan valores entre 0 y 1 que son escalados al ancho y alto del lienzo, respectivamente. Esto produce un movimiento continuo y sin saltos, imitando el comportamiento errático pero fluido de un insecto real.
Al hacer click sobre el canvas se dibujan en él algunas flores, el ruido de Perlin ayuda en la generación de características visuales únicas para cada flor como el color de sus pétalos, el tamaño y hasta la cantidad de pétalos, características que no varían tanto debido a los pequeños saltos generados por el mismo ruido.
Flores: Cada flor tiene características únicas pero coherentes, simulando diversidad natural en colores y formas.
Insectos: Los insectos se mueven de manera fluida y aleatoria, replicando comportamientos biológicos observados en la naturaleza.
Código
let flowers = []; // Lista de floreslet insects = []; // Lista de insectoslet noiseOffset = 0; // Offset del ruido de Perlin para generar flores únicas
function setup() { createCanvas(800, 600); background(0, 255, 236); // Color de césped // Crear insectos iniciales for (let i = 0; i < 15; i++) { insects.push(new Insect(random(width), random(height), random(0.1, 1))); }}
function draw() { background(166, 255, 242, 50); // Suavizado para simular un brillo tenue
// Dibujar flores for (let flower of flowers) { flower.grow(); flower.display(); }
// Dibujar insectos for (let insect of insects) { insect.move(); insect.display(); }}
function mousePressed() { // Crear una nueva flor en la posición del mouse flowers.push(new Flower(mouseX, mouseY, noiseOffset)); noiseOffset += 0.5; // Incrementar el ruido más significativamente}
class Flower { constructor(x, y, noiseOffset) { this.x = x; this.y = y; this.noiseOffset = noiseOffset; this.size = 0; // Tamaño inicial de la flor this.maxSize = random(20, 100); // Tamaño máximo basado en un rango aleatorio
// Ajuste para variar la cantidad de pétalos de forma más visible this.petalCount = floor(map(noise(noiseOffset), 0, 1, 5, 15));
this.petalColor = color( noise(noiseOffset) * 155, 100 + noise(noiseOffset + 1) * 155, 100 + noise(noiseOffset + 2) * 255 ); // Color basado en el ruido this.centerColor = color(255, 204, 0); // Centro amarillo cálido }
grow() { if (this.size < this.maxSize) { this.size += 0.5; // Crecimiento gradual } }
display() { push(); translate(this.x, this.y); for (let i = 0; i < this.petalCount; i++) { let angle = TWO_PI / this.petalCount * i; let petalX = cos(angle) * this.size; let petalY = sin(angle) * this.size; fill(this.petalColor); ellipse(petalX, petalY, this.size / 2, this.size); // Pétalos alargados } fill(this.centerColor); ellipse(0, 0, this.size / 2); // Centro de la flor pop(); }}
class Insect { constructor(x, y, speed) { this.x = x; this.y = y; this.speed = speed; // Velocidad de movimiento del insecto this.noiseX = random(1000); // Offset único para el movimiento en X this.noiseY = random(1000); // Offset único para el movimiento en Y }
move() { this.x = noise(this.noiseX) * width; // Movimiento horizontal suave this.y = noise(this.noiseY) * height; // Movimiento vertical suave this.noiseX += 0.01 * this.speed; // Incrementar el ruido para simular movimiento this.noiseY += 0.01 * this.speed; }
display() { fill(50, 50, 50); // Color del insecto ellipse(this.x, this.y, 10, 10); // Cuerpo del insecto fill(255); ellipse(this.x - 3, this.y - 3, 4, 4); // Ala izquierda ellipse(this.x + 3, this.y - 3, 4, 4); // Ala derecha }}
Aplicación
Vas a aplicar los conceptos con los que experimentaste en la fase de investigación para diseñar y desarrollar una aplicación interactiva en tiempo real.
Actividad 08
Diseño: exploración de la idea
Enunciado: diseña una aplicación interactiva en tiempo que utilice los conceptos que investigaste. La aplicación debe:
- Generar una pieza de arte generativo algorítmico.
- Debes usar al menos TRES conceptos.
- El contenido generado debe ser interactivo. Puedes utilizar mouse, teclado, cámara, micrófono, etc, para variar los parámetros del algoritmo en tiempo real.
Entrega:
- Un texto donde expliques tu intención de diseño.
- ¿Cómo piensas usar los tres conceptos y por qué estos?
- Reporta los referentes que usaste para inspirarte.
🚀 Tu solución:
Fiesta de partículas
El proyecto será de exploración de partículas y cómo podemos crear formas divertidas con ellas. El usuario seleccionará desde su dispositivo algunas siluetas (preferiblemente de animales marinos) y las partículas rastrearán esta imagen y tratarán de imitarla por medio de su distribución en el canvas. Además, habrá un botón llamado “Fiesta🥳” que podrá crear un efecto divertido sobre el tamñano, colores y la distribución de las partículas; y un botón “Normal” para volver a la simulación.
¿Cómo piensas usar los tres conceptos y por qué estos?
- Random Gaussean (distribución normal) —> Colores de las partículas para que se mantengan dentro de una misma gama de color.
- Random walk—> Color del fondo para generar un efecto de viveza al canvas, lo pensé como un acuario que dependiendo de la luz que reciba del sol va a tener un azul más o menos profundo y el random walk hace que el cambio de color no sea abrupto.
- Levy fligth---> Activado mediante el botón fiesta, podría crear un ambiente divertido al cambiar los colores, el tamaño y el comportamiento de las partículas con los saltos cortos frecuentes y los largos ocasionales.
Reporta los referentes que usaste para inspirarte.
Patch de partículas en cables link aquí
Cambio a modo “fiesta” inspirado en el trabajo de Emanuel :)
Actividad 09
Materialización
Enunciado: vas a implementar tu aplicación diseñada.
Entrega:
- Código de la aplicación.
- Captura del contenido generado.
- En caso de realizar alguna variación al concepto original, escribe un texto donde expliques la razón del cambio.
🚀 Tu solución:
Fiesta de partículas
Enlace del proyecto aquí
Imagen original
Imagen Modo Normal
Imagen Modo Fiesta
Código
let img;let particles = [];let imgData = [];let input;let bgColor; // Color de fondo dinámicolet fiesta = false;let buttonFiesta, buttonNormal;
function setup() { createCanvas(600, 800); background(0); input = createFileInput(handleFile); input.position(10, 10);
buttonFiesta = createButton('Fiesta'); buttonFiesta.position(10, 50); buttonFiesta.mousePressed(() => toggleFiesta(true));
buttonNormal = createButton('Normal'); buttonNormal.position(10, 90); buttonNormal.mousePressed(() => toggleFiesta(false));
// Inicializamos el color de fondo en un azul oscuro bgColor = createVector(10, 20, 80);}
function handleFile(file) { if (file.type === 'image') { img = loadImage(file.data, () => { processImage(); }); }}
function processImage() { image(img, 0, 0, width, height); loadPixels();
imgData = []; for (let x = 0; x < width; x += 4) { // Mayor precisión reduciendo el paso for (let y = 0; y < height; y += 4) { let index = (x + y * width) * 4; let brightness = pixels[index] + pixels[index + 1] + pixels[index + 2]; if (brightness < 400) { // Filtrar puntos oscuros de la imagen imgData.push(createVector(x, y)); } } }
particles = []; for (let i = 0; i < imgData.length; i++) { particles.push(new Particle(random(width), random(height), imgData[i])); }}
function draw() { updateBackground(); // Actualizar el color de fondo con random walk background(bgColor.x, bgColor.y, bgColor.z);
for (let p of particles) { p.update(); p.show(); }}
function updateBackground() { // Random walk en la gama de azules oscuros bgColor.x = constrain(bgColor.x + random(-5, 5), 0, 50); // Mantener tonos oscuros en R bgColor.y = constrain(bgColor.y + random(-5, 5), 0, 50); // Mantener tonos oscuros en G bgColor.z = constrain(bgColor.z + random(-10, 10), 50, 150); // Azul oscuro variable}
function toggleFiesta(state) { fiesta = state; if (fiesta) { // Cambiar colores a modo fiesta for (let p of particles) { p.r = random(255); p.g = random(255); p.b = random(255); } } else { // Restaurar colores y tamaños originales for (let p of particles) { p.r = constrain(randomGaussian(100, 30), 50, 200); p.g = 150; p.b = constrain(randomGaussian(255, 20), 200, 255); p.size = 3; } }}
class Particle { constructor(x, y, target) { this.pos = createVector(x, y); this.target = target; this.vel = p5.Vector.random2D(); this.acc = createVector(); this.maxSpeed = 2; this.size = 3;
// Distribución normal para el color de las partículas this.r = constrain(randomGaussian(100, 30), 50, 200); this.g = 150; this.b = constrain(randomGaussian(255, 20), 200, 255); }
update() { if (fiesta) { // Movimiento caótico con vuelo de Lévy let step = pow(random(1), -1.5); let angle = random(TWO_PI); this.vel.x = cos(angle) * step; this.vel.y = sin(angle) * step; this.size = constrain(2 + step * 3, 2, 10); // Variar tamaño con Lévy Flight } else { let force = p5.Vector.sub(this.target, this.pos); force.setMag(0.1); this.acc.add(force);
// Reducir gradualmente el tamaño si está en modo normal this.size = lerp(this.size, 3, 0.1); }
this.vel.add(this.acc); this.vel.limit(this.maxSpeed); this.pos.add(this.vel); this.acc.mult(0); }
show() { fill(this.r, this.g, this.b); noStroke(); ellipse(this.pos.x, this.pos.y, this.size, this.size); }}
Consolidación y matacognión
Ahora que has experimentado con la aleatoriedad y has aplicado estos conceptos en una pieza de arte generativo, es momento de reflexionar sobre el proceso y los resultados obtenidos.
Actividad 10
Análisis de resultados
Enunciado: revisa los resultados de las actividades de la fase APPLY. ¿Qué desafíos encontraste al aplicar los conceptos aprendidos? ¿Qué aprendiste de estos desafíos?
Entrega: descripción de los desafíos encontrados y las lecciones aprendidas durante la fase APPLY.
🚀 Tu solución:
Desafíos a los que me enfrente en la fase APPLY
-
Cuando debía aplicar los concepto aprendidos en la fase SEEK, me enfrenté a un bloqueo creativo. No sabía de qué manera divertida abordar estos temas, busqué algunas referencias pero nada me convencía del todo. La primera idea fue la de hacer un acuario con peces y burbujas que interactuaran entre sí pero no terminaba de convencerme la interacción del usuario. Finalmente, recurrí a inspirarme de proyectos hecho en Cables.gl, una página web con la que pude experimentar el semestre pasado y fue así como encontré un proyecto que me iluminó el camino.
-
Después de inspirarame, inicié a experimentar para ver si podía replicar de cierta manera la interacción de las partículas de Cables en P5.js, sin embargo, el proyecto que me inspiró contenía a las partículas en un espacio tridimensional así que tuve que modificar algunos factores para el funcionamiento de mi proyecto.
Lecciones aprendidas de la fase APPLY
- Para mí, crear diferentes versiones de una misma idea o concepto me ayuda a crear un producto final más completo y divertido.
- Aunque Cables.gl sea una plataforma diferente es una gran fuente de inspiración para explorar con el arte generativo.
Actividad 11
Conexión con Diseño de Entretenimiento Digital
Enunciado: describe cómo los conceptos de aleatoriedad, distribuciones y ruido Perlin pueden ser utilizados en el diseño de videojuegos, experiencias interactivas o animaciones. Da ejemplos concretos.
Entrega: descripción de al menos tres aplicaciones de los conceptos aprendidos en el diseño de entretenimiento digital, con ejemplos concretos.
🚀 Tu solución:
Aplicaciones de los conceptos aprendidos en experiencias interactivas
1. Ruido de Perlin: Sirve para generar texturas procedurales y elementos dinámicos que pueden emplearse en escenarios y montajes de experiencias. Los videojuegos y experiencias interactivas a menudo necesitan generar mundos dinámicos sin depender completamente de diseños predefinidos. El ruido Perlin se usa para crear terrenos, texturas y patrones naturales de manera fluida y coherente.
- Ejemplo: En una instalación interactiva con proyección en un domo, el paisaje generado responde al movimiento de los usuarios. Usando ruido Perlin, se puede modificar la topografía de montañas o la disposición de vegetación de forma suave y realista, evitando la artificialidad del ruido aleatorio puro.
2. Vuelos de Lévy
El movimiento de personajes o elementos en entornos interactivos puede beneficiarse de modelos estadísticos más complejos que la simple aleatoriedad uniforme. Un enfoque es el uso de distribuciones normales para animaciones suaves o vuelos de Lévy para movimientos caóticos e impredecibles.
- Ejemplo: En una instalación donde partículas de luz siguen a los usuarios en una pantalla interactiva, en vez de moverse de forma lineal, pueden tener variaciones usando una el vuelo de Levy, haciendo que su seguimiento parezca más divertido y dinámico.
3. Distribuciones de probabilidad
Las distribuciones de probabilidad pueden ser utilizadas para modelar el comportamiento de personajes no jugadores (NPCs), enemigos o entidades en un juego. En lugar de moverse de forma completamente aleatoria, se pueden emplear distribuciones normales o personalizadas para definir patrones de movimiento más realistas.
- Ejemplo: En juegos de sigilo como The Last of Us, las patrullas enemigas no siguen un patrón fijo, sino que su comportamiento es influenciado por distribuciones de probabilidad que definen con qué frecuencia revisan ciertas áreas o cómo reaccionan ante estímulos del entorno.
Actividad 12
Reflexión sobre el proceso de aprendizaje
Enunciado: reflexiona sobre tu propio proceso de aprendizaje durante esta unidad. ¿Qué estrategias te resultaron más efectivas para comprender los conceptos? ¿Qué podrías mejorar en futuras unidades?
Entrega:
- Descripción de las estrategias de aprendizaje utilizadas y su efectividad.
- Planteamiento de mejoras para futuras unidades.
🚀 Tu solución:
Estrategias de aprendizaje utilizadas
- Crear analogías entre los conceptos y actividades cotidianas para comprenderlos de manera más sencilla.
- Practicar los conceptos con temas que me interesen, por ejemplo: quisiera comenzar a dibujar animales marinos, ¿cómo podría hacerlo con los conceptos que estoy aprendiendo?
- Pensar en buscar referencias divertidas que al verlas me haga querer intervenirlas a mi manera.
Planteamiento de mejoras para futuras unidades.
- Para futuras unidades quisiera seguir haciendo proyectos divertidos relacionados con mis hobbies, así que un consejo para mi yo del futuro es buscar referencias visuales que se salgan de mi zona de confort o sitios recurrentes para así poder experimenta y arriesgarme más.
Actividad 13
Autoevaluación
Enunciado: evalúa tu nivel de comprensión de los conceptos de la unidad en una escala del 1 al 5 (1: Nada de comprensión, 5: Dominio completo). Justifica tu autoevaluación con ejemplos concretos de tu trabajo en la unidad. Identifica áreas donde necesitas reforzar tu aprendizaje.
Entrega:
- Autoevaluación con justificación y ejemplos concretos.
- Identificación de áreas de mejora.
🚀 Tu solución:
Escala de comprensión
- Me asigno un nivel de 4, comprendo los conceptos y puedo aplicarlos a proyectos de manera dinámica aprovechando los beneficios de cada uno pero personalemnte considero que debo practicar un poco más en otros proyectos similares al planteado en la actividad 8 para así sentirme más confiada a la hora de aplicarlos en mis proyecto. El concepto que tal vez me causa más curiosidad sobre cómo implementarlo es el Lévy flight pues en mi proyecto lo empleé en el modo fiesta, quisiera usarlo de varias maneras para sacarle más provecho sin que sea solo un modo a parte de aleatoriedad.