Mini Project 4. Purple Haze

Project Title: Purple Haze

Link:https://editor.p5js.org/N-A-E-S/sketches/9AoAeKusd

Brief Description: This project aims to create a self-generative smoke-like atmosphere for project A. The project used Perlin Noise to generate continuous random values to denote the different parts of the smoke area.

Visual Documentation: Purple Haze under different frames

Coding:

function setup() {
createCanvas(600, 600)
noStroke()
}

function draw() {
const noiseScale = 0.01
bscale=map(sin(frameCount*0.05),-1,1,5,10)
for (let i = 0; i < width; i += bscale) {
for (let j = 0; j < height; j += bscale) {
const noiseVal = noise(i * noiseScale, j * noiseScale,frameCount*0.05)
const currentColor = map(noiseVal, 0, 1, 0, 255)
fill(currentColor*0.75+map(sin(frameCount*0.05),-1,1,20,50),50,map(sin(frameCount*0.05),-1,1,120,170))
rect(i,j,bscale,bscale)
}
}
}

 

Mini Project3-Project A Proposal

Sketch1: Models of sexual reproduction of organisms

Link:https://editor.p5js.org/N-A-E-S/sketches/nweZqmRem

In Sketch 1 I explored a very basic part of living creatures: reproduction. In the simulation presentation, male creatures are marked as green circles with a name randomly picked, with the existing lifetime of individual creatures increasing, the color would go blue. A single male creature could live for 600 frames. When the male organism grows mature enough (more than 200 frames), it will search for unpregnant female organisms within 200 distance. If there is no qualified object in the corresponding range, it will swim randomly.

When a pair of creatures mate, the male swims towards his mate and mates. After a while the male leaves. The female then carries offspring after a short period of gestation. There is an 80% chance that breeding will produce male offspring and a 20% chance that it will produce female offspring. To mark the parent, male offspring inherits the first two characters of his name from his mother and female offspring inherits the first character of her name from her father.

I decided to develop this sketch into my project A because the sketch studied multiple creatures that interacted with each other. Also, this sketch could be self-developed into a self-sustained system.

Coding:

function setup() {
  createCanvas(600, 600);
  background(225)
}
class male_c{  //male creature
  constructor(name,x,y){
    this.name=name
    this.x=x
    this.y=y
    this.lifetime=0
    this.size=50
    this.r=0
    this.g=220
    this.b=0
    this.mate=null
    this.xspeed=random(-2,2)
    this.yspeed=random(-2,2)
    this.moveTimeCount=0
    this.mateTime=0
  }
  show(){
    noStroke()
    fill(this.r,this.g,this.b)
    ellipse(this.x,this.y,this.size,this.size)
    fill(0)
    text(this.name,this.x-15,this.y)
    
  }
  move(){
    if(this.mateTime>30){
      this.mate=null
      this.mateTime=0
        this.xspeed=random(-2,2)
      this.yspeed=random(-2,2)}
    if(this.mate!=null)
      this.mateTime+=1
    if(this.mate==null){
      this.moveTimeCount+=1
      if(this.moveTimeCount>=50)
        {
          this.xspeed=random(-2,2)
          this.yspeed=random(-2,2)
          this.moveTimeCount=0
        }
    }
    else{
      if(dist(this.x,this.y,this.mate.x,this.mate.y)>=50){
      this.xspeed=map(this.mate.x-this.x,300,-300,20,-20)
      this.yspeed=map(this.mate.y-this.y,300,-300,20,-20)
      }
      else{
        this.xspeed=0
        this.yspeed=0
      }
    }
    if(this.x>0 && this.y>0 && this.x<600 && this.y<600){ this.x+=this.xspeed this.y+=this.yspeed } } propose(fl){ this.mate=fl fl.pergnant=true } } class female_c{ //female creature constructor(name,x,y){ this.name=name this.x=x this.y=y this.lifetime=0 this.size=50 this.r=220 this.g=0 this.b=0 this.pergnant=false this.pergnant_break=0 } show(){ noStroke() fill(this.r,this.g,this.b) rect(this.x,this.y,this.size,this.size) fill(0) text(this.name,this.x+5,this.y+25) } birth(){ var gender=random(-1,1) if(gender>-0.5){
  this.new_name=this.name[0]+this.name[1]
  this.new_name+=alphabet[int(random(0,52))]
    mc.push(new male_c(this.new_name,this.x+random(10,30),this.y+random(10,30)))
  }
  else{
    this.new_name=this.name[0]
  this.new_name+=alphabet[int(random(0,52))]
  this.new_name+=alphabet[int(random(0,52))]
    fc.push(new female_c(this.new_name,this.x+(0.5+random(-1,1))*50*random(1,1.5),this.y+(0.5+random(-1,1))*50*random(1,1.5)))
  }
  this.pergnant=false
  }
}
var alphabet=new Array('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')//alphabet for name generate
var mc=new Array()
var fc=new Array()
function keyPressed(){
    if(key=='m')//male product
      {
        name=''
        wc=int(random(2,5))
        for(i=0;i<wc;i++)
          {
            w=int(random(1,52))
            name+=alphabet[w]
          }
        new_male=new male_c(name,mouseX,mouseY)
        mc.push(new_male)
        console.log(new_male.name)
      }
      if(key=='f')
      {
        name=''
        wc=int(random(2,5))
        for(i=0;i<wc;i++)
          {
            w=int(random(1,52))
            name+=alphabet[w]
          }
        new_female=new female_c(name,mouseX,mouseY)
        fc.push(new_female)
        console.log(new_female.name)
      }
  if(key=='c'){
    mc=new Array()
    fc=new Array()
  }
}
function draw() {
  background(255)
  for(i=0;i<mc.length;i++){ mc[i].b+=0.5 mc[i].show() mc[i].move() if(mc[i].mate==null && mc[i].lifetime>200){
      for(j=0;j<fc.length;j++){
        if(dist(mc[i].x,mc[i].y,fc[j].x,fc[j].y)<=200 && fc[j].pergnant==false) mc[i].propose(fc[j]) } } if(mc[i].mate!=null){ line(mc[i].x,mc[i].y,mc[i].mate.x,mc[i].mate.y) } mc[i].lifetime+=1 mc[i].size50=map(mc[i].lifetime,0,500,50,100) if(mc[i].lifetime>=600)
      mc.splice(i,1)
  }
  for(i=0;i<fc.length;i++){ fc[i].b+=0.5 fc[i].show() fc[i].lifetime+=1 if(fc[i].pergnant==true) fc[i].pergnant_break+=1 if(fc[i].pergnant_break>200 && fc[i].pergnant==true)
      {
        fc[i].pergnant_break=0        
        fc[i].pergnant=false
        fc[i].birth()
      }
        console.log(fc[i].pergnant_break,fc[i].pergnant)
    fc[i].size50=map(fc[i].lifetime,0,500,50,100)
    if(fc[i].lifetime>=2000)
      fc.splice(i,1)
  }
    
} 

Sketch2: Feed the loading ring

Link:https://editor.p5js.org/N-A-E-S/sketches/0Iwsggodt

This sketch focuses on exploring the feeding and hunting of food. The loading ring simulated a snake-shaped creature. The HP stands for the health standard of the creature, which will decrease over time.  A higher HP point means a larger size of the creature and a faster spinning speed. Pressing the mouse will deploy food in the mouse position. The creature will adjust its radius to eat the food. 

coding:function setup() {
createCanvas(400, 400);
}
var t=0
var hp=100
var r=50
var rp=50
class food{
constructor(hp,x,y){
this.x=x
this.y=y}
}
f=new food(0,200,200)
function draw() {
if(mouseIsPressed){
f.x=mouseX
f.y=mouseY
f.hp=random(10,15)
rp=dist(f.x,f.y,200,200)
}
t+=0.05*hp*0.01
if(hp>0)
hp-=0.05
background(0,20);
if(r<rp)
r+=1
if(r>rp)
r-=1
console.log(r,rp)
noStroke()
sv=r*sin(t)
cv=r*cos(t)
x=200+sv
y=200+cv
fill(255)
text('hp:'+hp,10,10,200,200)
circle(x,y,hp*0.25)
if(abs(f.x-x)<5 && abs(f.y-y)<5)
{
hp+=f.hp
f.hp=0
}
if(f.hp>1)
fill(255)
else
fill(0)
circle(f.x,f.y,10)
}

Sketch3: mountain drawing with Perlin Noise

 

Link:https://editor.p5js.org/N-A-E-S/sketches/MYnB4NKQM

In this sketch, I use two Perlin Noise functions to draw a multi-dimensional mountain. The color and altitude both decrease. With the Perlin Noise function, we could get the different mountain shapes.

Coding:

function setup() {
createCanvas(400, 400);
background(0);
stroke(100)
}
var x=1
var xspeed=2
var c1=100
var c2=50
var layers=0
function draw() {
let freq = frameCount * 0.02;
let amp = 250-0.05*layers;
let amp2=250-0.05*layers
x+=xspeed
if(x>400 || x<=0){
xspeed=-xspeed
layers+=50
c2=c1
c1+=50
}
let noiseValue = noise(freq) * amp; // noise
let noiseValue2= noise(freq)*amp2
let yNoise=50+noiseValue+layers
let yNoise2=100+noiseValue2+layers
noStroke()
ellipse(x, yNoise, 5, 5);
ellipse(x, yNoise2, 5, 5);
fill(c2)
rect(x,yNoise2,2,400-yNoise2)
fill(c1)
rect(x,yNoise,2,yNoise2-yNoise)
}

Evolving Virtual Creatures:Karl Sim’s Virtual Creatures

Evolving Virtual Creatures

Link to slides:https://docs.google.com/presentation/d/1u3ku1ZeubXsbXU8jDdwYmSOl5FgtYG1HD41C4jKLy_0/edit?usp=sharing

Creating process:

The project involves simulated Darwinian evolutions of some virtual block creatures generated by computers, which consist of digital brains and physical bodies. Digital genes are stored to describe their physical features. Creatures will be sorted by the computer, and the survivors will combine with each other to make offspring.

 

Features:

  1. Visual: The creatures are made up of blocks linked together. They follow the laws of physics to move.
  2. Technical: The creatures combine their genes to generate more adequate physical features to survive in this digital space. The user can set the condition of the environment and wait for the creatures to evolve by themselves.
  3. Material: These creatures “live” in a virtual computer world that mimics the real physical world.

 

Forms of interaction

These creatures don’t actually interact with observers. They have an inner interactive chain, and when they perform an ideal move, the feature that enables them to do this move will be kept and developed.

Intentions

The research intends to do research on the virtual ecosystem and how computers can realize the Darwinian evolving process. He successfully created this virtual environment and made some virtual creatures that can imitate real creatures well. It has verified the possibility for humans to create a “real” virtual world in the future with more advanced technology.

Views

The researcher thinks that this process enables people to generate complicated creatures with simple prompts. It’s a new discovery in artificial generative arts.

Background

Karl Sims is a computer graphics artist and researcher who excels at using particle systems and artificial life generation in computer animation. After graduating from MIT, he worked at Thinking Machines, which used to be an AI company that released several powerful supercomputers. He was awarded many times for his groundbreaking research in digital arts.

Methods

Optimization techniques help automatically generate complex creatures. The researcher uses the Darwinian “survival of the fittest” approach to search for optima. They then use interactive evolution to procedurally generate results that can be explored by simply choosing the most desirable individuals, mixing their genes, and repeating this process.

Inspirations

This project might be the beginning of creating digital ecosystems and making self-evolving digital creatures. The researcher might have been inspired by the status quo at that time when people were able to develop methods to make digital objects to do movement but only with complicated algorithms, so this research aimed to explore the possibilities of generating moving methods by automatically evolving.

Historical Context

This research was conducted over 20 years ago when there was no advanced generative AI technology like ChatGPT or Stable Diffusion. Though the interface is very simple, it is still an advanced exploration of generative arts.

 

Discussion

Significance:  This research aims to achieve the reappearance of Darwin’s evolving theory using virtual creatures that could algorithmically self-evolving, which opened up a whole new area of artificial life that goes across biology, computer science, and visual art. Moreover, the study offered a new approach to automatically generate complex motion control algorithms under several environments.

Relation between the concepts we are learning in CCLab: Such a study involves various methods to generate complex object-to-object interaction on a 3D platform while attaching a self-developing algorithm to a visual art product. The research also adapts virtual simulation to basic physical elements such as force, movement, speed, etc.

Takeaways and inspiration: The idea of having an algorithm that develops itself could give visual arts a new layer of interactivity: let the outcome inspire the user, rather than only letting the user express their creativity. Having the idea of machine learning involved could expand the user’s experience time.

 

Individual Conclusion

Rebecca: This project includes automatically generating the physical appearance and movement of creatures. It makes me think of another more recent research video about making AI teach itself to walk. In this video, the mini AI creature learned how to walk on two feet independently. The generative arts can produce some outcomes that can’t be occurred to an ordinary person and then stimulate their creativity. These projects have proved the possibility of creating a completely automatically generated AI ecosystem in the future that we can experience through VR devices, or even live in. It inspired me that I can make a creature for my first big project that can automatically modify its appearance and behavior to adjust a randomly generated environment.

 

Sean: The project describes a system for creating virtual creatures using genetic algorithms and physical simulation. The creatures’ morphologies and neural systems are generated automatically, and different fitness evaluation functions are used to direct simulated evolutions towards specific behaviors such as swimming, walking, jumping, and following. The most inspiring part to me is the evolving theory of having several sets of competitions with a specific task in an arena to judge the advantages and disadvantages of changes in genetic layers. I would have a lot of interest in introducing these competitive rules into my coming big project.

CClab mini project2

Project title: Trisha’s Floating Dream

Link to the project:https://editor.p5js.org/N-A-E-S/sketches/N5_MncvSk

Description: This P5js work is based on the selfie from Trisha, who depicted her dream of everything around her floating and changing color. According to her description, I added some animation to her selfie and produced this work.

Visual Documentation:

Coding:

To achieve the animation of floating, I decided to introduce a variable to count the time. The reason why I didn’t choose frameCount is that this number increases too fast to control the movement, and decreasing the frameset would influence the tracking to the mouse position. Thus I introduced a variable t that increased 0.01 each frame. To limit the movement of all triangles, I decided to times a sin() function or cos() function after the Y axis of triangles.

 noStroke();
  fill(154, 205*cos(t), 155*sin(t));
  triangle(200, 100+15*sin(t), 200, 200+15*sin(t), 350, 100+15*sin(t));
  
  fill(255, 225*cos(t), 75*sin(t));
  triangle(40, 100+15*cos(t), 200, 25+15*cos(t), 100, 150+15*cos(t));
    
  fill(255*sin(t), 50, 175);
  triangle(400, 150-5*sin(t), 300, 50-5*sin(t), 380, 10-5*sin(t));
    
  fill(154, 212, 54);
  triangle(0, 70, 150, 0, 0, 0);
    
  fill(126*cos(t), 235*sin(t), 184*cos(t));
  triangle(0, 100+15*sin(t), 50, 200+15*sin(t), 100, 200+15*sin(t));
  
  fill(126, 270, 184);
  triangle(200, 50+15*cos(t), 260, 10+15*cos(t), 250, 70+15*cos(t));

 with the triangle functions, these triangles will slowly move around within 30 pixels,  acting as if they are floating.

Also, I used the same method to achieve the switching of color

Then I expected to achieve the function of keeping the eyes looking at the mouse, so I used a module function to control the distance, which eventually caused the consent shaking of the eyeballs. At first, I decided to use the map() function to replace but I found it quite funny so I just kept it.

// eyes
  strokeWeight(1)
  fill(0);
  ellipse(140,240,30);
  fill(255);
  ellipse(140+(mouseX-140)%10, 240+(mouseY-240)%10, 10);
  
  strokeWeight(1)
  fill(0);
  ellipse(270,240,30);
  fill(255);
  ellipse(270+(mouseX-270)%10, 240+(mouseY-240)%10, 10);
   

 As for the switching hair color part, I just declare key “s” to be the key that changes the color. Every press would lead to a random color.

Entire Coding:

function setup() {
  createCanvas(400, 400);
  background(255, 234, 124);
  }
let t=0;
let r=70;
let g=100;
let b=255;
  // add your code here!
  function draw() {
  background(255, 234, 124);
  t+=0.01;
  // hair //
  noStroke();
  if(keyIsPressed)
    if(key=='s')
      {
        r=random(255);
        g=random(255);
        b=random(255);
      }
  fill(r,g,b);
  rect(25, 200, 350, 200);
    
  noStroke();
  fill(r,g,b);
  rect(25, 160, 350, 50);
    
  fill(250, 250, 250);
  strokeWeight(1)
  ellipse(200, 200, 300, 350); 
    
  fill(r,g,b);
  arc(width/2, height/2.3, 350, 320, PI, PI*2, CHORD);
  
  arc(50, 90, 400, 250, 0, HALF_PI);
    
  ellipse(266, 130, 180);

// curves
 
    
  noFill()
  strokeWeight(5)
  arc(200, 250, 50, 90, PI*0, PI, CHORD);
  
  // eyes
  strokeWeight(1)
  fill(0);
  ellipse(140,240,30);
  fill(255);
  ellipse(140+(mouseX-140)%10, 240+(mouseY-240)%10, 10);
  
  strokeWeight(1)
  fill(0);
  ellipse(270,240,30);
  fill(255);
  ellipse(270+(mouseX-270)%10, 240+(mouseY-240)%10, 10);
  
    
// curves on the left
  noFill();
  stroke(600);
  strokeWeight(5);
  bezier(0, 250, 0, 100, 100, 0, 200, 0, 0, 0, 100, 0);
    
  noFill();
  strokeWeight(5);
  bezier(0, 100, 0, 100, 50, 0, 100, 0, 0, 0, 100, 0);
    
  noFill();
  strokeWeight(5);
  bezier(0, 40, 0, 15, 30, 0, 40, 0, 0, 0, 50, 0);

// curve on the right   
    
  noFill();
  stroke(600);
  strokeWeight(5);
  bezier(400, 0, 10, 0, 400, 0, 400, 160, 50, 0, 0, 0);
    
  noFill();
  strokeWeight(5);
  bezier(400, 0, 160, 0, 400, 0, 400, 105, 50, 0, 0, 0);
    
  noFill();
  strokeWeight(5);
  bezier(400, 0, 270, 0, 400, 0, 400, 40, 50, 0, 0, 0);
  
  // abstract design  
    
  noStroke();
  fill(154, 205*cos(t), 155*sin(t));
  triangle(200, 100+15*sin(t), 200, 200+15*sin(t), 350, 100+15*sin(t));
  
  fill(255, 225*cos(t), 75*sin(t));
  triangle(40, 100+15*cos(t), 200, 25+15*cos(t), 100, 150+15*cos(t));
    
  fill(255*sin(t), 50, 175);
  triangle(400, 150-5*sin(t), 300, 50-5*sin(t), 380, 10-5*sin(t));
    
  fill(154, 212, 54);
  triangle(0, 70, 150, 0, 0, 0);
    
  fill(126*cos(t), 235*sin(t), 184*cos(t));
  triangle(0, 100+15*sin(t), 50, 200+15*sin(t), 100, 200+15*sin(t));
  
  fill(126, 270, 184);
  triangle(200, 50+15*cos(t), 260, 10+15*cos(t), 250, 70+15*cos(t));
  
// mouth
  noStroke();
  fill(230, 130, 0);
  square(170, 300, 35, 9);
    
// earrings
    
  fill(255, 245, 94);
  ellipse(50, 290, 50, 60);
    
  fill(r,g,b);
  ellipse(50, 290, 20, 40);

  fill(255,245,94);
  ellipse(340, 290, 50, 60);
  
  fill(r,g,b);
  ellipse(340, 290, 20, 40); 
if (keyIsPressed)
  if(key=='s')
    {
      print(key)
    }
//save("sketch.png");
    
} 

 Reflection: The use of maths functions could provide a much easier way to the goal.

Partner comment: The eyeballs moving part is quite funny though the hair changing is a bit too fast.