2017/11/25

Biblioteca p5.play

p5.play es una biblioteca de p5.js (que a su vez es una biblioteca de JavaScript) que nos permite trabajar con la clase Sprite, haciendo mucho más sencilla la creación de animaciones, detección de colisiones, interacción con teclado y ratón, etc.

En el ejemplo de más abajo he creado un Sprite con una animación formada por una secuencia de ocho dibujos. Si pulsas con el ratón en cualquier punto del área amarilla, el Sprite se moverá persiguiendo el click.



Código html:
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <title>Prueba p5.play.js</title>
    <script src="libraries/p5.js"></script>
    <script src="libraries/p5.play.js"></script>
    <script src="code.js"></script>
</head>
  <body style="text-align:center; margin:0px">
  </body>
</html>

Código p5.js:
var alien;
var secuenciaInvader;

function preload(){
  secuenciaInvader = loadAnimation(
    "images/SpriteAlien04a.png",
    "images/SpriteAlien04b.png",
    "images/SpriteAlien04c.png",
    "images/SpriteAlien04d.png",
    "images/SpriteAlien04e.png",
    "images/SpriteAlien04f.png",
    "images/SpriteAlien04g.png",
    "images/SpriteAlien04h.png"
    );
}

function setup() {
  createCanvas(500, 500);
  alien = createSprite(width/2, height/2,40,25);
  alien.addAnimation("default", secuenciaInvader);
  alien.rotateToDirection = false;
  alien.maxSpeed = 2;
  alien.friction = 0.05;
}

function draw() {
  background(255,215,0);
  if (mouseIsPressed) {
    alien.attractionPoint(0.5, mouseX, mouseY);
  }
  drawSprites();
}

2017/11/18

Objetos en p5.js



Código html:
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <title>Objetos en p5.js</title>
    <script src="libraries/p5.js"></script>
    <script src="code.js"></script>
</head>
  <body style="text-align:center; margin:0px">
  </body>
</html>

Código p5.js:
var cuadrado;

function setup() {
  createCanvas(500, 500);
  background(255,215,0);
  cuadrado = new Poligono();
}

function draw(){
  background(255,215,0,10);
  cuadrado.mover();
  cuadrado.dibujar();
}

function Poligono(){
  this.x;
  this.y;
  this.lado = 15;
  this.centroX = random(0 + this.lado, width - this.lado);
  this.centroY = random(0 + this.lado, height - this.lado);
  this.alpha = 0;

  this.mover = function(){
    this.x = this.centroX + cos(this.alpha)*25;
    this.y = this.centroY + sin(this.alpha)*25;
    this.alpha = this.alpha + (2*PI/360)*5;
  }

  this.dibujar = function(){
    rectMode(CENTER);
    fill(255,0,0);
    rect(this.x, this.y, this.lado, this.lado);
  }
}

2017/11/16

Tangencias: Caso 2A de Apolonio

Caso 2: PPR
Caso 2A: Los dos puntos están en el mismo lado de la recta.

Trazar las circunferencias que pasan por A y B y son tangentes a r.


2017/11/14

Algoritmo de conducción autónoma (I)

Sencillo algoritmo de conducción autónoma que puede aplicarse a robots seguidores de líneas.


Código html:
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <title>Robot sigue líneas</title>
    <script src="libraries/p5.js"></script>
    <script src="code.js"></script>
</head>
  <body style="text-align:center; margin:0px">
  </body>
</html>

Código p5.js:
var circuito;
var rgba, r, g, b, a;
var rojo;

function setup() {
  createCanvas(500, 500);
  circuito = loadImage("images/Circuito03.png");
  rojo = new Coche(250,410,3);
}

function draw(){
  image(circuito,0,0);
  rgba = get(mouseX, mouseY);
  r = subset(rgba, 0, 1);
  g = subset(rgba, 1, 1);
  b = subset(rgba, 2, 1);
  a = subset(rgba, 3, 1);
  debug();
  rojo.dibujar();
  rojo.mover();
}

function debug(){
  fill(255);
  text("MOUSE:", 10, 20);
  text("Position: " + mouseX + " " + mouseY, 10, 35);
  text("Color (RGBA): " + rgba, 10, 50);
  text("Red: " + r, 10, 65);
  text("Green: " + g, 10, 80);
  text("Blue: " + b, 10, 95);
  text("Alpha: " + a, 10, 110);
  text("ROJO:", 200, 20);
  text("Left G: " + rojo.l, 200, 35);
  text("Right G: " + rojo.r, 200, 50);
}

function Coche(x,y,v){
  this.x = x;
  this.y = y;
  this.v = v;
  this.angulo = 0;
  this.l;
  this.r;

  this.dibujar = function(){
    translate(this.x, this.y);
    rotate(this.angulo);
    fill(255,0,0);
    triangle(0,5,0,-5,10,0);
    stroke(255);
    strokeWeight(3);
    point(30, -10);
    point(30, +10);
    stroke(0);
    noStroke();
    this.l = subset(get(this.x +25*cos(this.angulo)-10*cos(this.angulo+(PI/2)), this.y +25*sin(this.angulo)-10*sin(this.angulo+(PI/2))), 1, 1);
    this.r = subset(get(this.x +25*cos(this.angulo)+10*cos(this.angulo+(PI/2)), this.y +25*sin(this.angulo)+10*sin(this.angulo+(PI/2))), 1, 1);
  }

  this.mover = function(){
    if(this.l == "0" && this.r == "0"){
      this.angulo = this.angulo + 0*(2*PI/360);
    }else if(this.l == "180" && this.r == "0"){
      this.angulo = this.angulo + 5*(2*PI/360);
    }else if(this.l == "0" && this.r == "180"){
      this.angulo = this.angulo - 5*(2*PI/360);
    }
    this.x = this.x + cos(this.angulo)*this.v;
    this.y = this.y + sin(this.angulo)*this.v;
  }
}

2017/11/11

Tangencias: Caso 4A de Apolonio

Caso 4: RRR
Caso 4A: Tres rectas secantes

Trazar las circunferencias tangentes a las tres rectas r, s y t dadas.


Tangencias: Caso 1A de Apolonio

Caso 1: PPP
Caso 1A: Los tres puntos no están alineados

Trazar la circunferencia que pasa por tres puntos A, B y C dados.


2017/11/10

Tangencias: Los 10 problemas de Apolonio

Los problemas de Apolonio siempre comienzan con tres elementos que pueden ser puntos, rectas y circunferencias. Las soluciones son circunferencias que pasan por los puntos y son tangentes a las rectas y las circunferencias. A continuación se muestra una clasificación que tiene en cuenta únicamente los datos iniciales que nos da el problema:


  • Caso 1: Punto, Punto, Punto
    • 1A: Los tres puntos no están alineados. 1 solución.
    • 1B: Los tres puntos están alineados. 0 soluciones.
  • Caso 2: Punto, Punto, Recta
    • 2A: Los dos puntos están del mismo lado de la recta. 2 soluciones.
    • 2B: Un punto pertenece a la recta. 1 solución.
    • 2C: La recta está entre los dos puntos. 0 soluciones.
  • Caso 3: Punto, Recta, Recta
    • 3A: Dos rectas secantes y un punto que no pertenece a ninguna. 2 soluciones.
    • 3B: Dos rectas secantes y un punto que pertenece a una de ellas. 2 soluciones.
    • 3C: Dos rectas secantes y un punto que pertenece a ambas rectas. 0 soluciones.
    • 3D: Dos rectas paralelas y un punto entre ellas. 2 soluciones.
    • 3E: Dos rectas paralelas y un punto que pertenece a una de ellas. 2 soluciones.
    • 3F: Dos rectas paralelas y un punto situado al lado de una de ellas. 0 soluciones.
  • Caso 4: Recta, Recta, Recta
    • 4A: Tres rectas secantes entre ellas. 4 soluciones.
    • 4B: Dos rectas paralelas y una secante a ambas. 2 soluciones.
    • 4C: Tres rectas paralelas. 0 soluciones.
  • Caso 5: Recta, Recta, Circunferencia
    • 5A: Dos rectas secantes entre ellas y una circunferencia no secante con ninguna de las rectas. 4 soluciones.
    • 5B: Dos rectas secantes entre ellas y una circunferencia secante con una de las rectas. 4 soluciones.
    • 5C: Dos rectas secantes entre ellas y una circunferencia secante con las dos rectas. 8 soluciones.
    • 5D: Dos rectas paralelas y una circunferencia situada entre ellas. 4 soluciones.
    • 5E: Dos rectas paralelas y una circunferencia secante con una de ellas. 2 soluciones.
    • 5F: Dos rectas paralelas y una circunferencia secante con las dos rectas. 4 soluciones.
    • 5G: Dos rectas paralelas y una circunferencia no secante situada al lado de una de las rectas. 0 soluciones.
  • Caso 6: Recta, Circunferencia, Circunferencia
    • 6A: Caso general (no lo damos en Bachillerato)
    • 6'A: Caso especial. Dos circunferencias iguales, tangentes y con la línea que une sus centros paralela a la recta. 2 soluciones.
  • Caso 7: Circunferencia, Circunferencia, Circunferencia
    • 7A: Caso general (no lo damos en Bachillerato)
    • 7'A: Caso especial. Tres circunferencias iguales y tangentes entre sí. 2 soluciones.
  • Caso 8: Circunferencia, Circunferencia, Punto
    • 8A: Caso general (no lo damos en Bachillerato)
    • 8'A: Caso especial. Dos circunferencias iguales, tangentes entre sí y un punto situado en la mediatriz de los centros de las circunferencias. 2 soluciones.
  • Caso 9: Circunferencia, Punto, Punto
    • 9A: Los dos puntos fuera de la circunferencia. 2 soluciones.
    • 9B: Los dos puntos dentro de la circunferencia. 2 soluciones.
    • 9C: Un punto dentro y otro fuera de la circunferencia. 0 soluciones.
    • 9D: Un punto fuera de la circunferencia y otro pertenecente a la misma. 1 solución.
    • 9E: Un punto dentro de la circunferencia y otro perteneciente a la misma. 1 solución.
    • 9'A: Caso especial. Los dos puntos son simétricos respecto a un diámetro de la circunferencia. 2 soluciones.
  • Caso 10: Punto, Recta, Circunferencia
    • 10A: El punto, la recta y la circunferencia no se tocan. 4 soluciones.
    • 10B: El punto pertenece a la recta. 2 soluciones.
    • 10C: El punto pertenece a la circunferencia. 2 soluciones.
    • 10D: La recta está entre el punto y la circunferencia. 0 soluciones.

Tangencias: Caso 10B de Apolonio

Caso 10: PRC
Caso 10B: El punto está en la recta

Trazar las circunferencias que pasen por el punto A y sean tangentes a la recta r y a la circunferencia c.



Tangencias: Caso 10C de Apolonio

Caso 10: PRC
Caso 10C: El punto está en la circunferencia

Trazar las circunferencias que pasen por el punto A y sean tangentes a la recta r y a la circunferencia c.


2017/11/09

Marabunta (WIP)



Código html:
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <title>Marabunta</title>
    <script src="libraries/p5.js"></script>
    <script src="marabunta.js"></script>
</head>
  <body link="black" style="text-align:center; margin:0px; background-color:white; font-family:sans-serif; font-size:12px; width:500px; margin-left:auto; margin-right:auto;">
    <h1 style="font-size:24px; text-align:center; color:grey;">MARABUNTA</h1>
    <p style="text-align:justify; color:grey;">Marabunta is a game of life programmed in <a href="https://p5js.org/" style="text-decoration:none" target="_blank">p5.js</a> and based on my <a href="http://antoniovallecillos.blogspot.com.es/2015/11/game-of-life-v22.html" style="text-decoration:none" target="_blank">Game of Life</a>. Just follow the instructions that appear on the screen or press de <b><cite>CTRL</cite></b> button to show more controls.
  </body>
</html>

Código p5.js
var specimens = 0;
var maximo = 5000;
var speed = 1;
var controles = -1;
var creaBicho = 1;
var numero = -1;
var aviso = 1;
var pointer = 100;
var pantallaX, pantallaY;
var iniControl1X, iniControl1Y;
var iniControl2X, iniControl2Y;
var iniControl3X, iniControl3Y;
var iniControl4X, iniControl4Y;
var iniControl5X, iniControl5Y;
var iniControl6X, iniControl6Y;
var i;

var hormigas = [];

function setup() {
  frameRate(300);
  createCanvas(500,500);
  pantallaX = width;
  pantallaY = height;
  iniControl1X = width-40;
  iniControl1Y = 5;
  iniControl2X = iniControl1X;
  iniControl2Y = iniControl1Y+40;
  iniControl3X = iniControl2X;
  iniControl3Y = iniControl2Y+40;
  iniControl4X = iniControl3X;
  iniControl4Y = iniControl3Y+40;  
  iniControl5X = iniControl4X;
  iniControl5Y = iniControl4Y+40;
  iniControl6X = iniControl5X;
  iniControl6Y = iniControl5Y+40;

  bichoX = width/2;
  bichoY = height/2;

  for (i=0; i<maximo; i++) {
    hormigas[i] = new Bicho(bichoX, bichoY, speed);
  }
}

function draw() {
  background(255, 200, 0);
  marcadorPermanente();
  if (controles == 1){
    marcador();
  }
  tap();

  for (i = 0; i < specimens; i++) {
    hormigas[i].mover();
    hormigas[i].dibujar();
  }
}

function marcadorPermanente(){
  var iniTituloX = 5;  
  var iniTituloY = 5;
  
  noFill();
  stroke(0, 100);
  rect (iniTituloX, iniTituloY, pantallaX-10-40, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(12);
  text ("MARABUNTA v0.24 [DEC-24-2016] - A GAME OF LIFE", (pantallaX-10-40)/2, 20);
  text ("DESIGN AND PROGRAMMING: ANTONIO VALLECILLOS @fotovallegrafia", (pantallaX-10-40)/2, 35);
  
  noFill();
  stroke(0, 100);
  if (controles == 1){
    fill (255,0,0,100);
  }
  rect (iniControl1X, iniControl1Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("CTRL", iniControl1X+18, iniControl1Y+22);
  
  if (specimens == 0){
    textAlign(CENTER);
    textSize(18);
    fill(255,0,0);
    if (aviso == 1) {
      text ("TAP THE SCREEN ANYWHERE", width/2, height/2-20);
      text ("SO THAT A NEW SPECIMEN IS BORN", width/2, (height/2));
    }
    textSize(12);
  }
}

function marcador() {
  var iniGameX = 5;
  var iniGameY = 45;
  var iniDebugX = 5;
  var iniDebugY = 135;
  
  noFill();
  stroke(0,100);
  rect (iniGameX, iniGameY, 150, 85);
  fill(0, 100);
  line (iniGameX, iniGameY+20, iniGameX+150, iniGameY+20);
  textAlign(LEFT);
  textSize(12);
  text ("GAME PARAMETERS:", 10, 60);
  text ("TIME = " + round(millis()/1000), 10, 80);
  text ("SPECIMENS = " + specimens, 10, 95);
  text ("SPEED = " + speed, 10, 110);
  text ("LIFE = CHON", 10, 125);
  stroke(0, 100);
  
  noFill();
  rect (iniDebugX, iniDebugY, 150, 40);
  fill(0, 100);
  line (iniDebugX, iniDebugY+20, iniDebugX+150, iniDebugY+20);
  textAlign(LEFT);
  textSize(12);
  text ("DEBUG:", iniDebugX+5, iniDebugY+15);
  text ("FRAME RATE = " + round(frameRate()), iniDebugX+5, iniDebugY+35);
  
  noFill();
  if (creaBicho == 1){
    textSize(10);
    fill(255,0,0);
    textAlign(CENTER);
    text ("TAP THE SCREEN", iniControl2X+18-65, iniControl2Y+22); 
    fill (255,0,0,100);
  }
  rect (iniControl2X, iniControl2Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("BUG+", iniControl2X+18, iniControl2Y+22);
  
  noFill();
  if (creaBicho == 0){
    if (specimens > 0){
      textSize(10);
      fill(255,0,0);
      textAlign(CENTER);
      text ("TAP THE SCREEN", iniControl3X+18-65, iniControl3Y+22); 
    }
    fill (255,0,0,100);
  }
  rect (iniControl3X, iniControl3Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("BUG-", iniControl3X+18, iniControl3Y+22);
  
  noFill();
  rect (iniControl4X, iniControl4Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("VEL+", iniControl4X+18, iniControl4Y+22);

  noFill();
  rect (iniControl5X, iniControl5Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("VEL-", iniControl5X+18, iniControl5Y+22);  

  noFill();
  if (numero == 1){
    fill (255,0,0,100);
  }
  rect (iniControl6X, iniControl6Y, 35, 35);
  fill(0, 100);
  textAlign(CENTER);
  textSize(10);
  text ("NUM", iniControl6X+18, iniControl6Y+22); 
}

function tap(){
  pointer = pointer + 1;
  if (pointer < 5) {
    ellipseMode(CENTER);
    noStroke();
    fill(255,0,0,3);
    for (var a = 10; a < 76; a++){
    ellipse(mouseX, mouseY, a, a);
    }
  }
}

function mousePressed(){
  aviso = 0;
  pointer = 0;
  if (iniControl1X <= mouseX && mouseX <= iniControl1X+35 && iniControl1Y <= mouseY && mouseY <= iniControl1Y+35) {
    controles = controles*-1;
  }else if (iniControl2X <= mouseX && mouseX <= iniControl2X+35 && iniControl2Y <= mouseY && mouseY <= iniControl2Y+35 && controles == 1) {
    creaBicho = 1;
  }else if (iniControl3X <= mouseX && mouseX <= iniControl3X+35 && iniControl3Y <= mouseY && mouseY <= iniControl3Y+35 && controles == 1) {
    creaBicho = 0;
  }else if (iniControl4X <= mouseX && mouseX <= iniControl4X+35 && iniControl4Y <= mouseY && mouseY <= iniControl4Y+35 && controles == 1) {
    speed = speed + 1;
  }else if (iniControl5X <= mouseX && mouseX <= iniControl5X+35 && iniControl5Y <= mouseY && mouseY <= iniControl5Y+35 && controles == 1) {
    if(speed>0){
      speed = speed - 1;
    }
  }else if (iniControl6X <= mouseX && mouseX <= iniControl6X+35 && iniControl6Y <= mouseY && mouseY <= iniControl6Y+35 && controles == 1) {
    numero = numero * -1;
  }else if(specimens<maximo && creaBicho == 1){
    specimens = specimens+1;
    hormigas[i].nacer();
  }else if(specimens>0 && creaBicho == 0){
    specimens = specimens-1;
    hormigas[i].nacer();
  }
}

function Bicho(xpos, ypos, vel) {
  this.x = xpos;
  this.y = ypos;
  this.velocidad = vel;
  this.angulo = random(0, 2*PI);

  this.nacer = function(){
    this.x = mouseX;
    this.y = mouseY;
  }

  this.dibujar = function() {
    applyMatrix();
    translate(this.x,this.y);
    fill(0,125,0,255);
    if (numero == 1){
      textAlign(LEFT);
      text (i+1,8,4);
    }
    rotate(this.angulo);
    fill(0);
    strokeWeight(1);
    stroke(0,0,0);
    line(-5,0,0,0);
    noStroke();
    triangle(0,-3,0,4,8,1);
    resetMatrix();
  }

  this.mover = function(){
    if (speed > 0){
      if (this.x >= pantallaX-1){
        this.angulo = this.angulo + random(PI-PI/4, PI+PI/4);
        this.x = this.x-1;
      } else if (this.x <= 0){
        this.angulo = this.angulo + random(PI-PI/4, PI+PI/4);
        this.x = this.x+1;
      } else if (this.y >= pantallaY-1){
        this.angulo = this.angulo + random(PI-PI/4, PI+PI/4);
        this.y = this.y-1;
      } else if (this.y <= 0){
        this.angulo = this.angulo + random(PI-PI/4, PI+PI/4);
        this.y = this.y+1;
      } else {      
        this.angulo = this.angulo + random(-PI/12,PI/12);
      }
      this.velocidad = speed;
      this.x = this.x + cos(this.angulo)*this.velocidad;
      this.y = this.y + sin(this.angulo)*this.velocidad;
    }
  }
}