Assignment 9: Immune cells vs. Disease cells

Inspiration:

The inspiration for this project stems from the incredible complexity and beauty of the human immune system. Observing the intricate dance of immune cells as they work together to defend the body against invading pathogens is a mesmerizing spectacle. Additionally, the field of artificial life and emergent behavior in simulations served as a key inspiration. The idea of applying the principles of flocking behavior to simulate the coordinated movement of immune cells creates a visually compelling representation of their protective role in the body.

Concept:

The main concept behind this project is to use the principles of flocking behavior to simulate the movement and interactions of immune cells in response to the presence of disease cells. The flocking algorithm is based on three key principles:

  1. Separation: Each cell maintains a certain distance from its neighbors, representing the need for immune cells to avoid crowding, ensuring efficient patrolling of the body.
  2. Cohesion: Cells are drawn towards the average position of their neighbors, promoting a sense of unity and collaboration in the immune response.
  3. Alignment: Cells align their direction with that of their neighbors, mimicking the cooperative movement of immune cells as they collectively respond to threats.

The disease cells, represented as potential pathogens, introduce a dynamic element to the simulation. They act as attractors, causing nearby immune cells to adjust their movement to intercept and neutralize the threat.

Demo:

Reflection:

This project serves as a visual exploration of the principles of flocking behavior applied to the context of the immune system. Through this simulation, the intricate choreography of immune cells is brought to life, providing a dynamic and engaging representation of their vital role in protecting the body.

The use of P5.js as the framework for this project allowed for a seamless integration of visual elements and behavioral logic. Experimentation with parameters such as separation distance, cohesion strength, and alignment influence provides an opportunity to fine-tune the simulation and observe the emergent patterns that arise.

Additionally, the project opens up possibilities for educational purposes, as it provides a tangible and interactive way for individuals to grasp the collective behavior of immune cells. By observing the simulation, users can gain a deeper understanding of the coordinated efforts employed by the immune system to maintain health and combat potential threats.

In conclusion, this project not only explores the artistic potential of simulating immune cell behavior but also serves as a tool for educational outreach, bridging the gap between art and science to enhance our appreciation for the complexity of the human body’s defense mechanisms.

Coding Assignment Week #9 – Confetti System

Inspiration:

When I think of confetti I think of celebrations, and birthdays and the joy and laughter that comes with it! Interestingly, the way confetti moves in air when it is first released from its container is a very sudden and quick movement, which if you arent paying close attention to, you could easily miss. Which is why I began to think of how I can better visualize such confetti, and what would make this movement slow down, so we can visualize this motion and its changes more clearly.

Bright colourful party sparkling party confetti background canvas prints for the wall • canvas prints explode, entertainment, luxury | myloview.com

Concept:

The concept of this program mainly revolves around a simulation of a flock of confetti, which are simple agents that move similarly to confetti with a more limited speed. The main classes are Flock and Boid(confetti). The Flock class manages a list of confetti instances and has methods to simulate the collective behavior of the collection and add more confetti. 

The behavior of the flocking  revolves arounf three main principles/rules: separation, alignment, and cohesion. The flock method in the Boid class calculates forces for each of these principles based on the positions and velocities of neighboring boids/confetti particles. These forces are then applied to the boid’s acceleration, influencing its movement. The update method handles the adding of acceleration to update the boid’s position and velocity. The display method visually represents each boid as a neon-colored dot with a line trace, creating a dynamic simulation.

Bird Brain Maps: Study Explores the Neuroecology of Flocking in Birds | College of Biological Sciences

How to create a boids system (flocking algorithm) - Scripting Support - Developer Forum | Roblox

Program With Comments:
Reflection:

As I concluded this program I began to wonder how I could further advance this program visually, which is when I thought of the methods we learnt about last week and how they can really push this program. For instance, a more dramatic separation steering behavior is particularly suitable for this program, because it serves to keep the confetti from clumping together.

Local separation, alignment and cohesion on the motion of flocking... |  Download Scientific Diagram

 

Week #8 Assignment: Flower Heliotropism by Abdelrahman Mallasi

Concept

The concept of this project revolves around simulating heliotropism, which is the ability of certain plants to grow and orient themselves in response to the direction of sunlight. , which regulates cell elongation and growth.
This phenomenon is primarily controlled by the plant hormone auxin, which stimulates growth. When light shines on one side of a plant, it triggers the redistribution of auxin, causing the plant to grow more on the shaded side. This growth pattern leads to the plant bending or turning towards the light source. Sunflowers are an example of plants that exhibit heliotropism, as they follow the sun’s path across the sky during the day.

In this project, I aim to represent heliotropism through an interactive simulation. I created a visual display where a flowers grow towards the sun, which is controlled by the mouse cursor. As the flowers reach a specific height, it blooms, showcasing the transition from growth to flowering. Each flower has its own maximum height and growth rate that are randomly generated each time the sketch. The project exhibits properties of autonomous objects by illustrating seeking behavior, with the sun acting as the target and the plants as the vehicle.

Highlight of Code

grow() {
   if (this.height < this.maxHeightForBlossom) {
     this.height += this.growthRate;
   }
 }

 blossom() {
   if (this.height >= this.maxHeightForBlossom) {
     fill(255, 0, 255);
     stroke(255, 0, 255);
     ellipse(this.root.x, this.root.y - this.height - 20, 20, 20);
   }
 }

These two methods are under the Plant class

grow() represents the process of the plant growing over time. The if statement checks whether the current height of the plant (this.height) is less than the maximum height for blossoming (this.maxHeightForBlossom). If so, the plant’s height is increased by the growth rate (this.height += this.growthRate). This means that the plant grows a certain amount with each frame of the animation until it reaches the maximum height.

blossom() is responsible for checking whether the plant has reached the height for blossoming and displaying a flower if it has. Similar to before, it checks whether this.height is greater than or equal to this.maxHeightForBlossom. If so, it draws a flower at the root adjusted for its height (this.root.y – this.height – 20). The 20 is used to position the flower slightly above the top of the plant stem.

Embedded sketch

Link to Sketch

Future Ideas

  • The initial idea for this project was to depict realistic plant growth with the root firmly anchored at the bottom of the canvas, creating a curving stem as the plant grows towards the sun. However, this proved to be a challenge to implement

Coding Assignment – Week #8

Concept:

For this week’s assignment, I wanted to focus on developing a concept and creating a fun adaptation for the new simulations of movements that we learned in class. As I was revising the different behaviors of agents that we simulated in code, the pursue and evade example caught my eye the most, mostly because of the endless opportunities it opens to tell simple stories. The three agents are like characters in a tale: the main character pursues something while trying to evade the bad guy. Many many possibilities to give this plot a more detailed and interesting scenario.

The scenario that I decided to with is the one of a Fisherman. The movement of the initial agent reminded me of that of a canoe in the sea. Here was my first experiment (I see a boat lost in the sea at night, but that might as well just be me haha!):

Nevertheless, I wanted to come back to the pursue and evade story plot. I created three characters: a fisherman in a canoe, a fish, and a shark. The story: the fisherman pursues the fish while avoiding the shark. Here is my final sketch:

 Implementation:

For the sketch to come together, I decided to roughly sketch my own PNGs. Here they are:

Regarding the code, the difficult part was to correctly display the images, mostly the rotation so that the canoe moves with its tip facing the fish, and so does the fish and the shark. Here is how I modified the show() function for the Vehicle class:

show() {
  let angle = this.velocity.heading();
  fill(127);
  stroke(0);
  push();
  translate(this.position.x, this.position.y);
  rotate(angle + HALF_PI); 
  image(boat, -50, -50, 100, 100); 
  pop();
}

For further improvements, it would be interesting to make the shark to also pursue the fish. Additionally, for more details, I would add an event that occurs when either the fisherman or the shark gets to the fish first and a collision occurs. Now, when the images intersect, one just flows on top of the other, which is not the most smooth visual result.

Xiaozao Assignment #8 – Ant’s Death Spiral

Ant’s Death Spiral

Code: https://editor.p5js.org/Xiaozao/sketches/e8ilAu4Ew

This week’s assignment is inspired by a well-known phenomenon in animals’ behavior called “the ant’s death spiral”. When ants are navigating in a dense forest, each ant always maintains a close distance from the ant ahead of them by following the pheromone trail it leaves. However, when the leading ant loses its track and accidentally runs into one of the other ants, it will form a closed circle among the ants, and make them fall into the endless loop of circular motion that leads to their death.

Therefore, I wanted to create this autonomous agent system where at first, the leading ant is wandering to find food, and every ant in the line follows the ant in front of it. But when the leading ant runs into another ant, it will stop wandering and instead decide to follow that ant’s track. Therefore, all the ants are following the ant ahead of them, meaning that no one is leading, or you can say everyone is leading. They will continue this pattern forever.

Code-wise, I mainly used two classes: the normal ant (vehicle) and the leading ant (target). All the ants can seek but the leading ant has the extra ability to wander.

I used this loop to make any ant follow the ant ahead of it:

let second_ant = ants[num-1];
  let second_seek = second_ant.seek(leading_ant);
  second_ant.applyForce(second_seek);
  second_ant.update();
  second_ant.show();
  
  for (let i = 0; i < num-1; i++) {
    let front_ant = ants[i+1];
    let back_ant = ants[i];
    let steering = back_ant.seek(front_ant);
    back_ant.applyForce(steering);
    back_ant.update();
    back_ant.show();
  }
  
  leading_ant.update();
  leading_ant.show();

And I check if the leading ant is running into any of the ants, and change its behavior if so:

if (trapped == false) {
    let steering_wander = leading_ant.wander();
    leading_ant.applyForce(steering_wander);
      
    // checking leading ant collision
    for (let i = 0; i < num; i ++) {
      let ant = ants[i];
      if (leading_ant.position.dist(ant.position) < 1) {
        let new_steering = leading_ant.seek(ant);
        leading_ant.applyForce(new_steering);
        followed_ant = ant;
        trapped = true;
        break;
      }
    }  
  } else {
    let steering = leading_ant.seek(followed_ant);
    leading_ant.applyForce(steering);
  }

What to improve:

In this sketch, I think that the ants are over-ordered. In reality, the ants are not in a perfect line and they are slightly affected by other ants and their surroundings. Maybe I can add other factors that can affect the ants’ movement in the future.

 

Coding Assignment #7 – Week 9

Concepts:

For this week’s assignment, I tried to implement a cloud of particles, each inspired by Craig Reynolds’s autonomous agents, that seek invisible and randomly generated vertices. I wanted to see how these agents work together, figure out the best path, and adapt to the changing environment. In terms of technicalities, I’m using a seek function and acceleration to drift toward the vertices one by one, and the HSB color mode for aesthetics.

Sketch:

Process:

View post on imgur.com

View post on imgur.com

View post on imgur.com

Code Walkthrough:

Vehicle Class:

The vehicle class represents the autonomous agents (cloud of particles), and has one movement function alongside the constructor. It uses position, velocity, acceleration, direction, and color properties.

Move():

The move() function combines the seeking force and other helper functions (finding the next vertex index, checking if the particle reaches the vertex, changing direction)

move() {
  // Go to the next vertex
  let target = this.vertices[this.idx];
  let distance = dist(this.position.x, this.position.y, target.x, target.y);
        
  if (distance < 45) {
    if ((this.direction==1 && this.idx==this.vertices.length-1) || (this.direction==-1 && this.idx==0)) {
    this.direction*= -1;
    }
    this.idx+=this.direction;
  }

  // Seek the next vertex
  if (distance >1) {
    let steer = new p5.Vector(target.x, target.y);
    steer.sub(this.position);
    steer.normalize();
    steer.mult(0.045);
    this.acceleration.add(steer);
  }
        
  // Add movement
  this.velocity.mult(0.99);
  this.velocity.add(this.acceleration);
  this.velocity.limit(6);
  this.position.add(this.velocity);
  this.acceleration.mult(0);
}

Upon every mouseclick, 1000 new particles are generated and the vertices change as well.

Vertices:

To generate the vertices, I’m using a random function:

vertices=[];
for (let i = 0; i < 6; i++) {
      let x = map(i, 0, 6, width/4, width - width/4);
      let y = random(120, height - 120);
      vertices.push(new p5.Vector(x, y))
}

HSB Color Mode:

I’m using the Hue specifically and brightness to add an aesthetic look to the particles.

Next Steps:

Future steps would be to add other forces i.e. avoiding obstacles.

Week 8 – Buzzing

For my assignment this week, I wanted to recreate something that follows an attractor with high speeds and natural orbiting movement. I wanted this attractor to buzz around more than flow.  I thought of bees around honey or something similar.

class Attractor {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.mass = 50;
  }

  attract(star) {
    let force = p5.Vector.sub(this.pos, star.pos);
    let distance = force.mag();
    distance = constrain(distance, 100, 500);
    force.normalize();

    let strength = (1 * this.mass * star.mass) / (distance * distance);
    force.mult(strength);

    return force;
  }

  update() {
    this.pos.add(p5.Vector.random2D().mult(5));
  }

  display() {
    // noFill();
    noStroke();
    fill(237, 208, 92);
    ellipse(this.pos.x, this.pos.y, 20, 20);
  }
}

I want the attractor to move at certain distances and have a certain strength, so the update function is what controls the movement of the attractor so that it buzzes around. I set the multiplying as a number of 5 and it was the perfect value for the attractor to buzz around.

class Bee {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = p5.Vector.random2D();
    this.acc = createVector();
    this.maxSpeed = 100;          //speed of the particles 
  }

For my bee class, the most important attribute in this class would be speed as it gives that high speed buzzing effect of the bees and makes the final code look much more realistic.

let choice = random();
    if (choice > 0 && choice < 1/3) {
      fill(255, 215, 0, alphaValue);
    } else if(choice > 1/3 && choice < 2/3){
      fill(255, alphaValue);
    }
    else{
    fill(0,alphaValue)}
    noStroke();
    ellipse(this.pos.x, this.pos.y, 5, 5);

This code gives an even chance of the colours I wanted to present on the canvas and the opacity is dependent on how far away the bees are from the attractor. The further away, the less opaque.

Next time

I think next time, I want to try an idea of the attractor moving in a natural curve like a shooting star collecting more stars on the way.

Coding Assignment – Week 8

Concept and Approach:

My approach for this assignment was quite simple, I thought of things I could create with the seek and flee dynamic involved between them. The first thing that came to mind was mice and cheese, which was completely inspired by the cartoon Tom and Jerry, and Jerry’s love for cheese. I read a bit around the topic and found that in fact mice’s love for food, and cheese in specific, is over exaggerated, they just tend to be attracted to foods that are high in carbohydrates in general. Hence, I decided to create a sketch that shows their attraction to cheese in a way that also demonstrates the idea that they are not extremely fond of it.

The method I followed was very similar to what we had done in class. I created a class of mice that have different functions including seeking and fleeing and I had an image of cheese be their target. In my Draw function I called a number of mice, all seeking the cheese. Once one of them had arrived to the cheese, it ‘eats’ it and all the other mice flee away rather than gathering around it and ‘eating’ it all together.

The way I separated their actions was through incorporating boolean values that are set as false in the beginning of the code. Once the distance between the position of the closest mouse and the cheese is less than 10, the boolean value changes to true, leading that specific mouse and the cheese to disappear. The other if function checks that this happened (one mouse arrived at the cheese and basically left the array of mice), and accordingly calls the flee function on all the other mice.

if (!targetReached) 
  {
    // First loop through all the mice array and call the Mouse class functions
    for (let i = 0; i < mice.length; i++) 
    {
      mice[i].seek(cheese);
      mice[i].update();
      mice[i].display();
      image(cheesePic, cheese.x, cheese.y, 20, 20);

      // Check if the mouse has reached the cheese by measuring distance between mouse and cheese
      if (mice[i].position.dist(cheese) < 10) 
      {
        // set the boolean to true
        targetReached = true;
        mice[i].arrived = true;
      }
    }
  } 
  //now for the other mice
  else 
  {
    // Loop through all the array. The mouse that reached the cheese would have disappeared by now
    for (let i = 0; i < mice.length; i++) 
    {
      // If there was a mouse that arrived
      if (!mice[i].arrived) 
      {
        // Then have all the other mice flee and call the other functions of the class
        mice[i].flee(cheese);
        mice[i].update();
        mice[i].display();
      }
    }
  }
}

Reflection and Ideas:

I think the only challenging part was coordinating the boolean values and knowing when to set them to true/ false and how to have everything follow based on them. But overall, this wasn’t that difficult, with a few trials and errors I was able to get the code to work in the way I needed.

An improvement that I tried to actually apply but was not successful in doing so, was having the mice be images rather than just triangles. My issue with that was being unable to rotate the images based on the velocity’s angle. In my attempt, they did rotate, however, they weren’t all pointed towards the cheese which made the sketch look unrealistic. Moving forward I’d like to learn if it possible to implement that, because I think images would definitely make the sketch more interesting.

Coding Assignment Week #8

CONCEPT

For this week’s sketch, I wanted to explore the different autonomous behaviours we have covered in class and how they interact and respond to each other. In other words, what if instead of studying each steering method separately, we create a system where every object has its own steering behaviour and we how it affects and influences other vehicles having a different behaviour. With this idea, I started to experiment!

PROCESS

    1. Multiple wandering objects:
    2. Then I decided to have smaller objects to either pursue, evade, or arrive at one of these big wandering (blue) objects.
    3. Currently, in the above sketch, each smaller target is currently pursuing or evading a fixed predefined wanderer. I wanted to try to randomize that based on whichever wanderer is closest. I modified the code to calculate the minimum distance and store it and use that to assign the target. I made a line between the wanderer and pursuer / evader for increased visibility.
      Here is the code for it:

      let steering = [];
      
      // to calculate and find min distance between current seeker 0 and all wanders
      let d = p5.Vector.dist(vehicle_seekers[0].position, vehicle_wanderers[0].position); // to store the min distance - initially start with first available dist
      let index = 0; // to store which wanderer is closest
      for (j = 1; j < N1; j++) {
        let d2 = p5.Vector.dist(vehicle_seekers[0].position, vehicle_wanderers[j].position);
        if (d2 < d) {
          d = d2;
        }
      }
      
      steering[0] = vehicle_seekers[0].pursue(vehicle_wanderers[index]);
      
      // making a line between them for more visibility
      push();
      stroke(2,255,2);
      line(vehicle_seekers[0].position.x, vehicle_seekers[0].position.y, vehicle_wanderers[index].position.x, vehicle_wanderers[index].position.y);
      pop();
    4. Some improvisation. Firstly, I added more wanderers for the system to be more dynamic. Secondly, the pursuer gets suck to the target once it seeks it (i.e. reaches it). So, I tried the opposite. Instead of pursuing the closest target, pursue the farthest. So, it keeps changing its direction and does not get stuck.

      The code for it changed as described below:

      let steering = [];
      
      // to calculate and find max distance between current seeker 0 and all wanders
      let d = p5.Vector.dist(vehicle_seekers[0].position, vehicle_wanderers[0].position); // to store the max distance - initially start with first available dist
      let index = 0; // to store which wanderer is closest
      for (j = 1; j < N1; j++) {
        let d2 = p5.Vector.dist(vehicle_seekers[0].position, vehicle_wanderers[j].position);
        if (d2 > d) {
          d = d2;
        }
      }
      
      steering[0] = vehicle_seekers[0].pursue(vehicle_wanderers[index]);
      
      // making a line between them for more visibility
      push();
      stroke(2,255,2);
      line(vehicle_seekers[0].position.x, vehicle_seekers[0].position.y, vehicle_wanderers[index].position.x, vehicle_wanderers[index].position.y);
      pop();
    5. Lastly, I created my own trailing path with these new set of rules for steering behaviour to create the below output!

Pretty Mishap?

So, while on my way to figuring out the code for trailing paths, I kind of ran into this happy accident. The trails clearly do not appear as they should but it was interesting enough to document. I believe this is because I am not correctly popping from the list of paths and rotating indefinitely.

I then fixed the rotating problem but ran into something the professor warned us about – edge to edge lines!! (when the object wraps around, it draws a line across the page). I do like this effect too – seems like a women quilt / blanket.

It was easy to fix this as I did this modification for the pen plotter too in my midterm. Plotting dots was easy, but for plotting lines, I had to reset the line every time it made a huge jump so as to not have lines all across the page. This one was not exactly the same, but similar in terms of the concept.

FURTHER DEVELOPMENT

Currently my design is based on wanderers being the main targets. One way to improve this is by having different agents (objects) each having their own property of wandering, pursuing, evading etc., and calculating the minimum distance from each of those, not just the wanderers. This way, an evader could flee a pursuer closest to them, or a pursuer could seek a target farthest to them (not closest). That would be interesting to see.

Week 7 Assignment

Concept: 

I came across “The Snow Queen” fairy tale a few days ago when I was browsing through the books in my Kindle, and this randomly crossed my mind when I was brainstorming for this assignment. Using the arrival, wander, etc. codes that we learned in class, I thought it’d be fun to show the scene of Kay’s heart being pierced and frozen from the Snow Queen’s snowflake pieces.

Process/Highlight:

I used this image for the heart, and I basically used similar structure of wander and arrival from class except I had the diamonds (“vehicles”) continuously moving even after arriving at the heart (“target’). A particular highlight would be the “separation” function I used so that the diamonds won’t be colliding into each other, which took some time for me to figure out how to use.

Here’s the code snippet:

// separation
separate(vehicles) {
  let desiredSeparation = 25; // Adjust as needed
  let steer = createVector(0, 0);
  let count = 0;

  for (let other of vehicles) {
    let d = p5.Vector.dist(this.position, other.position);
    if (other !== this && d < desiredSeparation) {
      let diff = p5.Vector.sub(this.position, other.position);
      diff.normalize();
      diff.div(d); // Weight by distance
      steer.add(diff);
      count++;
    }
  }

  if (count > 0) {
    steer.div(count);
  }

  if (steer.mag() > 0) {
    steer.setMag(this.maxSpeed);
    steer.sub(this.velocity);
    steer.limit(this.maxForce);
  }
  return steer;
}

And here’s the final sketch:

Reflection:

For some reason I couldn’t move the diamonds to be drawn at the front of the heart image for this sketch despite trying to rearrange the order of them, so that’s something I’d like to figure out and improve on next time!