Unidad 6
Introducción 📜
¿Qué aprenderás en esta unidad? 💡
Actividad 01
Inspiración en agentes y comportamiento emergente
👣 Pasos:
- Observa “Arrels”: dedica tiempo a mirar imágenes o videos de “Arrels”. Fíjate en las estructuras que se forman. ¿Parecen seguir reglas? ¿Cómo interactúan las diferentes “ramas” o elementos?
- Observa “encuentros”: explora la obra “Encuentros”. Observa los
"Outputs finales"
¿Qué tipo de movimiento o trayectoria siguen las entidades? ¿Parecen evitarse, seguirse o ignorarse? ¿Qué reglas simples podrían generar estos caminos complejos? - Reflexiona sobre la autonomía: Para ambas obras (“Arrels” y “Encuentros”), reflexiona sobre estas preguntas:
- ¿Qué reglas o comportamientos autónomos crees que podrían estar programados en los agentes (sean ramas, líneas, partículas) para generar estas formas y patrones?
- ¿Cómo se percibe la “vida”, la “agencia” o el comportamiento emergente (complejidad no programada explícitamente) en estas obras?
- (Opcional) Si viste el video de Blender: ¿Cómo se relaciona el concepto de flow field mostrado en Blender con las ideas de agentes siguiendo reglas en un entorno? ¿Qué posibilidades creativas te sugiere para la animación?
🚀 Tu solución:
Inspiración en agentes y comportamiento emergente
-
Observa “Arrels”: dedica tiempo a mirar imágenes o videos de “Arrels”. Fíjate en las estructuras que se forman.
¿Parecen seguir reglas? ¿Cómo interactúan las diferentes “ramas” o elementos?
- Se parecen entes vivientes similares a los gusanos de Dune o también se pueden relacionar con grandes tentáculos. Aunque cada uno parece ser independiente de los anteriores y tienen diferentes rutas de acción, todo suelen tener como un tiempo de acción que culmina con mini puntos. Comienzan con trazos grueso que van achicándose. Se sobreponen unos sobre otros, varían los colores para dar la sensación de profundidad, se generan siempre desde el perímetro del canvas y en su mayoría se concentran en el centro del canvas para terminar su ciclo de vida.
-
Observa “encuentros”: explora la obra “Encuentros”. Observa los “Outputs finales”
¿Qué tipo de movimiento o trayectoria siguen las entidades? ¿Parecen evitarse, seguirse o ignorarse? ¿Qué reglas simples podrían generar estos caminos complejos?
- El movimiento está muy orientado al wavy art, mi favorito. Veo que ubican diferentes grillas con ciertos puntos definidos como guías para que las líneas se conecten y repliquen sus caminos. Yo creo que se puede establecer con una sola generación, un patrón. Para que las líneas que se creen después guarden cierta distancia pero quieran copiar el camino de la anterior a su manera con los puntos de referencia.
-
Reflexiona sobre la autonomía: Para ambas obras (“Arrels” y “Encuentros”), reflexiona sobre estas preguntas:
-
¿Qué reglas o comportamientos autónomos crees que podrían estar programados en los agentes (sean ramas, líneas, partículas) para generar estas formas y patrones?
- Arrels: Los tentáculos tienen autonomía en la ruta que toman porque no cumplen una ruta fija sino que varían sus luhgares de origen, sus colores, tamaños y direcciones finales. Lo más probable es que se les asignen ciertos parámetros pero se les de la libertad de escoger cómo los siguen, porque igual siguen conservando la paleta de colores y no se demoran mil años entre la generación de uno y otro (son simultáneos)
- Encuentros: Para mí, esta obra tiene menos autonomía porque ya se establecen unos parámetros de espacio y puntos de referencia por los que las generaciones de líneas deben pasar para jugar con las formas y demás. Sin embargo, creo que al igual que el anterior ya hay unos patrones de movimiento definidos y se les otorga menos libertad para variar.
-
¿Cómo se percibe la “vida”, la “agencia” o el comportamiento emergente (complejidad no programada explícitamente) en estas obras?
- Arrels: Esta obra explora la autonomía del código como la libertad de ser, la libertad d ecruzarse y mezclarse porque sí y porque no. Las conexiones entre tentáculos son dinámicas y divertidas porque tienen cierto grado de sorpresa.
- Encuentros: Aquí lo veo más como fluir, ya existe una corriente a la que seguir pero lo haces desde tus términos de acción. Me gustó mucho por las posibilidades de establecer una corriente y ver qué pasa.
-
Investigación 🔎
Actividad 02
Analizando los campos de flujo (flow fields)
👣 Pasos:
- Ejecuta el ejemplo: ejecuta el código del ejemplo principal de Flow Fields de TNoC en p5.js. Observa el comportamiento de los vehículos/agentes.
- Identifica la estructura del campo: en el código (usualmente en una clase
FlowField
), localiza cómo se almacena el campo de flujo. ¿Qué estructura de datos se usa (ej: un array 2D)? ¿Qué representa cada elemento de esa estructura? ¿Cómo se calcula inicialmente el vector en cada punto? - Analiza el comportamiento del agente: en el código de la clase del vehículo/agente (
Vehicle
), encuentra la funciónfollow()
. Explica con tus palabras:- ¿Cómo determina el agente qué vector del campo de flujo debe seguir basándose en su posición actual? (pista: implica mapear la posición a índices de la cuadrícula).
- Una vez que tiene el vector deseado del campo, ¿cómo lo utiliza para calcular la fuerza de dirección (
steering force
)? (pista: implica calcular la diferencia con la velocidad actual y limitar la fuerza).
- Identifica parámetros clave: Localiza en el código las variables que controlan aspectos importantes como:
- La resolución del campo de flujo (el tamaño de las celdas de la cuadrícula).
- La velocidad máxima (
maxspeed
) y la fuerza máxima (maxforce
) de los agentes.
- Experimenta con modificaciones: realiza al menos una de las siguientes modificaciones en el código, ejecuta y describe el efecto observado en el comportamiento de los agentes:
- Cambia significativamente la forma en que se generan los vectores del campo (ej: usa una fórmula matemática diferente en lugar de
noise()
, o cambia drásticamente los parámetros denoise()
). - Modifica sustancialmente la resolución del campo de flujo (hazla mucho más fina o mucho más gruesa).
- Altera considerablemente
maxspeed
omaxforce
de los agentes.
- Cambia significativamente la forma en que se generan los vectores del campo (ej: usa una fórmula matemática diferente en lugar de
🚀 Tu solución:
Análisis de los flowFields
Preguntas
La estructura del campo
☀️¿Qué estructura de datos se usa?
- Se está usando un array bidimensional. Una matriz con tamaño de columnas x filas y cada elemento ue almacena es un vector d etipo p5.vector.
☀️¿Qué representa cada elemento de esa estructura?
- Cada celda field[i][j] contiene un vector unitario (p5.Vector) que indica una dirección.
☀️¿Cómo se calcula inicialmente el vector en cada punto?
- En el código se calcula gracias al uso del ruido de Perlin. Específicamente así:
- noise(xoff, yoff) genera un valor suave entre 0 y 1.
- Se mapea ese valor a un ángulo entre 0 y 2π.
- Se convierte ese ángulo a un vector unitario (dirección).
- Finalmente, cada punto tiene una dirección fluida, con continuidad espacial gracias al ruido de Perlin.
Comportamiento del agente/vehículo
🌊 ¿Cómo determina el agente qué vector del campo de flujo debe seguir basándose en su posición actual? (pista: implica mapear la posición a índices de la cuadrícula).
- El agente está en una posición dentro del lienzo (por ejemplo, en (x, y)), pero el campo de flujo está organizado como una cuadrícula, como si dividieras el espacio en casillas.Entonces, lo primero que hace es ver en qué casilla está, dividiendo su posición entre el tamaño de las casillas (la “resolución”).
Así convierte su posición en coordenadas de fila y columna dentro del campo, y con eso busca el vector que le corresponde en ese punto.
🌊 Una vez que tiene el vector deseado del campo, ¿cómo lo utiliza para calcular la fuerza de dirección (steering force)? (pista: implica calcular la diferencia con la velocidad actual y limitar la fuerza).
- Ese vector le dice hacia dónde debería ir y qué tan rápido. Entonces, el agente:
- Toma ese vector y lo ajusta a su velocidad máxima, porque quiere ir hacia allá a toda velocidad.
- Compara esa nueva dirección con la velocidad que ya lleva. La diferencia entre ambas le dice cuánto necesita girar o cambiar su movimiento.
- Esa diferencia es la fuerza de dirección (steering force).
- Para no hacer giros bruscos, limita esa fuerza a un valor máximo.
- Finalmente, aplica esa fuerza para corregir su rumbo suavemente.
Parámetros clave
🪸La resolución del campo de flujo (el tamaño de las celdas de la cuadrícula).
- Esto controla qué tan grandes son las celdas de la cuadrícula del campo de flujo (es decir, cuántas flechas habrá en el lienzo).
- En el código se encuentra en sketch.js
flowfield = new FlowField(20);
El número 20 es la resolución. Mientras más bajo el número, más celdas y más detalles tendrá el campo (porque cada celda será más pequeña).
🪸La velocidad máxima (maxspeed) y la fuerza máxima (maxforce) de los agentes.
-
Velocidad máxima: es el parámetro que limita qué tan rápido puede ir el agente otorgando un tope máximo evitando que se descontrole. Se define en la siguiente patrte de sketch.js
-
Fuerza máxima: es quien controla cuánto puede cambiar de dirección un agente en cada momento. Si es muy baja, el giro será suave. Si es alta, puede cambiar de rumbo más bruscamente.
new Vehicle(random(width), random(height), random(2, 5), random(0.1, 0.5))
El tercer parámetro (random(2, 5)) es la velocidad máxima, y varía aleatoriamente entre 2 y 5 para cada agente.
El cuarto parámetro (random(0.1, 0.5)) es la fuerza máxima de dirección, significa que cada agente tendrá una fuerza de giro diferente entre 0.1 y 0.5.
Experimentación
Enlace a la simulación aquí
Modificaciones aplicadas
- Los vectores ahora se generan de manera diferente, ahora siguen una forma en espiral. La dirección de cada vector se calcula como un ángulo basado en la diferencia de posición (dir.heading()) y la magnitud (distancia al centro) multiplicada por un factor (dir.mag() * 0.05). Este factor asegura que los vectores se van girando progresivamente a medida que aumentan su distancia al centro, creando así una trayectoria en espiral.
- Reduje la resolución en un 50% por lo que ahora hay más celdas o cuadrículas para que los vehículos direccionen su movimiento.
- Asigné una velocidad máxima de 1, así que los agentes se mueven MUCHO más lento tratando en identificar la celda en la que están para poder moverse y una fuerza máxima de 0.02 por lo que gira lentamente y ahora parecen agentes perezosos.
Actividad 03
Analizando el comportamiento de enjambre (Flocking)
👣 Pasos:
- Ejecuta el ejemplo: ejecuta el código del ejemplo principal de Flocking de TNoC en p5.js. Observa el movimiento colectivo de los “boids” (agentes).
- Identifica las tres reglas: en el código de la clase del agente (ej:
Boid
), localiza las funciones que implementan las tres reglas fundamentales del Flocking:- Separación (Separation): evitar el hacinamiento con vecinos cercanos.
- Alineación (Alignment): dirigirse en la misma dirección promedio que los vecinos cercanos.
- Cohesión (Cohesion): moverse hacia la posición promedio de los vecinos cercanos.
- Explica las Reglas: para cada una de las tres reglas, explica con tus propias palabras:
- ¿Cuál es el objetivo de la regla?
- ¿Cómo calcula el agente la fuerza de dirección correspondiente? (describe la lógica general, ej: “Calcula un vector apuntando lejos de los vecinos demasiado cercanos”).
- Identifica parámetros clave: localiza en el código las variables que controlan:
- El radio (o distancia) de percepción (
perceptionRadius
o similar) que define quiénes son los “vecinos”. A veces también hay un ángulo de percepción. - Los pesos o multiplicadores que determinan la influencia relativa de cada una de las tres reglas al combinarlas.
- La velocidad máxima (
maxspeed
) y la fuerza máxima (maxforce
) de los agentes (similar a Flow Fields).
- El radio (o distancia) de percepción (
- Experimenta con modificaciones: realiza al menos una de las siguientes modificaciones en el código, ejecuta y describe el efecto observado en el comportamiento colectivo del enjambre:
- Cambia drásticamente el peso de una de las reglas (ej: pon la cohesión a cero, o la separación muy alta).
- Modifica significativamente el radio de percepción (hazlo muy pequeño o muy grande).
- Introduce un objetivo (
target
) que todos los boids intenten seguir (usando una fuerza deseek
) además de las reglas de flocking, y ajusta su influencia.
🚀 Tu solución:
Análisis de los enjambres (Flocking)
Las 3 reglas
Identificación
- Se encuentran en la clase boid.js y se implementan cada una como un método de esta clase
Separación
// Separation // Method checks for nearby boids and steers away separate(boids) { let desiredSeparation = 25; let steer = createVector(0, 0); let count = 0; // For every boid in the system, check if it's too close for (let i = 0; i < boids.length; i++) { let d = p5.Vector.dist(this.position, boids[i].position); // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) if (d > 0 && d < desiredSeparation) { // Calculate vector pointing away from neighbor let diff = p5.Vector.sub(this.position, boids[i].position); diff.normalize(); diff.div(d); // Weight by distance steer.add(diff); count++; // Keep track of how many } } // Average -- divide by how many if (count > 0) { steer.div(count); }
// As long as the vector is greater than 0 if (steer.mag() > 0) { // Implement Reynolds: Steering = Desired - Velocity steer.normalize(); steer.mult(this.maxspeed); steer.sub(this.velocity); steer.limit(this.maxforce); } return steer; }
Alineación
// Alignment // For every nearby boid in the system, calculate the average velocity align(boids) { let neighborDistance = 50; let sum = createVector(0, 0); let count = 0; for (let i = 0; i < boids.length; i++) { let d = p5.Vector.dist(this.position, boids[i].position); if (d > 0 && d < neighborDistance) { sum.add(boids[i].velocity); count++; } } if (count > 0) { sum.div(count); sum.normalize(); sum.mult(this.maxspeed); let steer = p5.Vector.sub(sum, this.velocity); steer.limit(this.maxforce); return steer; } else { return createVector(0, 0); } }
Cohesión
// Cohesion // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location cohere(boids) { let neighborDistance = 50; let sum = createVector(0, 0); // Start with empty vector to accumulate all locations let count = 0; for (let i = 0; i < boids.length; i++) { let d = p5.Vector.dist(this.position, boids[i].position); if (d > 0 && d < neighborDistance) { sum.add(boids[i].position); // Add location count++; } } if (count > 0) { sum.div(count); return this.seek(sum); // Steer towards the location } else { return createVector(0, 0); } }
Explicación
1. Separación: evita colisiones o que los boids estén demasiado juntos.
- Revisa los demás boids a su alrededor (dentro de un cierto radio).
- Si encuentra a otros boids muy cerca (más cerca que desiredSeparation), calcula un vector en dirección contraria para alejarse.
- Si hay varios boids cerca, hace un promedio de esas direcciones.
2. Alineación: las partículas se mueven en la misma dirección promedio que sus vecinos.
- Encuentra los boids cercanos dentro de un radio (neighborDistance).
- Promedia las velocidades (dirección + rapidez) de sus vecinos cercanos.
- Intenta ajustar su velocidad para que coincida con ese promedio.
3. Cohesión: evita que el grupo se disperse haciendo que se acerquen al centro del grupo cercano.
- Identifica a los vecinos cercanos dentro de un radio (neighborDistance).
- Calcula el centro de masa (posición promedio) de los boids cercanos.
- Calcula un vector hacia ese punto central.
- Usa seek(target) para calcular una fuerza que lo lleve hacia ese centro.
La variable clave es:
let neighborDistance = 50; // distancia para considerar vecinos
Igual que la alineación.
Parámetros clave
El radio o distancia de percepción define qué tan lejos puede ver un boid para aplicar cada regla.
- La variable clave en separación es:
let desiredSeparation = 25; // qué tan cerca es “demasiado cerca”
- Las reglas de alineación y cohesión comparten la variable clave:
let neighborDistance = 50; // distancia para considerar vecinos
Los pesos o influencias relativas se aplican dentro del método flock(boids) de la clase boid.js justo antes de sumar las fuerzas de aceleración.
flock(boids) { let sep = this.separate(boids); // Separation let ali = this.align(boids); // Alignment let coh = this.cohere(boids); // Cohesion
// 🟢 Aquí están los multiplicadores: sep.mult(1.5); // Separación más fuerte ali.mult(1.0); // Alineación normal coh.mult(1.0); // Cohesión normal
// Se suman todas las fuerzas a la aceleración this.applyForce(sep); this.applyForce(ali); this.applyForce(coh); }
Es aquí donde se otorga una jerarquía de importancia para cada regla, en este caso la que tiene prioridad es la de separación (para evitar colisisones).
La velocidad máxima limita la velocidad en la que se puede mover un boid y la fuerza máxima limita la velocidad con la que cambia de dirección (si es suave o brusco)
En el código se encuentra en el constructor del boid
this.maxspeed = 3; // ← Velocidad máximathis.maxforce = 0.05; // ← Fuerza de dirección máxima (steering)
Experimentación
Enlace a la simulación aquí}
Modificaciones
-
Cambié drásticamente el peso de la separación, pasó de 1.5 a 5.0 pero también agregué otra fuerza de target que es la que atrae a los boids y es la principal con un peso de 5.5. La cohesión y alineación quedaron iguales. En la simulación se nota cómo se prioriza seguir al nuevo objeto y también cómo se mantienen separados, dispersos y salen desde varias direcciones.
-
Modifiqué el radio de separación por 90 así que los boids van bastante separados, quería ver qué pasaba si las variables claves de la cohesión y la alineación eran diferentes, así que con la primera conservé el valor de 50 y a la segunda uno de 20.
-
Ahora los boids tienden a mantenerse mucho más separados entre sí, como si se repelieran fuertemente, incluso desde la distancia.
-
Manteniendo la cohesión sigue igual la atracción hacia el centro del grupo, por lo que los boids podrían intentan agruparse constantemente, luchando contra la separación.
-
Con la alineación los boids copien rápidamente la dirección del grupo, incluso cuando están bastante lejos entre sí.
- Introduje un objetivo (target) que todos los boids intentan seguir (usando una fuerza de seek) y es la nueva fuerza principal del ejemplo por lo que siempre tienden a donde se encuentra el target que es justo la posición del mouse sobre el canvas.
Aplicación 🛠
Actividad 04
Aplicación creativa e inesperada de agentes autónomos
👣 Pasos:
- Elige un algoritmo: decide si trabajarás con Flow Fields o Flocking.
- Conceptualiza la aplicación inesperada: brainstorming: ¿Cómo puedes usar la lógica de ese algoritmo para representar algo diferente? ¿Qué fenómeno visual, natural o abstracto podrías simular de forma no convencional? Define tu concepto.
- Diseña la implementación:
- ¿Cómo adaptarás el algoritmo base a tu nuevo concepto? ¿Qué representarán los “agentes”? ¿Qué significará el “campo” o las “reglas de enjambre” en tu contexto?
- ¿Qué aspecto visual tendrán tus agentes o el resultado del proceso?
- ¿Qué tipo de interacción incluirás? (ej: el mouse influye en el flow field, un clic añade/quita agentes, teclas cambian parámetros, micrófono, etc).
- Implementa tu sketch: escribe el código en p5.js. Empieza adaptando el código base del algoritmo elegido e introduce gradualmente los cambios para tu concepto, los nuevos visuales y la interacción.
- Prueba y refina: ejecuta, prueba la interacción y refina los parámetros y el aspecto visual hasta que logres una pieza coherente con tu concepto inesperado.
🚀 Tu solución:
Aplicación creativa de Flow Fields
El concepto
- La idea es representar un ciberataque a sistemas de datos. El usuario es el hacker “infecta” un sistema, las partículas son los expertos en ciberseguridad que intentan detener al atacante que parece ser inofensivo, sin embargo, él ya ha tomado el control del sistema y los elimina uno a uno hasta apoderarse de todo.
Adaptación
Zonas de glitch que simulan la afectación del virus
let isGlitchZone = dist(mouseX, mouseY, x * scl, y * scl) < 100;let angle = glitchMode || isGlitchZone ? random(TWO_PI) : noise(xoff, yoff) * TWO_PI * 4;
- Si estás en glitchMode o el mouse está cerca de una zona, el ángulo es aleatorio.
- Esto rompe el patrón orgánico del flowfield y genera movimientos erráticos → estética glitch.
La escala o resolución se adapta al campo
scl = glitchMode ? 300 : 200;
- En modo glitch se hace menos denso (menos filas/Columnas)
- Esto cambia la estructura del campo y el comportamiento de las partículas.
Partículas influenciadas por el campo
particle.follow(flowField);
- Cada partícula consulta la fuerza del flowfield local y se mueve con base en ella.
- El applyForce() aplica esta dirección suavemente.
Atracción hacia el cursor con oscilación
Aunque esto no es del flow field en sí, complementa el movimiento con una fuerza que se superpone a la del campo:
let forceX = (mouseX - this.pos.x) * attractionStrength + angleOffsetX;let forceY = (mouseY - this.pos.y) * attractionStrength + angleOffsetY;
- Esto hace que parezca que el “virus” (cursor) está atrayendo o manipulando las partículas.
- Tiene un toque “hipnótico” gracias a los sin y cos.
Interacción implementada
-
Al hacer click se activa el modo “glitch”:
- Cambia el estado del sistema (glitchMode).
- Se recalcula la grilla (calculateGrid()).
- Se genera una explosión en la posición del cursor.
-
Atracción hacia el mouse
- Las partículas se sienten atraídas hacia el mouse, con una fuerza que disminuye con la distancia.
- Se suma un movimiento oscilante para hacerlo más expresivo.
-
Reinicio del sistema con barra espaciadora
- Al presionar espacio, se reinician las partículas y las explosiones.
-
Explosiones que afectan a las partículas
- Aplica una fuerza repulsiva a las partículas cercanas.
- “Mata” partículas si están demasiado cerca.
El código
Simulación aquí
let particles = [];let flowField;let cols, rows;let scl = 200;let inc = 0.1;let explosions = [];let glitchMode = false;
function setup() { createCanvas(windowWidth, windowHeight); calculateGrid(); flowField = new Array(cols * rows);
for (let i = 0; i < 4000; i++) { particles.push(new Particle()); }
background(0);}
function draw() { background(0, 10);
// Flow field let yoff = 0; for (let y = 0; y < rows; y++) { let xoff = 0; for (let x = 0; x < cols; x++) { let index = x + y * cols; let isGlitchZone = dist(mouseX, mouseY, x * scl, y * scl) < 100; let angle = glitchMode || isGlitchZone ? random(TWO_PI) : noise(xoff, yoff) * TWO_PI * 4; let v = p5.Vector.fromAngle(angle); v.setMag(1); flowField[index] = v; xoff += inc; } yoff += inc; }
// Explosiones for (let explosion of explosions) { explosion.update(); explosion.show(); }
// Actualizar partículas for (let i = particles.length - 1; i >= 0; i--) { let particle = particles[i];
for (let explosion of explosions) { explosion.affect(particle); if (explosion.kills(particle)) { particles.splice(i, 1); break; } }
if (particles[i]) { particle.follow(flowField); particle.update(); particle.edges(); particle.show(); } }
explosions = explosions.filter(e => !e.isDone());
noFill(); stroke(0, 255, 255, 50); strokeWeight(2); ellipse(mouseX, mouseY, sin(frameCount * 0.1) * 50 + 100);}
function mousePressed() { glitchMode = !glitchMode; calculateGrid(); explosions.push(new Explosion(mouseX, mouseY));}
// Evento de teclado para reiniciar el sistemafunction keyPressed() { if (key === 'r' || key === 'R') { restart(); }}
function keyPressed() { if (keyCode === 32) { // 32 es el código de la barra espaciadora restart(); }}function restart() { particles = []; explosions = []; calculateGrid(); for (let i = 0; i < 4000; i++) { particles.push(new Particle()); } background(0);}
function calculateGrid() { scl = glitchMode ? 300 : 200; cols = floor(width / scl); rows = floor(height / scl); flowField = new Array(cols * rows);}
class Particle { constructor() { this.pos = createVector(random(width), random(height)); this.vel = createVector(0, 0); this.acc = createVector(0, 0); this.maxSpeed = glitchMode ? 5 : 2; this.prevPos = this.pos.copy(); this.attractionFactor = random(0.2, 1); }
follow(vectors) { let x = floor(this.pos.x / scl); let y = floor(this.pos.y / scl); let index = x + y * cols; let force = vectors[index]; if (force) this.applyForce(force); }
applyForce(force) { let maxForce = glitchMode ? 0.5 : 0.2; this.acc.add(p5.Vector.mult(force, maxForce)); }
update() { this.vel.add(this.acc); this.vel.limit(this.maxSpeed); this.pos.add(this.vel); this.acc.mult(0); }
edges() { 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; }
show() { let distToMouse = dist(this.pos.x, this.pos.y, mouseX, mouseY); if (random(1) < this.attractionFactor) { let attractionStrength = map(distToMouse, 0, width, 0.05, 0); let angleOffsetX = sin(frameCount * 0.1) * 2; let angleOffsetY = cos(frameCount * 0.1) * 2; let forceX = (mouseX - this.pos.x) * attractionStrength + angleOffsetX; let forceY = (mouseY - this.pos.y) * attractionStrength + angleOffsetY; this.vel.x += forceX; this.vel.y += forceY; }
let colorChange = map(distToMouse, 0, width, 255, 0); stroke(colorChange, 100, 255 - colorChange, 100); strokeWeight(1); line(this.pos.x, this.pos.y, this.pos.x - this.vel.x, this.pos.y - this.vel.y); }}
class Explosion { constructor(x, y) { this.pos = createVector(x, y); this.radius = 0; this.maxRadius = 250; this.lifespan = 255; }
update() { this.radius += 15; this.lifespan -= 10; }
isDone() { return this.lifespan <= 0; }
affect(particle) { let d = dist(particle.pos.x, particle.pos.y, this.pos.x, this.pos.y); if (d < this.radius) { let dir = p5.Vector.sub(particle.pos, this.pos); dir.normalize(); let strength = map(this.radius - d, 0, this.radius, 4, 0); dir.mult(strength); particle.applyForce(dir); } }
kills(particle) { let d = dist(particle.pos.x, particle.pos.y, this.pos.x, this.pos.y); return d < this.radius * 0.2; }
show() { noFill(); stroke(255, 100, 100, this.lifespan); strokeWeight(3); ellipse(this.pos.x, this.pos.y, this.radius * 2); }}
Pieza final
Consolidación y metacognición 🤔
Actividad 05
Comparando algoritmos y consolidando conceptos
👣 Pasos:
Reflexiona sobre los dos algoritmos y tu experiencia:
- Diferencias fundamentales: ¿Cuál dirías que es la diferencia principal en cómo Flow Fields y Flocking logran el movimiento coordinado o dirigido de los agentes? (piensa en dónde reside la “inteligencia” o las reglas: ¿En el entorno o en las interacciones entre agentes?).
- Tipos de comportamiento emergente: basado en tu análisis y aplicación, ¿Qué tipo de comportamiento colectivo o patrón visual crees que es más fácil o natural lograr con Flow Fields? ¿Y con Flocking? Da ejemplos.
- Ventajas y desventajas: en tu opinión, ¿Cuáles podrían ser las ventajas o desventajas de usar uno u otro algoritmo para ciertos tipos de efectos visuales o simulaciones?
- El agente autónomo: ¿Cómo te ayudaron estos dos ejemplos (Flow Fields y Flocking) a entender mejor el concepto de “agente autónomo”? ¿Qué características definen a un agente en estos sistemas?
- Emergencia: ¿En qué momento observaste “comportamiento emergente” (complejidad o patrones no programados explícitamente) al trabajar con estos algoritmos?
🚀 Tu solución:
Reflexiona sobre los dos algoritmos y tu experiencia:
Diferencias fundamentales
-
Flow Fields: La inteligencia reside principalmente en el entorno. Las partículas simplemente “leen” el campo vectorial y responden a él. No tienen conocimiento de otras partículas. Es como si estuvieran en una corriente invisible.
-
Flocking: Aquí la inteligencia está en los agentes mismos, quienes siguen reglas simples basadas en la posición y velocidad de sus vecinos (alineación, cohesión y separación). Cada partícula (boid) es consciente de su entorno local inmediato.
-
Mi simulación: Reproduce claramente un entorno tipo flow field, pero con toques interesantes como explosiones, glitch zones, y atracción al mouse. Estos elementos enriquecen el campo y, por tanto, el “ambiente” que guía a los agentes.
Tipos de comportamiento emergente
-
Flow Fields: Facilita trayectorias suaves y fluidas. Es ideal para generar patrones tipo ríos de movimiento, ondas o flujos cerebrales/glitch digitales, como hiciste tú. Ejemplo: En mi simulación, las partículas parecen crear un patrón coral, dinámico y orgánico cuando el campo es suave, y se vuelve caótico y fragmentado cuando entra el modo glitch o hay explosiones.
-
Flocking: Produce agrupamientos naturales y patrones como bandadas o cardúmenes. La belleza está en la forma en que pequeñas decisiones locales generan orden colectivo (un grupo que gira o escapa sin haber un “líder”).
Ventajas y desventajas
En tu opinión, ¿Cuáles podrían ser las ventajas o desventajas de usar uno u otro algoritmo para ciertos tipos de efectos visuales o simulaciones?
-
FLOW FIELDS
-
VENTAJA:
- Se pueden lograr efectos visuales complejos sin la necesidad de hacer muchos cálculos
-
DESVENTAJA:
- Como no hay interacción entre partículas, puede ser un poco aburrido o parecer artificial si no se enriquece su concepto.
-
-
FLOCKING
-
VENTAJA:
- Es una simulación más relacionada con fenómenos naturales y colectivos, así que es ideal para simular vida y comoportamientos biológicos.
-
DESVENTAJA:
- Como las partículas analizan el movimiento de sus compañeritas se hacen más cálculos computacionales y si se quieren modificar comportamientos es más dificíl de controlar el comportamiento de las partículas.
-
El agente autónomo
¿Cómo te ayudaron estos dos ejemplos (Flow Fields y Flocking) a entender mejor el concepto de “agente autónomo”? ¿Qué características definen a un agente en estos sistemas?
- Bueno en ambos algoritmos identifiqué las siguientes características del agente autónomo: tiene una posición, velocidad, aceleración, decide cómo moverse en función de inputs locales (campo o vecinos) y actúa de manera independiente, pero con reglas comunes.
En el caso de mi código experimental, cada partícula decide qué hacer dependiendo del campo y de su cercanía al mouse o a una explosión.
Emergencia
¿En qué momento observaste “comportamiento emergente” (complejidad o patrones no programados explícitamente) al trabajar con estos algoritmos?
-
Bueno, cuando se activa el modo glitch pasa algo en particular y es que el sistema se vuelve un poco caótico pero coherente porque las partículas no se enlocan del todo, solo cambian de comportamiento que aunque sea aleatorio parece que tuviera una lógica programada detrás.
-
Las partículas rodean el mouse y parece que intentan “trabajar juntas” y no está programado en el patrón sino que las fuerzas que estpy usando hacen que eso suceda.
-
Las explosiones son la parte más dovertida porque dispersa naturalmente a las partículas que huyen como si quisieran salvarse.
Actividad 06
Autoevaluación del aprendizaje
👣 Pasos:
Considera tu experiencia personal en esta unidad y responde con honestidad:
- Comprensión conceptual: ¿Qué tan claros te resultaron los conceptos de agente autónomo, emergencia, flow fields y flocking? ¿Qué fue lo más fácil y lo más difícil de entender?
- Análisis de algoritmos: ¿Te resultó útil analizar los ejemplos de TNoC y experimentar con modificaciones para entender cómo funcionaban los algoritmos? ¿Qué dificultades encontraste en esta fase?
- Aplicación creativa: ¿Qué tan
"exitoso"
te sientes al aplicar uno de los algoritmos a un contexto inesperado? ¿Lograste plasmar tu idea? ¿Qué fue lo más desafiante de esta actividad? - Conexión con TNoC: ¿Cómo se conectan los conceptos de esta unidad (agentes, sistemas, fuerzas) con lo que has aprendido en unidades anteriores?
- Exploración futura: ¿Hay algún aspecto de los agentes autónomos, flow fields, flocking u otros comportamientos de sistemas que te gustaría explorar más a fondo después de esta unidad?
🚀 Tu solución:
Comprensión conceptual
¿Qué tan claros te resultaron los conceptos de agente autónomo, emergencia, flow fields y flocking? ¿Qué fue lo más fácil y lo más difícil de entender?
- Me pareció muy divertido y sencillo comprender los conceptos, fueron fáciles de analizar.
Análisis de algoritmos
¿Te resultó útil analizar los ejemplos de TNoC y experimentar con modificaciones para entender cómo funcionaban los algoritmos? ¿Qué dificultades encontraste en esta fase?
- Analizar los ejemplos y cambiar los parámetros de cada uno me ayudó a identificar con mayor facilidad los parámetros claves de cada algoritmo, no hubo nada difícil.
Aplicación creativa
¿Qué tan “exitoso” te sientes al aplicar uno de los algoritmos a un contexto inesperado? ¿Lograste plasmar tu idea? ¿Qué fue lo más desafiante de esta actividad?
- Me siento 10/10 porque apliqué el concepto de manera creativa a un contexto inesperado que me llamaba la atención (la ciberseguridad), fue una manera de demostrar de manera gráfica la importancia de tener sistemas de ciberseguridad blindados antes de que ocurra un ataque. Lo más complicado fue idear la manera en la que las explosiones tuvieran un impacto en el sistema de partículas que seguía el Flow Field.
Conexión con TNoC
¿Cómo se conectan los conceptos de esta unidad (agentes, sistemas, fuerzas) con lo que has aprendido en unidades anteriores?
- Los agentes se conectan con los sistemas de partículas y su eliminación, solo que esta vez no se eliminan después de x tiempo con una variable de vida si no que le asignamos una interacción que permita eliminarlos de manera divertida, las fuerzas de la unidad 3 son aplicadas a través de un target que atrae a las partículas y cuando activa la explosión las expulsa hacia afuera con una fuerza de repulsión. Otra cosa que recuerdo es que los agentes al estar dotados de velocidad, posición y son afectados por una fuerza. Esta unidad fue una unión de conceptos evaluados en un sistema de partículas autónomos que con un concepto creativo y divertido permitió la manipulación de variables claves para ajustarse a lo que tenía en mi cabeza.
Exploración futura
¿Hay algún aspecto de los agentes autónomos, flow fields, flocking u otros comportamientos de sistemas que te gustaría explorar más a fondo después de esta unidad?
- Al inicio de la unidad los referentes me parecieron brutales, siempre me ha gustado dibujar cosas muy fluidas y wavys. Me gustaría seguir explorando los flow fields porque fue el algoritmo que más me llamó la atención. Me gustaría ilustrar con partículas generando zonas de calor dentro del grid para ver qué visuales se pueden generar con algunas variaciones de colores y movimiento, siento que sería una manera divertida de explorar las posibilidades del concepto.
Actividad 07
Retroalimentación para mejorar la unidad
👣 Pasos:
Reflexiona sobre cómo fue tu experiencia personal al cursar esta unidad específica y responde:
- Claridad y enfoque: ¿Te pareció claro el objetivo de la unidad y la conexión entre las actividades (inspiración, análisis, aplicación)?
- Actividades de introducción e investigación: ¿Fueron útiles los referentes artísticos (SET) para introducir el tema? ¿Fueron efectivas las actividades de análisis de algoritmos para tu comprensión? ¿Sugerirías algún cambio?
- Actividad de aplicación: ¿Te gustó el desafío de la aplicación inesperada? ¿Fue demasiado difícil, demasiado fácil o adecuado? ¿Necesitabas más orientación o ejemplos para esta parte?
- Recursos: ¿Fueron suficientes los enlaces a TNoC y los ejemplos? ¿Necesitaste buscar muchos recursos adicionales por tu cuenta?
- Ritmo y carga de trabajo: ¿Cómo sentiste el ritmo y la carga de trabajo de esta unidad en comparación con las anteriores?
- Sugerencia principal: Si pudieras hacer una sugerencia principal para mejorar la experiencia de aprendizaje en esta unidad sobre agentes autónomos, ¿Cuál sería?
🚀 Tu solución:
Claridad y enfoque
¿Te pareció claro el objetivo de la unidad y la conexión entre las actividades (inspiración, análisis, aplicación)?
- Sí, el objetivo de esta unidad me pareció muy claro de comprender, la inspiración fue muy reveladora sobre las posibilidades de aplicación de los algoritmo. El análisis fue breve y conciso por lo que ver los parámetros claves me ayudó a experimentar de manera más fluida con los conceptos.
Actividades de introducción e investigación
¿Fueron útiles los referentes artísticos (SET) para introducir el tema? ¿Fueron efectivas las actividades de análisis de algoritmos para tu comprensión? ¿Sugerirías algún cambio?
- Las referencias fueron perfectas para motivar a explorar estos conceptos así que sí les doy un 10/10. Las actividades de análisis fueron muy directas y claras por lo que las pequeñas pistas motivaban a una investigación más consciente para descubrir “la clave”. Creo que la estructura de esta unidad estuvo muy bien distribuida.
Actividad de aplicación
¿Te gustó el desafío de la aplicación inesperada? ¿Fue demasiado difícil, demasiado fácil o adecuado? ¿Necesitabas más orientación o ejemplos para esta parte?
- Me gustó mucho este reto creativo pero al principio me bloqueé un poco porque no sabía cómo abordar de manera inesperada los algoritmos, pero ya después buscando referentes y pensando en mis intereses encontré un concepto muy interesante que fue muy divertido de aplicar así que mi veredicto final es que fue adecuado. Me gustaría que en el enunciado definieramos “inesperado” como un concepto menos abstracto como relacionado a algo que te guste o un concepto específico que todos podamos reinterpretar de maneras distintas.
Recursos
¿Fueron suficientes los enlaces a TNoC y los ejemplos? ¿Necesitaste buscar muchos recursos adicionales por tu cuenta?
- Fueron los enlaces necesarios, lo único que busqué fueron referentes visuales para el concepto.
Ritmo y carga de trabajo
¿Cómo sentiste el ritmo y la carga de trabajo de esta unidad en comparación con las anteriores?
- Wow, comparado con las anteriores este me pareció mucho más llevadero y sencillo de seguir.
Sugerencia principal
Si pudieras hacer una sugerencia principal para mejorar la experiencia de aprendizaje en esta unidad sobre agentes autónomos, ¿Cuál sería?
- Sería divertido que sobre un mismo concepto como por ejemplo “El mar” o “Los pensamientos” pudieramos hacer la parte de aplicación para ver cómo podemos resolver la parte de adaptación de conceptos con limitaciones, además de ver cómo cada uno puede a partir de un mismo punto de partida, generar múltiples soluciones.