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:
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.
1. STATE OF UNION - R. LUKE DUBOIS
Es un proyecto que busca capturar la atención de las personas a través de la crudeza de la realidad. Busca representar la complejidad de temas relacionados a la violencia con armas y a sus víctimas con una visualización de datos que no se reduce a las cifras y su representación con puntos y pixeles, por el contario, decide tomar la narrativa y representarla con un buen storytelling que dignifique las vidas perdidas impactando en las que aún siguen con vida. En su trabajo emplea las armas como los detonadores de la visualización de cifras de violencia en las que se emplean para ejercer violencias sobre otros y también ha empleado el sonido en diagramas de dispersión de algunos gráficos y salpicaduras de sangre muestra de dichas salpicaduras.
Me llama la atención porque tranforma la visualización de datos con storytelling, que muestra que, detrás de cada cifra hay vidas e impactos. Es una nueva visión y un campo de acción interesante de explorar para hacer que los datos se puedan interpretar más allá de lo cuantitativo de maneras interactivas que le faciliten a la audiencia comprender el impacto real de la información.
2. CLOUDS - James George & Jonathan Minard
Es un documental interactivo realizado entre 2012 y 2014 en el que se explora la generación de arte a través de código. Emplearon nubes de puntos para mostrar el movimiento humano de manera atractiva y fluida durante las conversaciones con expertos como una manera interactiva de explicar lo que estaba sucediendo desde diferentes campos de acción como el baile, el storytelling y demás. Fue un proyecto colaborativo muy grande que me abre la mente a explorar nuevas posibilidades de proyectos con colegas y amigos.
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:
SIMULACIONES A ANALIZAR:
1. Revisa detalladamente el ejemplo 4.2: an Array of Particles.
Código original
¿Cómo se está gestionando la creación y la desaparición de las partículas y cómo se gestiona la memoria?
- Asignación de memoria
- Cada vez que creamos una Particle, se reserva espacio en la memoria para su posición, velocidad, aceleración y otros atributos.
- Si no elimináramos partículas, el array particles crecería infinitamente, causando problemas de rendimiento.
- Liberación de memoria
- Cuando una partícula muere, se elimina del array con splice (i, 1), lo que hace que JavaScript libere su referencia en memoria y permita que el garbage collector la elimine en algún momento. Este enfoque es eficiente porque JavaScript maneja la memoria automáticamente, pero si el número de partículas fuera muy alto, podríamos optimizarlo más.
Código modificado
particle.js
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.applyAttraction(mouseX, mouseY); this.update(); this.show(); }
applyForce(force) { this.acceleration.add(force); }
applyAttraction(targetX, targetY) { let target = createVector(targetX, targetY); let force = p5.Vector.sub(target, this.position); let distance = force.mag(); distance = constrain(distance, 5, 80); force.normalize(); let strength = 8 / distance; force.mult(strength); this.applyForce(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; }}
sketch.js
let particles = [];const MAX_PARTICLES = 200;const MIN_PARTICLES = 50; // Para evitar que se queden sin partículas
function setup() { createCanvas(640, 240);}
function draw() { background(255);
// Calculamos la velocidad del mouse let mouseSpeed = dist(mouseX, mouseY, pmouseX, pmouseY);
// Mapeamos la velocidad del mouse a la cantidad de partículas creadas let particlesToAdd = map(mouseSpeed, 0, 50, 1, 5); // De 1 a 5 partículas
// Agregar partículas según la velocidad del mouse if (particles.length < MAX_PARTICLES) { for (let i = 0; i < particlesToAdd; i++) { particles.push(new Particle(mouseX, mouseY)); } }
// Recorrer partículas y actualizar for (let i = particles.length - 1; i >= 0; i--) { let particle = particles[i]; particle.run();
// Solo eliminar si hay suficientes partículas para mantener la fluidez if (particle.isDead() && particles.length > MIN_PARTICLES) { particles.splice(i, 1); } }}
🌳Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
-
Hice que las partículas aparezcan y desaparezcan de manera controlada. Con este sistema, evitamos que el programa se vuelva lento por tener demasiadas partículas al mismo tiempo.
-
Creación:
- Cada vez que el programa dibuja un nuevo cuadro, revisa qué tan rápido se está moviendo el mouse.
- Si el mouse está quieto, aparecen pocas partículas.
- Si el mouse se mueve rápido, aparecen más.
- Las partículas se crean justo en la posición del mouse y empiezan a moverse solas.
-
Desaparición:
- Cada partícula tiene un “tiempo de vida” que se va reduciendo con el tiempo.
- Cuando su tiempo de vida llega a 0, la eliminamos del arreglo que las guarda.
- Si ya hay muchas partículas, también eliminamos algunas para que la pantalla no se llene demasiado.
🌳Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
Concepto aplicado
- Apliqué una fuerza de atracción inversamente proporcional a la distancia, es decir que, si la partícula está lejos del mouse, la atracción es más débil. Si la partícula está cerca del mouse, la atracción es más fuerte.
Concepto aplicado y cómo lo apliqué
- Calculé la dirección hacia el mouse, para cada partícula, obtuve un vector que apunta desde su posición hasta el mouse.
- Medí la distancia entre la partícula y el mouse, esto me permite ajustar la intensidad de la atracción.
- Normalicé el vector para que solo indique dirección, así evité que partículas muy lejos reciban una fuerza excesiva.
- Multipliqué la fuerza por un valor inversamente proporcional a la distancia
- Apliqué la fuerza a la partícula, lo que hace que la partícula cambie su aceleración y se mueva hacia el mouse.
¿Por qué?
- Para que las partículas reaccionen al mouse de forma natural en lugar de moverse de manera brusca.
- Si usara una fuerza constante, todas las partículas se moverían igual sin importar la distancia y haría que la simulación fuera monótona.
- Para mejorar la visualización de la simulación, dándole una mejor interacción y dinamismo con el mouse.
2. Analiza el ejemplo 4.4: a System of Systems.
Código original
¿Cómo se está gestionando la creación y la desaparción de las partículas y cómo se gestiona la memoria?
-
Creación:
- Cada vez que se crea un Emisor (Emitter), se inicializa en una posición específica.
- En cada ciclo de draw(), los emisores generan nuevas partículas en su posición usando addParticle().
- Estas partículas se agregan a la lista this.particles dentro de cada Emitter.
-
Desaparición:
- Cada partícula tiene una variable lifespan que disminuye en cada frame.
- Cuando lifespan llega a 0, la partícula se considera “muerta”.
- En run(), se revisa cada partícula con isDead(), y si está muerta, se elimina con splice(i,1). Esto se hace recorriendo el array de atrás hacia adelante (for (let i = this.particles.length - 1; i >= 0; i—)), evitando errores al eliminar elementos dentro de un bucle.
-
Gestión de memoria en la simulación
- Se usa splice(i, 1) para eliminar partículas que han agotado su tiempo de vida. Esto evita acumulación innecesaria de objetos en la memoria, manteniendo el código eficiente.
- Cada Emitter maneja su propia lista de partículas de forma independiente.
- No hay eliminación automática de emisores, lo que podría hacer que la simulación consuma más memoria con el tiempo si se crean demasiados.
- No se almacenan partículas innecesarias.
Código modificado
emitter.js
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(gravity, time) { for (let i = this.particles.length - 1; i >= 0; i--) { let p = this.particles[i]; p.run(gravity, time); if (p.isDead()) { this.particles.splice(i, 1); } } }}
particle.js
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;
// Tamaño usando vuelo de Lévy this.size = this.levySize();
// Offsets para Perlin Noise en color this.colorOffsetR = random(1000); this.colorOffsetG = random(1000); this.colorOffsetB = random(1000); }
run(gravity, time) { this.applyForce(gravity); this.levyFlight(); this.update(); this.show(time); }
applyForce(force) { this.acceleration.add(force); }
levyFlight() { if (random() < 0.1) { let angle = random(TWO_PI); let step = pow(random(1), -1.5); // Vuelo de Lévy this.velocity.add(p5.Vector.fromAngle(angle).mult(step)); } }
levySize() { // Generamos un tamaño usando vuelo de Lévy let step = pow(random(1), -1.5) * 5; // Factor para escalar el tamaño return constrain(step, 5, 20); // Limitamos a un rango razonable }
update() { this.velocity.add(this.acceleration); this.position.add(this.velocity); this.lifespan -= 2; this.acceleration.mult(0); }
show(time) { let r = map(noise(this.colorOffsetR + time * 0.01), 0, 1, 50, 255); let g = map(noise(this.colorOffsetG + time * 0.01), 0, 1, 50, 255); let b = map(noise(this.colorOffsetB + time * 0.01), 0, 1, 50, 255);
stroke(0, this.lifespan); strokeWeight(2); fill(r, g, b, this.lifespan); circle(this.position.x, this.position.y, this.size); }
isDead() { return this.lifespan < 0.0 || this.position.y > height || this.position.x < 0 || this.position.x > width; }}
sketch.js
let emitters = [];let gravity;let time = 0; // Para variar el ruido de Perlin con el tiempo
function setup() { createCanvas(640, 240); gravity = createVector(0, 0.05);}
function draw() { background(255); time += 1;
for (let emitter of emitters) { emitter.run(gravity, time); if (mouseIsPressed) { // Solo genera si el mouse está presionado emitter.addParticle(); } }}
function mousePressed() { emitters = []; // Elimina todos los emitters anteriores let emitter = new Emitter(mouseX, mouseY); emitters.push(emitter); for (let i = 0; i < 10; i++) { emitter.addParticle(); }}
🌳Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
-
Creación de partículas:
- Cada vez que el usuario hace clic, se genera un nuevo Emitter en la posición del mouse, y eliminamos cualquier Emitter anterior para evitar acumulaciones innecesarias. Esto significa que siempre hay un único Emitter en pantalla.
- Dentro del Emitter, las partículas se crean de dos formas: Cuando se hace clic, se generan 10 partículas iniciales. Mientras el mouse está presionado, el Emitter sigue generando nuevas partículas.
-
Desaparición:
- Cada partícula tiene una vida útil (lifespan) que disminuye con el tiempo. También se eliminan si salen del área del canvas.
- En cada frame, revisamos si una partícula ha “muerto” y la eliminamos de la lista, lo que ayuda a mantener el rendimiento y la eficiencia en el uso de la memoria.
🌳Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
Concepto aplicado y cómo lo apliqué
- Apliqué distintas distribuciones:
- Ruido de Perlin para el color ya que cada partícula tiene valores únicos para R, G y B, que se generan usando Perlin Noise. Estos valores cambian con el tiempo para crear transiciones de color más suaves y orgánicas.
- Distribución normal para la velocidad inicial, lugar de asignar velocidades completamente aleatorias, utilicé una distribución normal para que la mayoría de las partículas tengan velocidades cercanas a un valor promedio, con algunas pocas siendo mucho más rápidas o lentas.
- Vuelo de Lévy para el tamaño y movimiento porque el tamaño de las partículas se genera con una distribución de Vuelo de Lévy, lo que significa que la mayoría son pequeñas, pero ocasionalmente aparecen algunas más grandes. También se aplica a su movimiento para que, en ocasiones, las partículas hagan saltos grandes en direcciones aleatorias.
¿Por qué?
- El ruido de perlin: genera cambios suaves y naturales, evitando cambios bruscos de color.
- Distribución normal: Hace que la dispersión de las partículas sea más realista pues en el mundo real, la mayoría de los fenómenos físicos siguen distribuciones normales.
- Vuelo de Lévy: Hace que algunas partículas realicen “saltos” grandes en lugar de moverse de manera uniforme generando un efecto más dinámico e impredecible y aumentando la variabilidad visual.
3. Analiza el ejemplo 4.5: a Particle System with Inheritance and Polymorphism.
Código original
¿Cómo se está gestionando la creación y la desaparición de las partículas y cómo se gestiona la memoria?
-
Creación:
- En cada frame (draw() en sketch.js), se llama a emitter.addParticle(), lo que añade una nueva partícula al sistema.
- La partícula puede ser un Confetti (cuadrado) o una Particle (círculo), con un 50% de probabilidad para cada una.
- Todas las partículas inician en la misma posición this.origin (el punto del emisor).
-
Desaparición:
-
En cada frame run() se actualiza cada partícula (p.run()), verificando si su ciclo de vida lifespan es menor a 0.
-
Si la partícula “ha muerto”, se elimina del array de particles con splice(i,1).
-
Gestión de memoria: Se eliminan del array las partículas inactivas para evitar la acumulación de memoria.
Código modificado
confetti.js
class Confetti extends Particle { show() { let angle = map(this.position.x, 0, width, 0, TWO_PI * 2); rectMode(CENTER); fill(this.painted ? color(128, 0, 128) : color(127, this.lifespan)); stroke(0, this.lifespan); push(); translate(this.position.x, this.position.y); rotate(angle); square(0, 0, 12); pop(); }}
emitter.js
class Emitter { constructor(x, y) { this.origin = createVector(x, y); this.particles = []; }
addParticle() { let r = random(1); if (r < 0.5) { this.particles.push(new Particle(this.origin.x, this.origin.y)); } else { this.particles.push(new Confetti(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); } } }
getParticles() { return this.particles; }}
particle.js
class Particle { constructor(x, y) { this.position = createVector(x, y); this.velocity = createVector(random(-1, 1), random(-1, 0)); this.acceleration = createVector(0, 0); this.lifespan = 255; this.size = 8; this.painted = false; }
run() { this.applyForce(createVector(0, 0.05)); 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); fill(this.painted ? color(128, 0, 128) : color(127, this.lifespan)); circle(this.position.x, this.position.y, this.size); }
isDead() { return this.lifespan < 0; }}
pendulum.js
class Pendulum { constructor(x, y, r) { this.pivot = createVector(x, y); this.bob = createVector(); this.r = r; this.angle = PI / 4;
this.angleVelocity = 0.0; this.angleAcceleration = 0.0; this.damping = 0.995; // Amortiguación this.ballr = 20; // Radio del bob this.dragging = false; }
update() { if (!this.dragging) { let gravity = 0.4; this.angleAcceleration = (-gravity / this.r) * sin(this.angle); this.angleVelocity += this.angleAcceleration; this.angle += this.angleVelocity; this.angleVelocity *= this.damping; } }
show() { this.bob.set(this.r * sin(this.angle), this.r * cos(this.angle)); this.bob.add(this.pivot);
stroke(0); strokeWeight(2); line(this.pivot.x, this.pivot.y, this.bob.x, this.bob.y); fill(128, 0, 128); noStroke(); circle(this.bob.x, this.bob.y, this.ballr * 2); }
clicked(mx, my) { let d = dist(mx, my, this.bob.x, this.bob.y); if (d < this.ballr) { this.dragging = true; } }
stopDragging() { this.angleVelocity = 0; this.dragging = false; }
drag() { if (this.dragging) { let diff = p5.Vector.sub(this.pivot, createVector(mouseX, mouseY)); this.angle = atan2(-diff.y, diff.x) - PI / 2; } }
checkCollision(particles) { for (let p of particles) { let d = dist(this.bob.x, this.bob.y, p.position.x, p.position.y); if (d < this.ballr + p.size / 2) { p.painted = true; } } }}
sketch.js
let emitter;let pendulum;
function setup() { createCanvas(640, 240); emitter = new Emitter(width / 2, 20); pendulum = new Pendulum(width / 2, 20, 150);}
function draw() { background(255);
emitter.addParticle(); emitter.run();
pendulum.update(); pendulum.drag(); pendulum.checkCollision(emitter.getParticles()); // Detectar colisión con partículas pendulum.show();}
function mousePressed() { pendulum.clicked(mouseX, mouseY);}
function mouseReleased() { pendulum.stopDragging();}
🌳Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
- No realicé ninguna modificación en cuanto a la generación de partículas porque quería realizar los cambios desde la integración de un nuevo concepto visto en unidades anteriores. Así que las partículas se siguen generando gracias al emitter, siguen estando las posibilidades 50/50 de que la partícula sea un cuadrado (cofetti.js) o un círculo en (particle.js). Y se siguen desapareciendo si su ciclo de vida es menor a 0, para evitar saturar la memoria.
🌳Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
Concepto aplicado y cómo lo apliqué
- Regresé al concepto del péndulo. La idea era que en la parte inferior del canvas estuviera un péndulo que al entrar en contacto con las partículas que se generaban gracias al emitter, las pintara de color uva.
Creé una clase pendulum.js para que contuviera al péndulo simple y en esta misma clase hay una función checkCollision() que analiza si la partícula entra en contacto con el bob y si es así lo pinta del color indicado.
¿Por qué?
- Quería aplicar el concepto de resorte pero me di cuenta que no era óptimo para este ejemplo, incluso si era un resorte simple. Así que decidí replantear el concepto y fue allí donde me percaté que el movimiento natural de un péndulo podría sin mucho esfuerzo crear una buena interacción con las partículas.
4. Analiza el ejemplo 4.6: a Particle System with Forces.
¿Cómo se está gestionando la creación y la desaparición de las partículas y cómo se gestiona la memoria?
Código original
¿Cómo se está gestionando la creación y la desaparición de las partículas y cómo se gestiona la memoria en cada una de las simulaciones?
-
Creación: Sigue funcionando con el ciclo draw(), el emitter() y el addParticle() y el número de partículas crece indefinidamente hasta que son eliminadas.
- Se instancia un nuevo objeto Particle, se almacena en el array particles[] dentro del Emitter.
- Cada partícula tiene una posición inicial (this.origin.x, this.origin.y).
- Se crea con una velocidad inicial aleatoria (random(-1, 1) en X y random(-2, 0) en Y).
-
Gestión de la memoria y eliminación de partículas:
- Cada partícula tiene una propiedad lifespan (inicialmente 255) que disminuye con el tiempo en update().
- Cuando lifespan < 0, la partícula es considerada “muerta”. Para eliminarla, en Emitter.run() se usa un bucle inverso (for de atrás hacia adelante) para recorrer el array particles[].
- Si particle.isDead() retorna true (cuando lifespan < 0), la partícula se elimina con splice(i, 1).
- Se recorre el array de forma inversa para evitar problemas con los índices al eliminar elementos.
Código modificado
emitter.js
class Emitter { constructor(x, y, inverted = false) { this.origin = createVector(x, y); this.particles = []; this.inverted = inverted; // Indica si es el emisor reflejado }
addParticle() { let xOffset = randomGaussian(0, 40); let yOffset = randomGaussian(0, 25);
let x = this.origin.x + xOffset; let y = this.origin.y + (this.inverted ? -yOffset : yOffset); // Invertimos para el reflejado
this.particles.push(new Particle(x, y, this.inverted)); }
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); } } }}
particle.js
class Particle { constructor(x, y, inverted = false) { this.position = createVector(x, y); this.acceleration = createVector(0, 0.0); this.velocity = createVector(random(-1, 1), random(-2, 0)); if (inverted) this.velocity.y *= -1; // Invierte el movimiento si es el reflejado this.lifespan = 255.0; this.mass = 1;
this.r = constrain(randomGaussian(map(x, 0, width, 50, 255), 80), 0, 255); this.g = constrain(randomGaussian(map(y, 0, height, 50, 255), 80), 0, 255); this.b = constrain(randomGaussian(150, 80), 0, 255); }
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.position.add(this.velocity); this.acceleration.mult(0); this.lifespan -= 2.0; }
show() { stroke(0, this.lifespan); strokeWeight(2); fill(this.r, this.g, this.b, this.lifespan); circle(this.position.x, this.position.y, 8); }
isDead() { return this.lifespan < 0.0; }}
sketch.js
let emitter, emitter2;
function setup() { createCanvas(640, 640); emitter = new Emitter(width / 2, 50); // Emisor original emitter2 = new Emitter(width / 2, height - 50, true); // Emisor reflejado}
function draw() { background(255, 30);
let gravity = createVector(0, 0.1); let antiGravity = createVector(0, -0.1); // Para el reflejado
emitter.applyForce(gravity); emitter2.applyForce(antiGravity); // Aplica fuerza hacia arriba
emitter.addParticle(); emitter2.addParticle();
emitter.run(); emitter2.run();}
🌳Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
-
Creación de partículas:
- Tengo dos sistemas de partícula y en cada cuadro draw() se crean nuevas partículas.
- emitter.addParticle() agrega una nueva partícula al sistema original y emitter2.addParticle() agrega las partículas al sistema reflejado.
-
Eliminación:
- Cada partícula tiene una vida útil, la variable lifespan empieza en 255.0 y se reduce en cada frame.
- Se recorre el array de partículas al revés para evitar problemas al eliminar elementos dentro del bucle.
🌳Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
Concepto aplicado y cómo lo apliqué
- En esta simulación, utilicé la distribución normal (o gaussiana) para generar la posición inicial de las partículas y su color. Este tipo de distribución es útil cuando queremos que los valores generados se concentren alrededor de una media, con una probabilidad decreciente a medida que nos alejamos de ella.
¿Por qué?
- Quería simular una cascada y variar un poco la posición en la que se generaban de manera que no fueran muy abruptos los cambios y me pareció divertido que pudieran reflejarse y caer una sobre la otyra pero con distintos colores según la posición. Para la posición, usé randomGaussian() para que las partículas se concentren cerca del emisor con una dispersión natural. Para el color, usé la misma función para generar variaciones suaves en los valores RGB en función de la posición.
Esto permite una simulación más realista, donde la mayoría de las partículas aparecen cerca del origen y solo algunas se alejan, evitando distribuciones artificiales.
5. Analiza el ejemplo 4.7: a Particle System with a Repeller.
Código original
¿Cómo se está gestionando la creación y la desaparición de las partículas y cómo se gestiona la memoria?
-
Creación:
- En cada fotograma (draw()), se llama emitter.addParticle(), que crea una nueva partícula en la posición del emisor.
- Esto significa que una nueva partícula se añade al arreglo particles en cada frame, manteniendo el sistema en constante generación.
- A todas las partículas vivas se les aplica una fuerza de gravedad constante hacia abajo. Una fuerza de repulsión desde el Repeller, que varía dependiendo de la distancia a cada partícula.
-
Desaparición y control de memoria:
- En el método run() de Emitter, se recorre el arreglo particles de atrás hacia adelante.
- Cada partícula tiene un atributo lifespan, que disminuye con el tiempo en update(). Cuando este valor cae por debajo de 0, se considera “muerta”.
Código modificado
emitter.js
class Emitter { constructor(x, y) { this.origin = createVector(x, y); this.particles = []; this.timer = 0; }
addParticle() { this.timer++; if (this.timer % 100 === 0) { this.particles.push(new VectorParticle(this.origin.x, this.origin.y)); } else { this.particles.push(new Particle(this.origin.x, this.origin.y)); } }
applyForce(force) { for (let particle of this.particles) { particle.applyForce(force); } }
applyRepeller(repeller) { for (let particle of this.particles) { let force = repeller.repel(particle); particle.applyForce(force); } }
applyVectorRepel() { let vectors = this.particles.filter(p => p instanceof VectorParticle); for (let vector of vectors) { for (let particle of this.particles) { if (particle !== vector) { let repelForce = vector.repel(particle); particle.applyForce(repelForce); } } } }
run() { this.applyVectorRepel(); 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); } } }}
particle.js
// The Nature of Code// Daniel Shiffman// http://natureofcode.com
// Simple Particle System
// A simple Particle class
class Particle { constructor(x, y) { this.position = createVector(x, y); this.velocity = createVector(random(-1, 1), random(-1, 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; }}
sketch.js
let emitter;
function setup() { createCanvas(640, 240); emitter = new Emitter(width / 2, 60);
}
function draw() { background(255); emitter.addParticle();
let gravity = createVector(0, 0.1); emitter.applyForce(gravity);
emitter.run();
}
🌳Vas a gestionar la creación y la desaparición de las partículas y la memoria. Explica cómo lo hiciste.
- No cambié nada de la generación, eliminación y gestión de partículas en la memoria.
🌳Explica qué concepto aplicaste, cómo lo aplicaste y por qué.
- Apliqué una distribución gaussiana para generar variaciones suaves y naturales en dos aspectos del sistema de partículas: la posición inicial de las partículas y el color
Concepto aplicado y cómo lo apliqué
-
Vectores que representan fuerzas como la gravedad y la repulsión. También apliqué el motion 101 porque cada partícula tiene una posición, una velocidad y una aceleración
-
Partículas especiales con repulsión, inspiradas en la ley de Coulomb que repelen a las demás usando una fuerza basada en la distancia.
Por qué
- Quería explorar con los vectores como entes de repulsión para ver cómo interactuaba una partícula especial con las normales.
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:
Diseño de la obra
Idea inicial:
-
Quería trabajar sobre el ejemplo de polimorfismo y herencia de la actividad anterior porque le veía potencial, así que pensé que una buena idea sería volver a intervenirlo con los siguientes cambios:
- Voy a aplicar los siguientes conceptos: vectores, fuerzas, péndulo (funciones sinusoidales) y distribuciones.
- El canvas será de 500*500
- El nuevo concepto será el de una nube que emite partículas en forma de gotas de lluvia.
- El péndulo tendrá forma de rayo y ademas de cambiar el color de las partículas que toca también cambiará su forma para que sean estrellas
- La gestión de partículas en memoria seguirá igual.
- El color de fondo variará con una distribución gausiana para que cambie sutilmente entre colores azules.
- Quiero que también se puedan crear más partículas presionando una tecla.
Experimentación con código:
- Versión 1: simulación aquí
Cambios para la próxima versión
- Me di cuenta que la idea del rayo no me convencía tanto y las partículas sí se estan transformando en estrellas pero no había tanto dinamismo así que pensé que podía dejar también la funcionalidad del cambio de color para que fueran las probabilidades las que determinen si se cambia de color o de forma.
- Para la vista es muy cansado tener el fondo cambiando ligeramente con la distribución gausseana así que mejor me voy por un solo color.
- Quiero que sea una lluvia de partículas que se generarán en la parte superior de la pantalla
- El nuevo bob será una luna :)
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.
Resultado final
Enlace de la simulación aquí
El código
confetti.js
class Confetti extends Particle { constructor(x, y) { super(x, y); this.star = false; }
show() { rectMode(CENTER); stroke(0, this.lifespan); if (this.transformed) { if (this.star) { fill(255, 215, 0); // Amarillo estrella push(); translate(this.position.x, this.position.y); rotate(frameCount / 50.0); this.drawStar(0, 0, 5, 12, 5); pop(); } else { fill(255, 165, 0); // Naranja push(); translate(this.position.x, this.position.y); rotate(map(this.position.x, 0, width, 0, TWO_PI * 2)); square(0, 0, 12); pop(); } } else { fill(220, 220, 255, this.lifespan); push(); translate(this.position.x, this.position.y); rotate(map(this.position.x, 0, width, 0, TWO_PI * 2)); square(0, 0, 12); pop(); } }
drawStar(x, y, radius1, radius2, npoints) { let angle = TWO_PI / npoints; let halfAngle = angle / 2.0; beginShape(); for (let a = 0; a < TWO_PI; a += angle) { let sx = x + cos(a) * radius2; let sy = y + sin(a) * radius2; vertex(sx, sy); sx = x + cos(a + halfAngle) * radius1; sy = y + sin(a + halfAngle) * radius1; vertex(sx, sy); } endShape(CLOSE); }}
emitter.js
class Emitter { constructor() { this.particles = []; }
addParticle() { let x = width / 2 + randomLevyOffset(80); // Posición horizontal más errática let y = random(0, 10); if (random(1) < 0.5) { this.particles.push(new Particle(x, y)); } else { this.particles.push(new Confetti(x, 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); } } }
getParticles() { return this.particles; }}
particle.js
class Particle { constructor(x, y) { this.position = createVector(x, y); this.velocity = randomLevyVector(2); // Movimiento inicial usando Lévy this.velocity.y = abs(this.velocity.y); // Asegura que se muevan hacia abajo this.acceleration = createVector(0, 0); this.lifespan = 255; this.size = 8; this.transformed = false; }
run() { this.applyForce(createVector(0, 0.05)); 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); fill(this.transformed ? color(255, 165, 0) : color(220, 220, 255, this.lifespan)); circle(this.position.x, this.position.y, this.size); }
isDead() { return this.lifespan < 0; }}
pendulum.js
class Pendulum { constructor(x, y, r) { this.pivot = createVector(x, y); this.bob = createVector(); this.r = r; this.angle = PI / 4; this.angleVelocity = 0; this.angleAcceleration = 0; this.damping = 0.995; this.ballr = 20; this.dragging = false; }
update() { if (!this.dragging) { let gravity = 0.4; this.angleAcceleration = (-gravity / this.r) * sin(this.angle); this.angleVelocity += this.angleAcceleration; this.angle += this.angleVelocity; this.angleVelocity *= this.damping; } }
show() { this.bob.set(this.r * sin(this.angle), this.r * cos(this.angle)); this.bob.add(this.pivot);
stroke(255); strokeWeight(2); line(this.pivot.x, this.pivot.y, this.bob.x, this.bob.y);
fill(254, 255, 16 ); noStroke(); circle(this.bob.x, this.bob.y, this.ballr * 2); fill(3, 23, 58 ); circle(this.bob.x + 5, this.bob.y, this.ballr * 2); // Parte oscura de la luna }
clicked(mx, my) { let d = dist(mx, my, this.bob.x, this.bob.y); if (d < this.ballr) { this.dragging = true; } }
stopDragging() { this.angleVelocity = 0; this.dragging = false; }
drag() { if (this.dragging) { let diff = p5.Vector.sub(this.pivot, createVector(mouseX, mouseY)); this.angle = atan2(-diff.y, diff.x) - PI / 2; } }
checkCollision(particles) { for (let p of particles) { let d = dist(this.bob.x, this.bob.y, p.position.x, p.position.y); if (d < this.ballr + p.size / 2) { p.transformed = true; if (p instanceof Confetti) { p.star = random() < 0.5; } } } }}
sketch.js
let emitter;let pendulum;
function setup() { createCanvas(500, 500); emitter = new Emitter(); pendulum = new Pendulum(width / 2, 100, 200);}
function draw() { background(3, 23, 58);
// Emitimos más partículas con posición X basada en Lévy flight for (let i = 0; i < 2; i++) { emitter.addParticle(); }
emitter.run();
pendulum.update(); pendulum.drag(); pendulum.show(); pendulum.checkCollision(emitter.getParticles());}
function mousePressed() { pendulum.clicked(mouseX, mouseY);}
function mouseReleased() { pendulum.stopDragging();}
// ========== FUNCIONES LÉVY FLIGHT ==========
function levyFlight(scale = 1) { let r = random(1); return scale / pow(r, 1 / 3); // Exponente ajustable para la distribución}
function randomLevyVector(scale = 1) { let angle = random(TWO_PI); let mag = levyFlight(scale); return p5.Vector.fromAngle(angle).mult(mag);}
function randomLevyOffset(scale = 100) { return (random() < 0.5 ? -1 : 1) * levyFlight(scale);}
Conceptos aplicados
-
Unidad 1:
- Distribución no uniforme (Vuelo de Lévy): Para que la trayectoria de las partículas no sea tan predecible, apliqué el concepto en la posición inicial de las partículas y en la magnitud del vector de velocidad inicial.
-
Unidad 2:
- Vectores: el péndulo y los cálculos de la colisión de partículas emplean vectores y todo el sistema de movimiento usa esta función para poder dirigir a las partículas.
-
Unidad 3:
- Fuerzas: Estoy aplicando la fuerza la gravedad y sumatoria de fuerzas en el funcionamiento de las partículas para que su caída tenga sentido y simule una lluvia normal.
-
Unidad 4:
- El péndulo y las funciones sinusoidales: El programa implementa un péndulo simple y calcula su aceleración angular, velocidad y posición usando las leyes del movimiento angular. Se usan funciones como sin() y cos() para la posición del péndulo (bob) y el giro de las partículas (confetti) con rotate.
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:
Síntesis 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?
- Bueno, las partículas se crean gracias a una clase emitter (emisor) qu es el encargado de generar las partículas y se van almacenando en un arreglo pero para evitar que este colapse u ocupe mucha memoria, se le asigna a cada partícula un tiempo de vida y cuando este se cumple, pum, se elimina del arreglo.
✅ 2. ¿Cómo se aplica el marco de movimiento motion 101 en los sistemas de partículas que analizaste en la actividad anterior?
- El marco 101 nos permite dotar a nuestros elementos de posición, velocidad y aceleración. Cuando lo aplicamos a las partículas ayuda a que su moviento sea más coherente con las simulaciones que hacemos porque permite que se comporten de manera natural.
✅ 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?
- Las fuerzas se modelan como vectores, así que se escriben como p5.vector, facilitando que se puedan aplicar operaciones sobre ellas y actúen de manera natural sobre un objeto. En las unidades pasadas pude explorar con la gravedad, el viento y la fuerza de atracción/repulsión. Mi favorita fue la de atracción porque me permitía generar interacciones interesantes entre una partícula y el atractor, sin embargo, la que más usé fue la gravitacional porque es la que más fácil de modelar en los ejemplos que exploramos.
✅ 4. ¿Cómo se aplicaste los conceptos de herencia y polimorfismo en los sistemas de partículas que trabajaste en la unidad?
- El concepto de herencia me ayudó a crear partículas de diferentes formas que compartieran un molde en común. En el caso de la entrega final de esta unidad, el molde original era la clase particle.js y la hija que heredaba estas características era confetti.js. Por su parte, el polimorfismo me ayudó en la implementación de comportamientos similares sobre diferentes clases porque en mi programa tenía varias clases de partículas en cuanto a forma y color pero que a su vez cumplían muchas veces con el mismo movimiento.
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:
✅ 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í, muchas veces empleaba estos objetos en proyectos relacionados con videojuegos y me costaba comprenderlos con códigos de Unity por la dificultad de realcionarlo a mis intereses o comprender los códigos largos y complejos, sin embargo, en esta unidad pude explorar de manera visual e interactiva integrando conceptos que ya había aprendido de la misma manera. Así que sí, ya comprendo la relevancia de crear clases que se puedan heredar y también la importancia de aplicar polimorfismo para que objetos con cualidades compartidad pero a su vez diferentes puedan convivir juntos reutilizando funciones.
✅ 2. ¿Qué partes de esta unidad te resultaron más fáciles? ¿Por qué?
- Hacer la actividad 3 me resultó fácil porque ya había explorado bastante con ejemplos anteriores, no todo fue fácil. Pensar en qué conceptos integrar o cómo aplicarlos también me tomó mucho tiempo pero pensar en el concepto lo hizo más interesante y llevadero el proceso. Pienso que otro factor por el cual me resultó más fácil esta actividad fue porque para iniciar el trabajo reutilicé el código en el que se exploraba el polimorfismo y la herencia para poder superar mi bloqueo con la manera en la que iba a aplicar otros conceptos.
✅ 3. ¿Qué parte te pareció más difícil o te tomó más tiempo? ¿Cómo la resolviste?
- Realizar el análisis y modificación de los códigos de ejemplo fue un trabajo laargo que me tomó mucho tiempo y me exigió demasiado a la hora de pensar cómo integrar conceptos de otras unidades, pero ya después del segundo ejemplo se me hizo más fácil continuar el ritmo porque a pesar de ser largo el proceso de desarrollo y cambios, ya me estaba divirtiendo ver los resultados. Además lo que tenía que responder era lo mismo y fui comprendiendo qué partes del código analizar directamente para responder cada pregunta y las respuestas ya sabía cómo estructurarlas con mayor rapidez y coherencia. Finalmente, como mi parte favorita del proceso es idear y crear conceptos, una vez con todo claro crear se hizo más fácil.
✅ 4. Si pudieras repetir esta unidad, ¿Qué harías diferente para mejorar tu comprensión de los conceptos?
- Yo me tomé bastante tiempo en la actividad 2, en la que se exploraban los ejemplos y en parte me sentía abrumada por ello pero pensándolo bien fue lo mejor porque me permitió comprender con calma cada concepto aplicado y cada nueva manera de abordarlo. Si pudiera hacer algo diferente tal vez pensaría que ver todos los ejemplos y asignarles a cada uno desde el principio el concepto con el que quería explorar para ahorrarme un poco de tiempo y frustración. Pero con una mirada general sobre mi desempeño en la unidad considero que aprendí a mi ritmo y a lo que se acomodaba a mi comprensión así que si tuviera que volver a hacerla la haría de la misma manera.
✅ 5. ¿Crees que lo que aprendiste en esta unidad te servirá en futuros proyectos? ¿Por qué si o por qué no?
- Sí, me va a servir para futuros proyectos porque aunque mi enfoque realmente está más orientado hacia el diseño de experiencias, es importante hablar con propiedad sobre lo que aprendo para poder comunicarlo a las personas que están orientadas a la parte técnica y de desarrollo. Comprender cómo funcionan los conceptos que exploramos también me da más libertad de creación en cuanto a simulaciones que a futuro le puedo mostrar a un cliente o a mi equipo de trabajo para visualizar con facilidad los conceptos que proponga para eventos, experiencias y productos. Lo que para mí es parte esencial como diseñadora, transmitir ideas que tengo en mi cabeza de manera efectiva, clara y coherente.
✅ 6. ¿Qué parte de esta unidad te gustaría profundizar más? ¿Por qué?
- Me gustaría poder explorar más con el polimorfismo y la herencia en diferentes proyectos, ver cómo los puedo implementar en otras aplicaciones, con más sensores e interacciones. Son conceptos que me han quedado claros pero aprender haciendo es la mejor manera en la que puedo interiorizarlos y aumentar mi portafolio de ideas para distintos proyectos. Además que también son conceptos claves en POO porque facilitan la integración y reutilización de código que aunque no suene para mí como lo más llamativo sí facilita mucho la vida de los programamdores y quién quita que en futuro mis intereses cambien y quiera ser una programadora pro 500.
✅ 7. ¿Qué concepto de esta unidad se podría aplicar a tu área de interés profesional? ¿Por qué?
- El sistema de partículas con fuerzas y creo que en general cualquier simulación que modele las fuerzas porque es muy divertido otorgarles a objetos digitales características del mundo real. Se me hace muy interesante pensar en todas las posibilidades de simulación y experiencias que se pueden lograr jugando con las leyes naturales del mundo y aplicándolas a conceptos propios. También me parece super importante el énfasis de esta unidad en cuanto a la generación, eliminación y gestión de las partículas en la memoria porque me hizo muy consciente de la importancia de tener esto en cuenta para que mis proyectos, además de bonitos, interesantes y visuales; sean a su vez óptimos y funcionales.
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
✅ 1. Sobre la dificultad: ¿La unidad fue demasiado fácil, equilibrada o demasiado difícil? ¿Por qué?
- Creo que la unidad fue muy pesada porque en la parte de investigación porque habían muchos ejemeplos que si se separarán en diferentes actividades dentro de la misma sesión podría ser más llevadero para que el cerebro sienta el cambio.
✅ 2. Sobre el ritmo: ¿El tiempo asignado fue adecuado?
- Sí, dos semanas son fuficientes.
✅ 3. Sobre los materiales: ¿Qué tan útil fue la estructura de la unidad? ¿Cómo se podrían mejorar?
- Creo que la parte de “¿qué aprenderás en esta unidad?” podría tener una actividad adicional para ampliar la cantidad de referentes y ejemplos de cómo abordar los conceptos de manera creativa.
✅ 4. Sobre la experiencia de aprendizaje: ¿Qué fue lo mejor de esta unidad? ¿Qué te gustaría que se hiciera diferente?
- Me gustó mucho la parte más larga porque pude experimentar como quise con los ejemplos y fue bastante divertida (aunque densa porque todas los ejemplos hacían parte de una misma actividad). Yo seguiría segmentando las sesiones por mini actividades para que se sientan más ligeras.
✅ 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é?
- Yo pondría un ejemplo de actividad hecha por mí con los conceptos y las herramientas digitales (p5.js) de la unidad para que ellos relacionen los alcances de la experimentación pero con lo que tenemos a nuestra disposición.