Aves de Chile
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;
}
}
}