Aves de Chile

Subject
Creative Coding
Year
2023

Click a bird to turn it white — click elsewhere to reset it. Click a zone of the canvas to add more of that bird (top-left thrush, top-right woodpecker, bottom-right hummingbird, bottom-left yellow bird, center flamingo). Hover to make hummingbirds flee. Press A to make birds fall, D to blow them right with the wind, X to stop any A/D movement. Press S to show their names, S again to hide them. F for fullscreen. Speak or make noise for the birds to gather at the center. Birds (and flamingos) that bump into each other get startled and randomly change size.

An ecosystem of Chilean birds.

Sketch code

sketch.js

//INTERACCIONES:
//mouseClicked en un pájaro: color cambia a blanco. Al clickear en otro lado vuelve a su color original.
//mouseClicked dependiendo de la zona en el canva: aumenta la cantidad de un cierto tipo de pájaros (arriba der: tordo, arriba izq: carpintero, abajo der:picaflor, abajo izq: pajaro amarillo y en el centro: flamenco)
//mouseOver: picaflores se escapan
//tecla a: los pájaros caen
//tecla s: nombres de los pájaros (se apreta denuevo para que desaparezcan)
//tecla d: pájaros se vuelan con el viento a la derecha
//tecla x: detiene el movimiento que hayan hecho a o d
//tecla f: fullscreen
//micrófono: pájaros al centro
//intersección de pájaros con flamencos (y también entre flamencos): se asustan y aumenta random su tamaño y se devuelve a su tamaño original


let mic;

//criaturas (pájaros de Chile)
let flamenco = [];
let pajaroamarillo = [];
let tordo = [];
let picaflor = [];
let carpintero = [];

let on = true;

//timers
let timer1, timer2;

//estados de las teclas a/s/d, controlados desde keyPressed() en vez de leer
//"key" directamente en el draw — así cada una se puede prender y apagar por
//separado en vez de que la última tecla apretada pise a las demás
let mostrarNombres = false; //tecla s: toggle, prende y apaga
let cayendo = false; //tecla a: prende con "a", lo apaga "x"
let viento = false; //tecla d: prende con "d", lo apaga "x"

//--------------------------------------------------------
function setup() {
  let cnv = createCanvas(windowWidth, windowHeight);
  cnv.parent('p5-sketch-holder'); // contiene el canvas dentro de la página en vez de flotar en el body
  angleMode(DEGREES);

  //microfono
  mic = new p5.AudioIn(); // Crea un input de audio
  mic.start(); // inicia microfono

  //Crear Pájaros
  nFlamencos = 2;
  nPamarillos = 2;
  nTordos = 2;
  nPicaflores = 2;
  nCarpinteros = 2;

  resetear(); //esto las inicializa, ver funcion abajo.



  //crear timers
  timer1 = new Timer(0, 3000);
  timer2 = new Timer(1, 500);
}

//--------------------------------------------------------
function draw() {
  background(10,0,230);

  //montañas
   fill(255,196,192);
  noStroke();
  triangle(width/8,height/12,-1000,height,width+500,height);
  triangle(width/3,0,-200,height,width+1000,height);
 triangle(width/1.5,-5,-500,height,width+1000,height);
  triangle(10*width/2,100,width/7,height,width/1.5,height);



  //Si hay sonido, los pájaros se van al centro del canvas
  let vol = mic.getLevel(); //obtener volumen del input de audio
  if (vol > 0.3) {

      for (let i=0; i<tordo.length; i++){
      tordo[i].centrar();
}

      for (let i=0; i<carpintero.length; i++){
      carpintero[i].centrar();
}

      for (let i=0; i<picaflor.length; i++){
  picaflor[i].centrar();
}

      for (let i=0; i<flamenco.length; i++){
  flamenco[i].centrar();
}

      for (let i=0; i<pajaroamarillo.length; i++){
  pajaroamarillo[i].centrar();
}

  }


  //llamar metodos de criaturas

  for (let i in flamenco) {
    flamenco[i].mueve(); //para que se mueva
    flamenco[i].cruzaBorde(); //para cruzar al otro lado del canvas
    flamenco[i].intersecta(); //para interacción entre pájaros
    flamenco[i].dibujaFlamenco();
  }


    for (let i in tordo) {
    tordo[i].mueve();
    tordo[i].cruzaBorde();
    tordo[i].intersecta();
    tordo[i].dibujaTordo();
    }


   for (let i in carpintero) {
    carpintero[i].mueve();
    carpintero[i].cruzaBorde();
    carpintero[i].intersecta();
    carpintero[i].dibujaCarpintero();
    }


    for (let i in pajaroamarillo) {
    pajaroamarillo[i].mueve();
    pajaroamarillo[i].cruzaBorde();
    pajaroamarillo[i].intersecta();
    pajaroamarillo[i].dibujaPamarillo();
    }


    for (let i in picaflor) {
    picaflor[i].mueve();
    picaflor[i].cruzaBorde();
    picaflor[i].intersecta();
    picaflor[i].dibujaPicaflor();
    picaflor[i].escape(); //para que los picaflores escapen del mouse
    }
}

//--------------------------------------------------------
function resetear() {
  //Esta funcion es llamada desde el setup y cada vez que cambia tamano de ventana

  for (let i = 0; i < nFlamencos; i++) {
    flamenco[i] = new Criatura(
      i,
      random(50, width - 50),//x
      random(50, height - 50), //y
      width/10, //tam
      random(0,width), //vX
      random(0,height),//vY
      color(242,129,119),
      color(242,129,119,200),
      color(242,129,119,150),
      color(242,129,119,100),
      color(242,129,119,50),
      0
    );
  }
     for (let i = 0; i < nTordos; i++) {
      tordo[i] = new Criatura(
      i,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/30,
      random(0, 50),
      random(0,500),
      color(2,8,115),
      color(2,8,115,200),
      color(2,8,115,150),
      color(2,8,115,100),
      color(0)
    );
     }

  for (let i = 0; i < nCarpinteros; i++) {
      carpintero[i] = new Criatura(
      i,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/30,
      random(0,30),
      random(0,200),
      color(255,0,84),
      color(255,0,84,200),
      color(255,0,84,150),
      color(255,0,84,100),
      color(0)
    );
     }

   for (let i = 0; i < nPamarillos; i++) {
   pajaroamarillo[i] = new Criatura(
      i,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/60,
      random(-50,5),
      random(-90,5),
   color(242,159,5),
      color(242,159,5),
      color(242,159,5),
      color(0),
      color(0)
    );
   }

   for (let i = 0; i < nPicaflores; i++) {
     picaflor[i] = new Criatura(
      i,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/60,
      random(-1, 1),
      random(-1, 1),
      color(2,115,74),
      color(2,115,74,200),
      color(2,115,74,150),
      color(0),
      color(0)
    );
}}

//--------------------------------------------------------
  function mouseClicked() { //cuando clickeo con el mouse en un pájaro se transforma en blanco y si clickeo en otra parte vuelve a su color original


      for (let i=0; i<carpintero.length; i++){
  carpintero[i].blanco();
}

      for (let i=0; i<tordo.length; i++){
  tordo[i].blanco();
}

      for (let i=0; i<picaflor.length; i++){
  picaflor[i].blanco();
}

    for (let i=0; i<pajaroamarillo.length; i++){
  pajaroamarillo[i].blanco();
}

    for (let i=0; i<flamenco.length; i++){
  flamenco[i].blanco();
}

//cuando clickeo con el mouse en una cierta zona aumenta la cantidad de un tipo de pájaro

    if(mouseX<width/2 && mouseY<height/2){
    tordo.push(new Criatura( //agrego un tordo a la lista
      tordo.length+1,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/30,
      random(0, 50),
      random(0,500),
      color(2,8,115),
      color(2,8,115,200),
      color(2,8,115,150),
      color(2,8,115,100),
      color(0)
    ));}

    if(mouseX<width/2 && mouseY>height/2){

    picaflor.push(new Criatura( //agrego un picaflor a la lista
      picaflor.length+1,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/60,
      random(-1, 1),
      random(-1, 1),
      color(2,115,74),
      color(2,115,74,200),
      color(2,115,74,150),
      color(0),
      color(0)
    ));}


    if(mouseX>width/2 && mouseY>height/2){
      pajaroamarillo.push(new Criatura( //agrego un pajaro amarillo a la lista
      pajaroamarillo.length+1,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/60,
      random(-50,5),
      random(-90,5),
   color(242,159,5),
      color(242,159,5),
      color(242,159,5),
      color(0),
      color(0)
    ));}

if(mouseX>width/2 && mouseY<height/2){

      carpintero.push(new Criatura( //agrego un carpintero a la lista
      carpintero.length+1,
      random(50, (width - 50)),
      random(50, (height - 50)),
      width/30,
      random(0,30),
      random(0,200),
      color(255,0,84),
      color(255,0,84,200),
      color(255,0,84,150),
      color(255,0,84,100),
      color(0)
    ));}

    if(mouseX>width/4 && mouseX<3*width/4 && mouseY>height/4 && mouseY<3*height/4){

      flamenco.push(new Criatura( //agrego un flamenco a la lista
      flamenco.length+1,
      random(50, width - 50),//X
      random(50, height - 50), //Y
      width/10, //t
      random(0,width), //vX
      random(0,height),//vY
      color(242,129,119),
      color(242,129,119,200),
      color(242,129,119,150),
      color(242,129,119,100),
      color(242,129,119,50),
      0
    ));}

  }

//--------------------------------------------------------
function keyPressed() { //para poner pantalla completa y resetear
  if (key === "f") {
    let fs = fullscreen();
    fullscreen(!fs);
    resetear();
  }

  if (key === "s") {
    mostrarNombres = !mostrarNombres; //al volver a apretar s, los nombres desaparecen
  }

  if (key === "a") {
    cayendo = true;
  }

  if (key === "d") {
    viento = true;
  }

  if (key === "x") {
    cayendo = false; //detiene el movimiento hecho con "a"
    viento = false; //detiene el movimiento hecho con "d"
  }
}
//--------------------------------------------------------
function windowResized() { //para ajustar a la pantalla
  resizeCanvas(windowWidth, windowHeight);
  resetear();
}

Criatura.js

class Criatura {
  constructor(id, x, y, t, vx, vy, c1,c2,c3,c4,c5,r) { //variables para los pájaros

    this.id = id;
    this.x = x;
    this.y = y;
    this.velX = vx;
    this.velY = vy;
    this.tam = t;
    this.c1 = c1;
    this.c2 = c2;
    this.c3 =c3;
    this.c4 = c4;
    this.c5 = c5;
    this.Inic1 = c1;
    this.Inic2 = c2;
    this.Inic3 =c3;
    this.Inic4 = c4;
    this.Inic5 = c5;
    this.tocando = false; //variable para cuando los pájaros se intersectan con un flamenco
    this.click = false; //variable para cuando se clickea
    this.r = r; //variable para que las alas roten


    this.velIniX = vx;
    this.velIniY = vy;
    this.dx = 1;
    this.dy = 1;
    this.IniX = x;
    this.IniY = y;

    this.tamIniX = t;
    this.tamIniY = t;

    this.ranX = random(-5, 5);
    this.ranY = random(-5, 5);

    this.r = -5;
  }

  //--------------------------------------------------------
  dibujaFlamenco() {

    //pico y cabeza
    noStroke();
    fill(255);
    triangle(this.x-this.tam/3.5,this.y+this.tam/3.5, this.x+this.tam/3.5, this.y+this.tam/3.5, this.x, this.y+this.tam);
    fill(this.c1);
    circle(this.x, this.y, this.tam); // => circulo en x,y, radio 30.


    // Ala derecha desde el centro
    push();
    translate(this.x,this.y);
    rotate(this.r);
    fill(this.c2);
    circle(0 + (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 + (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 + (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
    fill(this.c5);
    circle(0 + (this.tam*17/6), 0 - (this.tam*1/6), this.tam*1/3);
    pop();



    // Ala izq desde el centro
    push();
    translate(this.x,this.y);
    rotate(-this.r);
    fill(this.c2);
    circle(0 - (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 - (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 - (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
    fill(this.c5);
    circle(0 - (this.tam*17/6), 0 - (this.tam*1/6), this.tam*1/3);
    pop();

    //rotación de las alas
     this.r = this.r + 0.5;
    if (this.r ==40 ){
      this.r = -1;
    }

    //nombre del pajaro
     if (mostrarNombres) {
    fill(255);
  noStroke();
  textAlign(LEFT, TOP);
  textSize(width/40);
  text("Flamenco", this.x-width/20, this.y-this.tam);
  } else{fill(0);}

    //viento a la derecha
    if (viento) {
    this.x = this.x+10;
  }

    //caída
     if (cayendo) {
    this.y = this.y+10;
  }

  }



  //--------------------------------------------------------
   dibujaTordo() {

    //pico y cabeza
    noStroke();
    fill(255);
    triangle(this.x-this.tam/3.5,this.y+this.tam/3.5, this.x+this.tam/3.5, this.y+this.tam/3.5, this.x, this.y+this.tam);
    fill(this.c1);
    circle(this.x, this.y, this.tam); // => circulo en x,y, radio 30.


    // Ala derecha desde el centro
    push();
    translate(this.x,this.y);
    rotate(this.r);
    fill(this.c2);
    circle(0 + (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 + (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 + (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
    pop();

    // Ala izq desde el centro
    push();
    translate(this.x,this.y);
    rotate(-this.r);
    fill(this.c2);
    circle(0 - (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 - (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 - (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
     pop();


     //rotación de las alas
       this.r = this.r + 0.5;
    if (this.r ==30 ){
      this.r = 0;
    }

       //nombre del pajaro
    if (mostrarNombres) {
    fill(255);
  noStroke();
  textAlign(LEFT, TOP);
  textSize(width/40);
  text("Tordo", this.x-15, this.y-this.tam);
  } else{fill(0);}

    //viento a la derecha
    if (viento) {
    this.x = this.x+10;
  }
     //caída
     if (cayendo) {
    this.y = this.y+10;
  }
  }


    //--------------------------------------------------------
   dibujaCarpintero() {

      //pico y cabeza
    noStroke();
    fill(255);
    triangle(this.x-this.tam/3.5,this.y+this.tam/3.5, this.x+this.tam/3.5, this.y+this.tam/3.5, this.x, this.y+this.tam);
    fill(this.c1);
    circle(this.x, this.y, this.tam); // => circulo en x,y, radio 30.


      // Ala derecha desde el centro
   push();
     translate(this.x,this.y);
     rotate(this.r);
   fill(this.c2);
    circle(0 + (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 + (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 + (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
     pop();


    // Ala izq desde el centro
    push();
     translate(this.x,this.y);
     rotate(-this.r);
    fill(this.c2);
    circle(0 - (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 - (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
    fill(this.c4);
    circle(0 - (this.tam*7/3), 0-(this.tam*1/2), this.tam*1/2);
     pop();

     //rotación de las alas
       this.r = this.r + 0.5;
    if (this.r ==25 ){
      this.r = -1;
    }

       //nombre del pajaro
    if (mostrarNombres) {
    fill(255);
  noStroke();
  textAlign(LEFT, TOP);
  textSize(width/40);
  text("Carpintero", this.x-25, this.y-this.tam);
  } else{fill(0);}

    //viento a la derecha
    if (viento) {
    this.x = this.x+10;
  }

      //caída
     if (cayendo) {
    this.y = this.y+10;
  }
  }

    //--------------------------------------------------------
   dibujaPicaflor() {

      //pico y cabeza
    noStroke();
    fill(255);
    triangle(this.x-this.tam/3.5,this.y+this.tam/3.5, this.x+this.tam/3.5, this.y+this.tam/3.5, this.x, this.y+this.tam);
    fill(this.c1);
    circle(this.x, this.y, this.tam); // => circulo en x,y, radio 30.


      // Ala derecha desde el centro
     push();
     translate(this.x,this.y);
     rotate(this.r);
   fill(this.c2);
    circle(0 + (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 + (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
     pop();


    // Ala izq desde el centro
    push();
    translate(this.x,this.y);
    rotate(-this.r);
    fill(this.c2);
    circle(0 - (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 - (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
     pop();

     //rotación de las alas
      this.r = this.r + 1;
    if (this.r == 10){
      this.r = 0;
    }

       //nombre del pajaro
      if (mostrarNombres) {
    fill(255);
  noStroke();
  textAlign(LEFT, TOP);
  textSize(width/40);
  text("Picaflor", this.x-20, this.y-30);
  } else{fill(0);}

   //viento a la derecha
    if (viento) {
    this.x = this.x+10;
  }

     //caída
     if (cayendo) {
    this.y = this.y+10;
  }
  }

   //--------------------------------------------------------
   dibujaPamarillo() {

      //pico y cabeza
    noStroke();
    fill(255);
    triangle(this.x-this.tam/3.5,this.y+this.tam/3.5, this.x+this.tam/3.5, this.y+this.tam/3.5, this.x, this.y+this.tam);
    fill(this.c1);
    circle(this.x, this.y, this.tam); // => circulo en x,y, radio 30.

      // Ala derecha desde el centro
     push();
     translate(this.x,this.y);
     rotate(this.r);
   fill(this.c2);
    circle(0 + (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 + (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
     pop();


    // Ala izq desde el centro
    push();
    translate(this.x,this.y);
    rotate(-this.r);
    fill(this.c2);
    circle(0 - (this.tam), 0-(this.tam*1/2), this.tam*5/6);
    fill(this.c3);
    circle(0 - (this.tam*5/3), 0-(this.tam*14/15), this.tam*2/3);
     pop();

     //rotación de las alas
       this.r = this.r + 0.5;
    if (this.r ==10 ){
      this.r = -1;
    }

       //nombre del pajaro
      if (mostrarNombres) {
    fill(255);
  noStroke();
  textAlign(LEFT, TOP);
  textSize(width/40);
  text("Pájaro Amarillo", this.x-40, this.y-30);
  } else{fill(0);}

        //viento a la derecha
    if (viento) {
    this.x = this.x+10;
  }

      //caída
     if (cayendo) {
    this.y = this.y+10;
  }
  }
  //--------------------------------------------------------
  dibujaId() {
    push();
    fill(0);
    noStroke();
    textAlign(CENTER, CENTER);
    textSize(12);
    text(str(this.id), this.x, this.y);
    pop();
  }

  //--------------------------------------------------------
  mueve() { //sin para hacer el movimiento mas natural
   // this.x += this.velX;
   // this.y += this.velY;
     this.x +=  sin(frameCount/this.velX);
     this.y += sin(frameCount/this.velY*this.tam*2);
  }

  //--------------------------------------------------------
  cruzaBorde() {
    if (this.x > width + this.tam) {
      this.x = -this.tam;
    }
    if (this.x < -this.tam) {
      this.x = width + this.tam;
    }
    if (this.y > height + this.tam) {
      this.y = -this.tam;
    }
    if (this.y < -this.tam) {
      this.y = height + this.tam;
    }
  }

  //--------------------------------------------------------
  intersecta() { //cuando los pájaros intersectan a un flamenco se asustan aumentando su tamaño de forma random. Entre flamencos también puede pasar

    for (let i = 0; i < flamenco.length; i++) {
      let distancia = dist(this.x, this.y, flamenco[i].x, flamenco[i].y);

      if (distancia < this.tam && this.id !== flamenco[i].id) {
        this.tam = random(10,100);
        this.tocando = true;
        break;
      } else {
        this.tocando = false;
      }
    }
  }


   //--------------------------------------------------------
  escape() { //cuando el mouse se acerca al picaflor se arranca

      let distancia = dist(mouseX, mouseY, this.x,this.y);

      if (mouseX<this.x && distancia < 100) {
        this.x = this.x+100;
        this.tocando = true;
      }

    if (mouseX>this.x && distancia < 100) {
        this.x = this.x-100;
        this.tocando = true;
      }

     if (mouseY>this.y && distancia < 100) {
        this.y = this.y-100;
        this.tocando = true;
      }

     if (mouseY<this.y && distancia < 100) {
        this.y = this.y+100;
        this.tocando = true;
      }
    }

 //--------------------------------------------------------
  centrar() { //cuando se hace un sonido los pájaros se dirigen al centro

        this.x = width/2;
        this.y = height/2;
  }

   //--------------------------------------------------------
  blanco() { //cuando se clickea un pájaro su color cambia a blanco. Al clickear en otro lado vuelve a sus colores originales.

      let distancia = dist(mouseX, mouseY, this.x, this.y);

      if (distancia<50) {
        this.c1 = (255);
        this.c2 = (255);
        this.c3 = (255);
        this.c4 = (255);
        this.c5 = (255);
        this.click = true;
      } else {
        this.c1 = this.Inic1;
        this.c2 = this.Inic2;
        this.c3 = this.Inic3;
        this.c4 = this.Inic4;
        this.c5 = this.Inic5;
        this.click = false;
      }
    }

}

Timer.js

class Timer {
  constructor(id, tmax) {
    this.id = id;
    this.ti = 0;
    this.tmax = tmax;
    this.ttrans = 0;
    this.tactual = 0;
    this.contando = false;
  }

  iniciar(t) {
    this.ti = t;
    this.contando = true;
  }

  update() {
    if (this.contando) {
      this.tactual = millis();
    }
  }

  getPct() {
    if (this.ttrans < this.tmax && this.contando) {
      this.tactual = millis();
      this.ttrans = this.tactual - this.ti;
      let pct = map(this.ttrans, 0, this.tmax, 1, 0);
      // console.log(pct);
      return pct;
    } else {
      this.contando = false;
      this.ttrans = 0;
      return 0;
    }
  }
}

Daniela Masihy Kowoll