Unidad 5
Introducción 📜
En esta unidad vas a explorar los sistemas de partículas. Los sistemas de partículas son conjuntos de partículas que interactúan entre sí y con su entorno. Estos sistemas son fundamentales en el mundo del arte y diseño generativo, ya que permiten crear composiciones complejas y dinámicas a partir de reglas simples.
¿Qué aprenderás en esta unidad? 💡
En esta unidad vas a experimentar con aplicaciones interactivas que tendrán las siguientes características:
- Emitirán partículas que se moverán en el espacio.
- Las partículas estarán sujetas a fuerzas que las harán cambiar de dirección y velocidad.
Actividad 01
¿En dónde se usan sistemas de partículas?
🎯 Enunciado: te voy a pedir que le des una mirada a este artículo publicado en Medium por la artista Amelia Winger-Bearskin. En el artículo vas a encontrar ejemplos de sistemas de partículas en el arte y la inteligencia artificial. Dale una mirada a los artistas, ejemplos y proyectos que aparecen en el artículo. Tengo que decirte que uno de los artistas que aparece referenciado es Refik Anadol, uno de mis artistas favoritos.
📤 Entrega: selecciona dos proyectos que mencionen en el artículo que te llamen la atención y que te gustaría explorar más. Escribe un breve resumen de cada uno de ellos y comenta por qué te interesan y cómo crees que se pueden conectar con tu perfil profesional o con algún interés personal que tengas.
🚀 Tu solución:
Sistemas de partículas
-
La primera obra de arte de la lista que me llamó la atención fue la que estuvo hecha con “Algorand technologies”, según estuve viendo, algorand es una empresa de criptomonedas que promete dar un enfoque en transacciones rápidas y con bajas comisiones, además de ser energéticamente eficiente. Este parece ser un NFT relacionado a la criptomoneda ALGO, y es interesante ver como se relacionan ya fundaciones de todo tipo con imágenes como esta, a pesar de que si se detalla a profundidad el sistema de partículas parece no ser tan trabajado, es un hecho que de manera general se ve muy bien. Esto nos muestra que los sistemas de partículas en la industria no tienen que ser de una calidad inmesurable, sino que deben ser eficientes y mostrar lo que necesitamos, dar la ilusión que queremos y así atraeremos la atención y retención que necesitamos.
-
La otra obra de arte, la cual si me parece mucho más compleja y completa fue la de “Refik Anadol”, una obra de arte que parece estar relacionada con Composiciones de Mozart, según entiendo, el artista tomó una cantidad considerable de datos de estas composiciones, extrajo características y las mapeó en puntos, logrando así algo tan impresionante de ver como esto, es interesante ver que el artista se refiere a la creación como un mapa de 6 dimensiones, lo cual realmente da mucho qué pensar sobre la complejidad de la obra, de la profundidad de la misma y la forma en que funcionan los algoritmos, programas o códigos que él utiliza para dar vida a algo como esto. Definitivamente esta obra puede ser la inspiración para muchas otras mucho más complejas en mi rama, la animación, y más que ahora estoy empezando a desarrollar un interés particular por la interacción con la animación, y claramente viendo como son las cosas hoy en día, conectar todo esto con la automatización y la generación procedural con ayuda de la IA sería un flujo redondo.
Investigación 🔎
En esta fase, repasarás los conceptos de herencia y polimorfismo que aplicarás para crear sistemas de partículas que se comporten y se vean de manera diferente. Adicionalmente, aplicarás fuerzas a las partículas para que se muevan e interactúan con el entorno.
Actividad 02
Revisa y repasa algunos conceptos
🎯 Enunciado: dale una mirada al capítulo sobre sistemas de partículas del texto guía del curso, pero quiero que te concentres en los siguientes conceptos:
✅ 1. Revisa detalladamente el ejemplo 4.2: an Array of Particles.
✅ 2. Analiza el ejemplo 4.4: a System of Systems.
✅ 3. Analiza el ejemplo 4.5: a Particle System with Inheritance and Polymorphism.
✅ 4. Analiza el ejemplo 4.6: a Particle System with Forces.
✅ 5. Analiza el ejemplo 4.7: a Particle System with a Repeller.
🧐🧪✍️ En tu bitácora responde a esta pregunta para cada una de las simulaciones: ¿Cómo se está gestionando la creación y la desaparción de las partículas y cómo se gestiona la memoria en cada una de las simulaciones?
📤 Entrega:
- Vas a modificar cada una de las simulaciones anteriores incluyen en cada una, al menos un concepto de las unidades anteriores, pero no repitas concepto, la idea es que repases al menos uno de cada unidad.
- Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
- Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
- Incluye un enlace a tu código en el editor de p5.js.
- Incluye el código fuente de cada una de las simulaciones.
- Captura de pantallas de cada una de las simulaciones con las imágenes que más te gusten como resultado de la ejecución de cada una de las simulaciones.
🚀 Tu solución:
Sistemas de partículas - Conceptos aplicados
-
1 - Nombre: Array of Particles. - Concepto: Vectores (unidad 2) - Aplicación: La idea es que se mueva este sistema de partículas a lo largo de la pantalla con las flechas de dirección.
Explicación: Los vectores son herramientas fundamentales en programación visual para representar posiciones, velocidades y direcciones. En este sistema, los usamos para mover las partículas por la pantalla, pero ahora también se integran con los controles del teclado, usando vectores para desplazar todo el sistema de partículas según la flecha presionada. Esto muestra cómo los vectores no solo afectan partículas individuales, sino también el movimiento de todo un conjunto de forma precisa y controlada. Usé este concepto ya que es el de los primeros, y este sistema de partículas al ser también básico, me parece que se complementan bien.
Código:
class Particle { constructor(x, y) { this.position = createVector(x, y); this.acceleration = createVector(0, 0); this.velocity = createVector(random(-1, 1), random(-1, 0)); this.lifespan = 255.0; }
run() { let gravity = createVector(0, 0.05); this.applyForce(gravity); this.update(); this.show(); }
applyForce(force) { this.acceleration.add(force); }
update() { this.velocity.add(this.acceleration); this.position.add(this.velocity); this.lifespan -= 2; this.acceleration.mult(0); }
show() { stroke(0, this.lifespan); strokeWeight(2); fill(127, this.lifespan); circle(this.position.x, this.position.y, 8); }
isDead() { return this.lifespan < 0.0; }}
let particles = [];let emitterPosition;
function setup() { createCanvas(640, 240); emitterPosition = createVector(width / 2, 20); // posición inicial del sistema}
function draw() { background(255); particles.push(new Particle(emitterPosition.x, emitterPosition.y));
for (let i = particles.length - 1; i >= 0; i--) { let p = particles[i]; p.run(); if (p.isDead()) { particles.splice(i, 1); } }}
function keyPressed() { let move = 10; if (keyCode === LEFT_ARROW) { emitterPosition.x -= move; } else if (keyCode === RIGHT_ARROW) { emitterPosition.x += move; } else if (keyCode === UP_ARROW) { emitterPosition.y -= move; } else if (keyCode === DOWN_ARROW) { emitterPosition.y += move; }}
-
2 - Nombre: System of Systems. - Concepto: Atracción gravitacional (Unidad 3) - Aplicación: La idea es que a pesar de que voy dando click y poniendo emisores de partículas a lo largo del canvas, que estos emisores con el tiempo vayan hacia un atractor movible con el mouse.
Explicación: Este sistema de partículas aplica el concepto de atracción gravitacional simulada, donde cada partícula de cada emisor es afectada por una fuerza que la atrae hacia la posición del mouse. Para lograrlo, se calcula un vector desde la partícula hasta el mouse, se normaliza y se le da una magnitud baja para que el efecto no sea abrupto, creando así un campo gravitacional suave. Esto transforma el comportamiento natural de caída en una trayectoria curva, haciendo que las partículas tiendan a moverse en dirección al cursor, como si este fuera una especie de planeta atrayéndolas. Decidí hacer esto para tener una interacción completa con el mouse, ya que lo utilizo para posicionar los sistemas de partículas, me pareció interseante que estas también interactúen con él de otra forma, en este caso, siendo atraídas hacia él. La gestión de memoria se maneja limpiamente: cada Emitter contiene su propio arreglo de partículas, y estas se eliminan cuando su vida (lifespan) se agota, recorriendo el arreglo en reversa para evitar errores al borrar elementos durante el bucle. Así, se evita la acumulación infinita de objetos en memoria.
Código:
class Emitter { constructor(x, y) { this.origin = createVector(x, y); this.particles = []; }
addParticle() { this.particles.push(new Particle(this.origin.x, this.origin.y)); }
run() { for (let i = this.particles.length - 1; i >= 0; i--) { this.particles[i].run(); if (this.particles[i].isDead()) { this.particles.splice(i, 1); } } }}
class Particle { constructor(x, y) { this.position = createVector(x, y); this.acceleration = createVector(0, 0); this.velocity = createVector(random(-1, 1), random(-1, 0)); this.lifespan = 255.0; }
run() { let gravity = createVector(0, 0.05); let attraction = p5.Vector.sub(createVector(mouseX, mouseY), this.position); attraction.setMag(0.05); // fuerza suave de atracción
this.applyForce(gravity); this.applyForce(attraction); this.update(); this.show(); }
applyForce(force) { this.acceleration.add(force); }
update() { this.velocity.add(this.acceleration); this.position.add(this.velocity); this.lifespan -= 2; this.acceleration.mult(0); }
show() { stroke(0, this.lifespan); strokeWeight(2); fill(127, this.lifespan); circle(this.position.x, this.position.y, 8); }
isDead() { return this.lifespan < 0.0; }}
let emitters = [];
function setup() { createCanvas(640, 240); createP("Click para agregar sistemas de partículas.");}
function draw() { background(255); for (let emitter of emitters) { emitter.run(); emitter.addParticle(); }}
function mousePressed() { emitters.push(new Emitter(mouseX, mouseY));}
-
3 - Nombre: Particle System with Inheritance and Polymorphism. - Concepto: Aleatoreidad (Unidad 1) - Aplicación: Siento que aquí hasta cierto punto ya se usa este concepto, pero la idea es añadir otra figura (triángulos) y colores a las partículas.
Explicación: Este sistema demuestra cómo aplicar la aleatoriedad mediante herencia y polimorfismo. Heredando de la clase Particle, se crean subclases como Confetti (cuadrado rotado) y TriangleParticle (triángulo), y se sobrescribe el método show() en cada una para representarlas gráficamente de manera distinta. Además, se introduce aleatoriedad en la selección de tipos de partícula y en sus colores. Cada vez que se añade una partícula al sistema, se escoge aleatoriamente entre tres tipos. Esto genera un sistema visualmente más dinámico y demuestra cómo la programación orientada a objetos facilita la extensión del comportamiento sin modificar la lógica principal del sistema, la cual de por sí ya tenía cierta aleatoreidad implementada. También, las partículas se eliminan de memoria cuando su vida (lifespan) llega a cero, lo cual es importante para mantener el rendimiento, especialmente con sistemas que generan muchas instancias a lo largo del tiempo.
Código:
class Particle { constructor(x, y) { this.position = createVector(x, y); this.acceleration = createVector(0, 0); this.velocity = createVector(random(-1, 1), random(-1, 0)); this.lifespan = 255.0; this.color = color(random(255), random(255), random(255), this.lifespan); }
run() { let gravity = createVector(0, 0.05); this.applyForce(gravity); this.update(); this.show(); }
applyForce(force) { this.acceleration.add(force); }
update() { this.velocity.add(this.acceleration); this.position.add(this.velocity); this.lifespan -= 2; this.acceleration.mult(0); }
show() { stroke(0, this.lifespan); strokeWeight(2); fill(this.color); circle(this.position.x, this.position.y, 8); }
isDead() { return this.lifespan < 0.0; }}
class Confetti extends Particle { show() { let angle = map(this.position.x, 0, width, 0, TWO_PI * 2); rectMode(CENTER); fill(this.color); stroke(0, this.lifespan); strokeWeight(2); push(); translate(this.position.x, this.position.y); rotate(angle); square(0, 0, 12); pop(); }}
class TriangleParticle extends Particle { show() { fill(this.color); stroke(0, this.lifespan); strokeWeight(2); push(); translate(this.position.x, this.position.y); beginShape(); vertex(-6, 6); vertex(6, 6); vertex(0, -6); endShape(CLOSE); pop(); }}
class Emitter { constructor(x, y) { this.origin = createVector(x, y); this.particles = []; }
addParticle() { let r = random(1); if (r < 0.33) { this.particles.push(new Particle(this.origin.x, this.origin.y)); } else if (r < 0.66) { this.particles.push(new Confetti(this.origin.x, this.origin.y)); } else { this.particles.push(new TriangleParticle(this.origin.x, this.origin.y)); } }
run() { for (let i = this.particles.length - 1; i >= 0; i--) { let p = this.particles[i]; p.run(); if (p.isDead()) { this.particles.splice(i, 1); } } }}
let emitter;
function setup() { createCanvas(640, 240); emitter = new Emitter(width / 2, 20);}
function draw() { background(255); emitter.addParticle(); emitter.run();}
-
4- Nombre: Particle System with Forces. - Concepto: Movimiento oscilatorio (Unidad 4) - Aplicación: La idea es reemplazar la estela que dejan las partículas al caer, por unas ondas, es decir, que estas partículas en lugar de dejar esa especie de trail, generen ondas a medida que van cayendo, como si fueran pulsaciones.
Explicación: La forma más sencilla y visual de representar el rastro oscilante es con un movimiento senoidal horizontal, o sea que, mientras las partículas caen verticalmente por la gravedad, su posición X oscila con el tiempo usando una función sin(), lo cual da una especie de simulación visual de trail de ondas. Me parecía ideal utilizar aquí este concepto ya que aparte de ser el escenario perfecto para que se note entre todos los sistemas de partículas propuestos, le da además un dinamismo diferente al sistema.
Código:
class Emitter { constructor(x, y) { this.origin = createVector(x, y); this.particles = []; }
addParticle() { this.particles.push(new Particle(this.origin.x, this.origin.y)); }
applyForce(force) { for (let particle of this.particles) { particle.applyForce(force); } }
run() { for (let i = this.particles.length - 1; i >= 0; i--) { const particle = this.particles[i]; particle.run(); if (particle.isDead()) { this.particles.splice(i, 1); } } }}
class Particle { constructor(x, y) { this.basePosition = createVector(x, y); // Referencia original this.position = createVector(x, y); this.acceleration = createVector(0, 0); this.velocity = createVector(random(-1, 1), random(-2, 0)); this.lifespan = 255.0; this.mass = 1; this.theta = random(TWO_PI); // fase inicial this.amplitude = random(10, 30); // amplitud de oscilación this.oscillationSpeed = random(0.05, 0.1); // velocidad de oscilación }
run() { this.update(); this.show(); }
applyForce(force) { let f = force.copy(); f.div(this.mass); this.acceleration.add(f); }
update() { this.velocity.add(this.acceleration); this.basePosition.add(this.velocity); // solo mover base Y this.theta += this.oscillationSpeed; // aumenta el ángulo this.position.x = this.basePosition.x + sin(this.theta) * this.amplitude; this.position.y = this.basePosition.y; // mantener en Y this.acceleration.mult(0); this.lifespan -= 2.0; }
show() { stroke(0, this.lifespan); strokeWeight(2); fill(127, this.lifespan); circle(this.position.x, this.position.y, 8); }
isDead() { return this.lifespan < 0.0; }}
let emitter;
function setup() { createCanvas(1280, 480); emitter = new Emitter(width / 2, 50);}
function draw() { background(255, 30);
let gravity = createVector(0, 0.1); emitter.applyForce(gravity);
emitter.addParticle(); emitter.run();}
-
5 - Nombre: Particle System with a Repeller. - Concepto: Atracción gravitacional (Unidad 3) - Aplicación: Ya se usaron las 4 unidades así que repetiré este, la idea es que el repelente se convierta en un atractor, que este absorba las partículas y se las “trague”.
Explicación: Para convertir el repeller en un atractor, simplemente invertimos el signo del cálculo para que sea positivo, o sea que ahora las partículas son atraídas, no repelidas. Me parece que este era el lugar perfecto para hacer un atractor jajaja ya que de esta manera le estamos dando completamente la vuelta a la gracia de este sistema de partículas.
Link: Sistema de partículas con repeller convertido en attractor
Código:
class Emitter {
constructor(x, y) { this.origin = createVector(x, y); this.particles = []; }
addParticle() { this.particles.push(new Particle(this.origin.x, this.origin.y)); }
applyForce(force) { //{!3} Applying a force as a p5.Vector for (let particle of this.particles) { particle.applyForce(force); } }
applyAttractor(attractor) { for (let particle of this.particles) { let force = attractor.attract(particle); particle.applyForce(force); }}
run() { for (let i = this.particles.length - 1; i >= 0; i--) { const particle = this.particles[i]; particle.run(); if (particle.isDead()) { this.particles.splice(i, 1); } } }}
class Particle { constructor(x, y) { this.position = createVector(x, y); this.velocity = createVector(random(-0.5, 0.5), random(-0.5, 0)); this.acceleration = createVector(0, 0); this.lifespan = 255.0; }
run() { this.update(); this.show(); }
applyForce(f) { this.acceleration.add(f); }
// Method to update position update() { this.velocity.add(this.acceleration); this.position.add(this.velocity); this.lifespan -= 2; this.acceleration.mult(0); }
// Method to display show() { stroke(0, this.lifespan); strokeWeight(2); fill(127, this.lifespan); circle(this.position.x, this.position.y, 8); }
// Is the particle still useful? isDead() { return this.lifespan < 0.0; }}
class Attractor { constructor(x, y) { this.position = createVector(100, 100); this.power = 100; // Fuerza de atracción }
show() { stroke(0); strokeWeight(2); fill(200, 50, 50); // Color rojo para resaltar que "absorbe" circle(this.position.x, this.position.y, 40); }
attract(particle) { let force = p5.Vector.sub(this.position, particle.position); let distance = force.mag(); distance = constrain(distance, 5, 50); let strength = (this.power) / (distance * distance); // signo positivo ahora force.setMag(strength); return force; }}
let emitter;
//{!1} One repellerlet attractor;
function setup() { createCanvas(640 , 640); emitter = new Emitter(width / 2, 60); attractor = new Attractor(width / 2, 250);}function draw() { background(255); emitter.addParticle();
let gravity = createVector(0, 0.05); emitter.applyForce(gravity);
emitter.applyAttractor(attractor); // ahora es atractor emitter.run();
attractor.show();}
Aplicación 🛠
En esta fase, aplicarás los conceptos que aprendiste en las fases anteriores para resolver un problema de diseño en el que puedas aplicar los conceptos de herencia y polimorfismo con partículas.
Actividad 03
Obra de arte generativa algorítmica interactiva en tiempo real
🎯 Enunciado: diseña e implementa una obra de arte generativa algorítmica interactiva en tiempo real en p5.js que cumpla con los siguientes requisitos:
- Debes utilizar los conceptos de herencia y polimorfismo que revisaste en la fase de investigación.
- Debes utilizar al menos un concepto de cada una de las unidades anteriores: 4 conceptos.
- Debes definir cómo vas a gestionar el tiempo de vida de las partículas y la memoria.
- La obra debe ser interactiva en tiempo real. Puedes usar teclado, mouse, música, el micrófono, video, sensor o cualquier otro dispositivo de entrada.
- Documenta el proceso de creación, incluyendo la idea inicial, bocetos, experimentación con el código y el resultado final.
📤 Entrega:
- Enlace a tu obra en el editor de p5.js.
- El código.
- Qué concepto de cada unidad aplicaste, cómo lo aplicaste y por qué.
- Una captura de pantalla con una imagen de tu obra.
🚀 Tu solución:
Obra generativa con partículas!!
Bueno, ahora sí, vamos con la obra de arte generativa…
-
Mi idea es que se implementen aparte de la herencia y el polimorfismo, la aleatoriedad, la aceleración, la gravedad (fuerzas) y las ondas oscilatiorias.
-
Lo que tengo pensado como idea inicial es un espacio, en donde hayan varios attractores que aparezcan aleatoriamente en este espacio, la idea es organizar el código para que no se superpongan entre ellos, que tengan diferentes tamaños y ubicaciones a lo largo del canvas de 800x800, estos atractores tendrán obviamente una función de absorber las partículas, aquí implementamos el concepto de fuerza y claramente la aleatoriedad se implementa en casi que todo el código, pero bueno, sigamos…
Otra interacción clave será con el micrófono, aquí lo que haremos será que al detectar un sonido, aparecerá aleatoriamente en algún lugar de la pantalla un emisor de partículas, claramente este emisor no se quedará para siempre, sólo estará ahí por 1 seg o 2 segs aproximadamente, y lo mismo con sus partículas, tendrán una vida útil limitada, la idea es que si se detecta un sonido aparezcan estos emisores, y entre más alto sea el sonido detectado, más rápido irán las partículas hacia los attractores, es decir, tendrán o ”más aceleración” o en su defecto ”menos peso”, cuando estas lleguen a los attractores y los toquen, deben desaparecer inmediatamente, claramente la idea de esto es que los emisores también tengan cierta aleatoriedad, algunos serán de bolitas normales, otros de confetti, otros de triangulitos, obvio con variedad de colores y eso, también me gustaría que los attractores tengan un efecto oscilatorio, meramente para que el concepto no quede vacío
-
Con todo esto considero que se está haciendo uso de todoo lo requerido, se están haciendo uso de todos los conceptos, de la gestión de vida de las partículas y de la memoria para que no haya una saturación, es interactiva con el micrófono y a continuación mostraré el boceto inicial, y el único cambio que llegué a hacer (esto lo estoy escribiendo después de terminado el código)
Boceto de concepto inicial:
-
En este caso se nota todo lo que quiero lograr, la creación de partículas, la interacción con los attractores, la aleatoriedad, fuerzas, oscilación de los attractores, etc
Me encontré al estar haciendo el código con una propuesta que me resultó interesante, y era de hacer que el fondo cambiara de colores, pero pensé que en es caso entonces también le deberíamos sumar a los attractores un fill para que no se perdieran y a las partículas aleatoriedad en tamaños y colores para que siempre haya una vista diferente del código, por lo cual pasamos de esto:
A esto:
Ese sería el resultado final, realmente me siento bastante satisfecho, se pueden lograr imágenes muy interesantes con diferentes tonos y entre más duro suene más locas serás las partículas
Aquí el link de mi Obra de Arte generativa con Partículas
Y el código utilizado:
class Emitter { constructor(pos, volume) { this.pos = pos.copy(); this.particles = []; this.lifespan = 10000; // ms this.birth = millis();
let count = int(random(10, 20)); for (let i = 0; i < count; i++) { let type = int(random(3)); let p; if (type === 0) p = new BallParticle(this.pos, volume); else if (type === 1) p = new Confetti(this.pos, volume); else p = new TriangleParticle(this.pos, volume); this.particles.push(p); } }
applyAttractors(attractors) { for (let p of this.particles) { for (let a of attractors) { let dir = p5.Vector.sub(a.pos, p.pos); let d = dir.mag(); if (d < a.r) { p.dead = true; } else { dir.normalize(); let force = dir.mult(0.2); p.applyForce(force); } } } }
update() { for (let i = this.particles.length - 1; i >= 0; i--) { this.particles[i].update(); if (this.particles[i].isDead()) this.particles.splice(i, 1); } }
display() { for (let p of this.particles) { p.display(); } }
isDead() { return millis() - this.birth > this.lifespan && this.particles.length === 0; }}
class Particle { constructor(pos, volume) { this.size = random(5, 20); this.col = color(random(100, 255), random(100, 255), random(100, 255)); this.pos = pos.copy(); this.vel = p5.Vector.random2D().mult(2); this.acc = createVector(); this.lifespan = 555; this.volume = volume; this.dead = false; }
applyForce(f) { let scaled = f.copy().mult(map(this.volume, 0.05, 0.5, 1.5, 5)); this.acc.add(scaled); }
update() { this.vel.add(this.acc); this.pos.add(this.vel); this.acc.mult(0); this.lifespan -= 5; if (this.lifespan <= 0) this.dead = true; }
isDead() { return this.dead; }
display() { // abstract }}
class BallParticle extends Particle {display() { noStroke(); fill(this.col.levels[0], this.col.levels[1], this.col.levels[2], this.lifespan); ellipse(this.pos.x, this.pos.y, this.size); }}
class Confetti extends Particle {display() { push(); translate(this.pos.x, this.pos.y); rotate(frameCount * 0.1); noStroke(); fill(this.col.levels[0], this.col.levels[1], this.col.levels[2], this.lifespan); rectMode(CENTER); rect(0, 0, this.size, this.size * 1.2); pop(); }}
class TriangleParticle extends Particle {display() { push(); translate(this.pos.x, this.pos.y); rotate(frameCount * 0.05); noStroke(); fill(this.col.levels[0], this.col.levels[1], this.col.levels[2], this.lifespan); beginShape(); vertex(-this.size / 2, this.size / 2); vertex(this.size / 2, this.size / 2); vertex(0, -this.size / 1.5); endShape(CLOSE); pop(); }}
class Attractor { constructor(pos, r) { this.basePos = pos.copy(); this.pos = pos.copy(); this.r = r; this.oscOffset = random(1000); }
display() { let osc = sin(frameCount * 0.05 + this.oscOffset) * 10; let newR = this.r + osc; fill(255,0,0); stroke(255, 100, 200); strokeWeight(2); ellipse(this.basePos.x, this.basePos.y, newR * 2); }}
let attractors = [];let emitters = [];let mic;let lastEmissionTime = 0;let emissionCooldown = 10; // ms
function setup() { createCanvas(800, 800); mic = new p5.AudioIn(); mic.start();
// Crear attractors aleatorios que no se superpongan let intentos = 0; while (attractors.length < 5 && intentos < 1000) { let r = random(30, 60); let pos = createVector(random(r, width - r), random(r, height - r)); let valido = true; for (let a of attractors) { if (p5.Vector.dist(pos, a.pos) < a.r + r + 20) { valido = false; break; } } if (valido) attractors.push(new Attractor(pos, r)); intentos++; }}
function draw() { let r = map(sin(frameCount * 0.1), -1, 1, 50, 200);let g = map(sin(frameCount * 0.1 + PI/3), -1, 1, 50, 200);let b = map(sin(frameCount * 0.1 + PI/2), -1, 1, 50, 200);background(r, g, b);
// Dibujar attractors for (let a of attractors) { a.display(); }
// Emitir partículas si se detecta sonido fuerte let vol = mic.getLevel(); if (vol > 0.01 && millis() - lastEmissionTime > emissionCooldown) { emitters.push(new Emitter(createVector(random(width), random(height)), vol)); lastEmissionTime = millis(); }
// Actualizar y mostrar todos los emisores y sus partículas for (let i = emitters.length - 1; i >= 0; i--) { emitters[i].applyAttractors(attractors); emitters[i].update(); emitters[i].display(); if (emitters[i].isDead()) emitters.splice(i, 1); }}
Consolidación y metacognición 🤔
En esta fase, consolidarás lo aprendido en la unidad y reflexionarás sobre tu proceso de aprendizaje.
Actividad 04
Consolidación de lo aprendido
🎯 Enunciado: en esta actividad vas a revisar y sintetizar lo aprendido en la unidad.
⚠️ IMPORTANTE: te ruego que no uses chatGPT para resolver esta actividad. La idea es que hagas un ejercicio de reflexión y consolidación de lo aprendido.
✅ 1. ¿Cómo se gestiona la creación y la desaparición de las partículas y cómo se gestiona la memoria?
✅ 2. ¿Cómo se aplica el marco de movimiento motion 101 en los sistemas de partículas que analizaste en la actividad anterior?
✅ 3. ¿Cómo se aplican fuerzas externas a los sistemas de partículas que trabajaste en la unidad? ¿Qué fuerzas se aplicaron y cómo están modeladas?
✅ 4. ¿Cómo se aplicaste los conceptos de herencia y polimorfismo en los sistemas de partículas que trabajaste en la unidad?
📤 Entrega: responde a las preguntas del enunciado en tu bitácora.
🚀 Tu solución:
Consolidación de lo aprendido
-
Gestión de la creación y desaparición de partículas y administración de memoria
En los diferentes sistemas de partículas de la undad, se utilizaron principalmente arreglos para gestionar la creación, desapareción y la memoria de los sistemas, aunque hubo ciertas variaciones, ya que en uno que otro habían interacciones, (Como por ejemplo en systems of systems, en donde poníamos los emisores con un click), todo se basa en conceptos bases clave, y es que estas salen del emisor, se almacenan en un array, y tienen unos ciclos de vida predefinidos limitados, cuando estos ciclos de vida acaban y la partícula se considera muerta, se eliminan de los arrays y así se evita la saturación de la memoria y se mantiene el código optimizado.
-
Aplicación del marco de movimiento Motion 101 en los sistemas de partículas
Realmente el marco de movimiento se aplica bastante normal, tal y como se ha aplicado en códigos de unidades anteriores, pero en este caso directamente a las partículas y no a los emisores, esto quiere decir que en cada actualización la aceleración acumulada se suma a la velocidad, y esta a su vez a la posición, generando un movimiento fluido y realista y por último la aceleración se reinicia a cero para permitir que las nuevas fuerzas del siguiente frame sean aplicadas correctamente. Nada del otro mundo, todo muy normal, pero en este caso aplicado directamente en la clase de particle.js, siempre se aplica ahí en la parte de update
-
Aplicación de fuerzas externas en los sistemas de partículas
La aplicación de las fuerzas externas también está en la clase de particle.js, y de hecho, justo arribita de la aplicación del marco 101, en la parte de run() y no es difícil notarlo, si se toma como ejemplo el código de system of systems (O de múltiples emisores), se ve como justo en esa parte está presenta la fuerza de gravedad, por obvias razones estas partículas deben seguir un comportamiento lógico, es lo que uno se espera, y en estos casos lo que podemos ver es esto, unas cuantas líneas que hacen que la partícula se vea afectada entre otras cosas por una fuerza gravitacional. También debo destacar que por ejemplo en el código en el cual hay un repeller, para lograr esta repulsión se calcula una fuerza similar a la gravitacional pero invertida, y luego están mis códigos, en donde aparte de esta fuerza gravitacional presente constantemente, se encuentran fuerzas hacia attractores, hacia el mouse, etc, todo modelado con una fuerza de atracción pero enfocadas en diferentes objetos o lugares, como ya he dicho, nada del otro mundo.
-
Uso de herencia y polimorfismo en los sistemas de partículas
Esto creo que sólo está presente en el sistema de partículas de “Particle System with Inheritance and Polymorphism” que pues, precisamente está hecho para hablar de esto e introducir los conceptos (O al menos darles un repaso) y en mi código de arte generativo, en todo caso, a través de la herencia, se definió una clase base Particle que contiene propiedades como la posición, velocidad, aceleración y métodos, y de esta clase se derivan otras subclases como confetti por ejemplo, es entonces cuando el polimorfismo se evidencia al tratar objetos de distintas subclases como si fueran de la clase base pero redefiniendo métodos según las distintas necesidades, como hice en mi caso que aparte de confetti también hice otra subclase de triangulitos
Actividad 05
Autoevaluación
🎯 Enunciado: evalúa tu propio proceso y detecta áreas de mejora. Responde las siguientes preguntas en un texto breve (mínimo 5 líneas por pregunta):
✅ 1. En lo que llevas de la carrera has utilizado la programación orientada a objetos en varios proyectos. Tal vez usaste el concepto de polimorfismo sin entender completamente qué significa. Luego de realizar esta unidad ¿Consideras que entiendes mejor este concepto? ¿Por qué si o por qué no?
✅ 2. ¿Qué partes de esta unidad te resultaron más fáciles? ¿Por qué?
✅ 3. ¿Qué parte te pareció más difícil o te tomó más tiempo? ¿Cómo la resolviste?
✅ 4. Si pudieras repetir esta unidad, ¿Qué harías diferente para mejorar tu comprensión de los conceptos?
✅ 5. ¿Crees que lo que aprendiste en esta unidad te servirá en futuros proyectos? ¿Por qué si o por qué no?
✅ 6. ¿Qué parte de esta unidad te gustaría profundizar más? ¿Por qué?
✅ 7. ¿Qué concepto de esta unidad se podría aplicar a tu área de interés profesional? ¿Por qué?
📤 Entrega: responde de maneara reflexiva y con autocrítica a las preguntas planteadas en el enunciado.
🚀 Tu solución:
Autoevaluación
-
1. En lo que llevas de la carrera has utilizado la programación orientada a objetos en varios proyectos. Tal vez usaste el concepto de polimorfismo sin entender completamente qué significa. Luego de realizar esta unidad ¿Consideras que entiendes mejor este concepto? ¿Por qué si o por qué no?
Sí, es un hecho que durante la carrera llegué a hacer varios trabajos con el concepto de polimorfismo, sin embargo, llevaba de hecho bastantes semestre sin utilizar ni este concepto, ni el de herencia, y bueno, a decir verdad tampoco la programación orientada a objetos, hasta llegar a este curso en que nuevamente vimos una programación en la que se utilizan directamente estas cosas, y de hecho sí, si me queda más claro, o mejor dicho, estos trabajos me ayudaron a refrescar la memoria, considero que ya tenía bastante claridad respecto al concepto, sin embargo, lo que hemos hecho en esta unidad me ayuda a corroborar que estaba en lo correcto desde antes, que tenía el concepto claro y que a pesar de haber pasado ya varios semestres sin ver nada al respecto, fue algo que realmente se me quedó ya que estuvimos trabajando durante casi todo un semestre con este término, entre otros.
-
2. ¿Qué partes de esta unidad te resultaron más fáciles? ¿Por qué?
La verdad no diría que fáciles, sólo que realmente lo que había que comprender era algo que prácticamente ya tenía que haberse hecho para las actividades anteriores, y con esto me refiero específicamente a la consolidación, me parece que simplemente debía escribir qué era lo que había pasado, realmente si de algo no me acordaba sólo debía ir al código y leer nuevamente cómo estaba escrita la lógica de los sistemas de partículas propuestos, y con eso las preguntas prácticamente se respondían solas.
-
3. ¿Qué parte te pareció más difícil o te tomó más tiempo? ¿Cómo la resolviste?
La parte que más tiempo me tomó fue la de los diferentes sistemas de partículas propuestos, en esta parte me confié y no leí bien, creí que eran referencias y poco más, sin embargo, al ver que tocaba modificarlos la cosa fue muy diferente, y más el hecho de tener que combinar estos nuevos códigos con conceptos de unidades anteriores, no por dificultad, sino por cuestión de ponerme a pensar, lo cual alargaba aún más el tiempo que creí que me iba a tomar, pero bueno, claramente para esto lo único que hice fue asociar los códigos con los conceptos que más fáciles se integraran a ellos, como fue por ejemplo en la aleatoriedad con el sistema en que aparte de partículas normales habían cuadrados, sólo añadí más aleatoriedad al visual y poco más, y así con todos ya que el tiempo que creí que me iba a gastar se alargó exponencialmente entre más leía la actividad.
-
4. Si pudieras repetir esta unidad, ¿Qué harías diferente para mejorar tu comprensión de los conceptos?
Debo decir que chatgpt me ayudó como siempre con la codificación ya que me corrigió errores que llegado a cierto punto yo no sabía como corregir, así que claramente la cosa va por este lado, si repitiera esta unidad claramente lo que haría para mejorar mi comprensión sería tratar de irme hasta el final con mis capacidades de codificación, claramente no creo que sea una buena idea ya que aún hay varias cosas en este apartado en las que flaqueo, pero es un hecho que si reduzco cada vez más la utilización de este tipo de herramientas por mi parte aunque tendré que poner más mentalmente, es un hecho que la consolidación será aún mejor, al igual que mejorarán mis habilidades en programación, y lógica.
-
5. ¿Crees que lo que aprendiste en esta unidad te servirá en futuros proyectos? ¿Por qué si o por qué no?
Claro que sí, aunque mi enfoque no es la programación, es algo que cada vez veo más necesario comprender, es un lenguaje que entre más comprendas, mejor te irá en este mundo digital, y es que aunque todo está en constante evolución, todo evoluciona sobre lo que ya está inventado, lo que pasa es que se innova todo el tiempo, y algo muy importante que sí es parte de mi campo de esta unidad, que pues, es lo principal pero obvio debía hacer mención a la programación, son los sistemas de partículas, eso es algo que sí o sí debo aprender a dominar eventualmente, a crear cualquier partícula de la nada, hacer sistemas interactivos y hacer que estos tengan una sinergia con los productos que pienso hacer, mis animaciones, mis efectos, mis diseños, etc.
-
6. ¿Qué parte de esta unidad te gustaría profundizar más? ¿Por qué?
Me gustaría profundizar más en la interacción entre sistemas de partículas, ya que es esto lo que me parece clave y lo que le dará un plus a todos esos productos con sistemas de partículas convencionales, los cuales de hecho muchos se encuentran simulados, puede que en tiempo real, puede que como post-procesos, pero en general suele ser así, la idea de dar interacción a estos sistemas es algo que suma mucho, y obvio sé que se hace y que está muy presente en la industria, pero a lo que quiero llegar es que es algo nuevo no para el mundo digital, sino para mí, y quiero aprender todo lo que pueda para poder sacarle todo el jugo creativo posible.
-
7. ¿Qué concepto de esta unidad se podría aplicar a tu área de interés profesional? ¿Por qué?
Aunque suene redundante, es necesario serlo para poder hablar de mi interés profesional, y bueno, nuevamente nos vamos con los sistemas de partículas y la interacción de los mismos con los entornos, o bueno, también entre ellos, para mí este concepto es muy útil para mí y es de mi interés ya que con los sistemas de partículas le puedo dar un toque mágico, personal y distintivo a mis experiencias audiovisuales, sean de la índole que sean, desde diseños interactivos hasta animaciones ya trabajadas y terminadas, las partículas bien utilizadas pueden darle a un entorno mucha magia, hacer que las cosas se sientan muchísimo más, dar una intención diferente o hacer énfasis en la principal del producto, todo esto me parece sumamente importante para lograr dar vida a todos esas historias que tengo en la cabeza.
Actividad 06
Feedback
🎯 Enunciado: ¿Me ayudas a mejorar esta unidad? Responde a las siguientes preguntas pensando en tus compañeros que tomarán este curso en el futuro.
✅ 1. Sobre la dificultad: ¿La unidad fue demasiado fácil, equilibrada o demasiado difícil? ¿Por qué?
✅ 2. Sobre el ritmo: ¿El tiempo asignado fue adecuado?
✅ 3. Sobre los materiales: ¿Qué tan útil fue la estructura de la unidad? ¿Cómo se podrían mejorar?
✅ 4. Sobre la experiencia de aprendizaje: ¿Qué fue lo mejor de esta unidad? ¿Qué te gustaría que se hiciera diferente?
✅ 5. Propuesta de mejora: si fueras el profesor y tuvieras que mejorar esta unidad para los próximos estudiantes, ¿Qué cambiarías y por qué?
📤 Entrega: ¿Me ayudas con estas preguntas justificando de la manera más precisa posible tus argumentos? De verdad, gracias por tu generosidad y sentido crítico.
🚀 Tu solución:
Feedback
-
-
¿La unidad fue demasiado fácil, equilibrada o demasiado difícil? ¿Por qué?
A decir verdad siento que la unidad fue una unidad equilibrada, no diría que fue fácil, quizá si alguien entra de primerazo y no tiene las bases tan firmes sobre los conceptos de herencia y polimorfismo, aparte de no saber desde antes cómo funcionan los sistemas de partículas, podría tener un poco más de dificultad en entender en general, sin embargo, no fue algo sumamente complicado, lo que sí es que la unidad aunque tenía muy pocas actividades, estas fueron muuy largas y quizá la actividad #2 sería algo cansón para muchas personas, ya que aunque se comprende el por qué se pedía lo que se pedía, y como ya dije, eran pocos puntos así que se compensa una cosa con otra, hacer una actividad así de larga realmente cansa bastante y lo único que variaban eran los tipos de sistemas, y los conceptos los cuales debíamos aplicar arbitrariamente, en resumen, fue una unidad equilibrada, tirando a fácil si ya se tenían conceptos base o al menos una idea de estos, pero las actividades a pesar de ser pocas, puede que fueran cansonas debido a su longitud.
-
-
-
¿El tiempo asignado fue adecuado?
A decir verdad, siempre y cuando se tengan en cuenta las horas que cada persona le debe dedicar a las unidades, semanalmente aparte de las horas en clase, me parece que sí es tiempo suficiente, claramente se tiene que hacer una planificación de lo que se va a hacer al empezar cada unidad para poder aprovechar correctamente el tiempo, y claro, en caso de haber alguna duda puntual, tratar de aclararla en cuanto antes, ya que cualquier cosa que impida el correcto avance de las actividades será crucial, son pocas actividades, pero son largas, así que el tiempo apremia, es suficiente, pero se debe aprovechar
-
-
-
¿Qué tan útil fue la estructura de la unidad? ¿Cómo se podrían mejorar?
La estructura de la unidad estuvo bien planteada, nuevamente se basó en un capítulo, hubo códigos propuestos y se invita al estudiante a que haga actividades de análisis, de experimentación, de consolidación de la información y de codificación, todos los recursos son claros, y no es difícil entender qué se debe hacer, aparte ya que se pide que se implementen conceptos ya vistos, para poder dar lugar a la experimentación, no se gasta tanto tiempo con otras cosas, sino en lo que ya había dicho antes, una planifiación para poder integrar la estructura de esta unidad con lo que se nos pide respecto a otros conceptos anteriores
-
-
-
¿Qué fue lo mejor de esta unidad? ¿Qué te gustaría que se hiciera diferente?
Me gustaría que se hiciera diferente la actividad #2, insisto en que aunque fueron pocas actividades, fueron largas y estar tanto tiempo haciendo “lo mismo” pero con ciertas variaciones, puede desmotivar un poco, esta fue la única parte que me parece que fue muuy larga, y que en lugar de haber sido tan larga, se pudo haber dividido en otras actividades pero pidiendo otras cosas, y no lo mismo en diferentes códigos y conceptos, no me parece que estuvo mal, anteriormente mencioné que es claro el por qué se hace de esta manera, se tiene que tener un dominio de los sistemas, entender cómo funciona cada uno, y de paso retomar conceptos anteriores para que estos no se enfríen, pero me parece que pudo haber sido hecho de otra manera así sea para dar la ilusión de que el avance es mayor.
-
-
-
¿Qué cambiarías y por qué?
Si fuera el profesor, cambiaría la distribución de las actividades, como ya dije, aunque fuera para que dé la ilusión de que se está avanzando más aunque sea en pasos pequeños, es preferible sentir eso a sentir que llevas horas en una sóla actividad, quizá estancando, quizá avanzando, pero en la misma, esto en mi caso me desmotivó un poco, me hizo sentir algo abrumado, y es muy probable que no sea el único, siento que tener a los estudiantes motivados es algo muy complicado pero muy gratificante, un estudiante motivado siempre dará más de lo que se le pide, así que considero que como profesor es muy importante tener esto en cuenta a la hora de proponer actividades y prácticas en clase o fuera de ella, sé que el profe en general lo hace aquí, y sé que me estoy repitiendo, pero en esta ocasión lo sentí un poco más pesado a pesar de que fueron menos actividades.
-