1. 程式人生 > >使用p5.js畫出動畫滑稽碰撞圖

使用p5.js畫出動畫滑稽碰撞圖

使用p5.js做了一個動態碰撞的滑稽笑臉,效果如圖 滑稽首先是定義了一個畫滑稽的函式,其中引數分別是滑稽的橫縱座標、大小以及眼珠的朝向,L可取-1和1兩個值,-1向右,1向左。臉用了兩個填充的圓重疊(也可一個圓加邊框)。嘴和眼睛以及眉毛是分別畫兩個圓弧相重疊而成。

function huaji(x,y,size,l){
	noStroke();
	fill(237,148,14);
	ellipse(x,y,1.06*size);
        fill(252,222,12);
        ellipse(x,y,size);//臉
	
	fill(173,91,10);
	arc(x, y, 0.8*size, 0.8*size, 0, PI, CHORD);
	fill(252,222,12);
	arc(x, y-0.01*size, 0.8*size, 0.7*size, 0, PI, CHORD);//笑
	
	fill(254,240,205);
	arc(x-0.25*size, y, 0.8*size, 0.6*size, 1.3*PI,1.7* PI, PIE);
	fill(252,222,12);
	arc(x-0.25*size, y, 0.8*size, 0.5*size, 1.3*PI,1.7* PI, PIE);
	
	
	fill(254,240,205);
	arc(x+0.25*size, y, 0.8*size, 0.6*size, 1.3*PI,1.7* PI, PIE);
	fill(252,222,12);
	arc(x+0.25*size, y, 0.8*size, 0.5*size, 1.3*PI,1.7* PI, PIE);//眼殼子
	if(l==-1){
	    fill(173,91,10);
  	    ellipse(x-0.34*size,y-0.28*size,0.1*size);
	    ellipse(x+0.16*size,y-0.28*size,0.1*size);//眼珠
	}
       if(l==1){
	    fill(173,91,10);
  	    ellipse(x-0.1*size,y-0.28*size,0.1*size);
	    ellipse(x+0.35*size,y-0.28*size,0.1*size);//眼珠
	}
	
	fill(58,43,1);
	arc(x-0.28*size, y-0.35*size,0.20*size, 0.20*size, 1.1*PI,2.1* PI, OPEN);
	fill(252,222,12);
	arc(x-0.28*size, y-0.35*size, 0.21*size, 0.16*size, 1*PI,2.2* PI, OPEN);
	
	fill(58,43,1);
	arc(x+0.28*size, y-0.35*size,0.20*size,0.20*size, 0.9*PI,1.9* PI, CHORD);
	fill(252,222,12);
	arc(x+0.28*size, y-0.35*size, 0.21*size, 0.15*size, 0.9*PI,1.9* PI, CHORD);//眉毛

	
	fill(241,74,56);
	ellipse(x-0.25*size,y-0.18*size,0.25*size,0.07*size);
	ellipse(x+0.25*size,y-0.18*size,0.25*size,0.07*size);
}

接下來是碰撞,

var numBalls = 10;
var spring = 0.05;
var gravity = 0.03;
var friction = -0.9;
var balls = [];


function setup() {
  createCanvas(720, 400);
  for (var i = 0; i < numBalls; i++) {
    balls[i] = new Ball(
      random(width),
      random(height),
      random(30, 100),
      i,
      balls
    );
  }
  noStroke();
  fill(255, 204);
}

function draw() {
  background(0);
  balls.forEach(ball => {
    ball.collide();
    ball.move();
    ball.display();
  });
}



以上可以看出,定義了一些變數以及初始化了畫布,並初始化了十個ball。 對每一個ball執行碰撞、移動和展示。我們接下來看看這三個函式分別是怎樣的。 首先,第一個函式colide中,對每一個球求距離並與兩球半徑和進行比較,當小於兩球半徑之和的時候,證明兩球相撞了,求出加速度,對兩球速度進行改變。 第二個函式move中,如果球撞到牆,將其速度*-0.9,即反向並略減少速度,而且每次都有個向下的加速度。所以後來的滑稽會慢慢停下。在前兩個函式中都對m進行取反的操作,即可每次碰撞都變化眼珠的朝向,而當速度非常小的時候,將m的值固定。 第三個函式display則是呼叫滑稽函式。

function Ball(xin, yin, din, idin, oin) {
  this.x = xin;
  this.y = yin;
  var vx = 0;
  var vy = 0;
  var m=1;
  this.diameter = din;
  this.id = idin;
  this.others = oin;

  this.collide = function() {
    for (var i = this.id + 1; i < numBalls; i++) {
      var dx = this.others[i].x - this.x;
      var dy = this.others[i].y - this.y;
      var distance = sqrt(dx * dx + dy * dy);
      var minDist = this.others[i].diameter / 2 + this.diameter / 2;
      if (distance < minDist) {
        var angle = atan2(dy, dx);
        var targetX = this.x + cos(angle) * minDist;
        var targetY = this.y + sin(angle) * minDist;
        var ax = (targetX - this.others[i].x) * spring;
        var ay = (targetY - this.others[i].y) * spring;
        vx -= ax;
        vy -= ay;
        this.others[i].vx += ax;
        this.others[i].vy += ay;
	m*=-1;
      }
    }
  };

  this.move = function() {
    vy += gravity;
    this.x += vx;
    this.y += vy;
    if (this.x + this.diameter / 2 > width) {
      this.x = width - this.diameter / 2;
      vx *= friction;
			m*=-1;
    } else if (this.x - this.diameter / 2 < 0) {
      this.x = this.diameter / 2;
      vx *= friction;
			m*=-1;
    }
    if (this.y + this.diameter / 2 > height) {
      this.y = height - this.diameter / 2;
      vy *= friction;
			m*=-1;
    } else if (this.y - this.diameter / 2 < 0) {
      this.y = this.diameter / 2;
      vy *= friction;
			m*=-1;
    }
		if((vx<0.1&&vx>-0.1)&&(vy<=0.1&&vy>-0.1)){
			 m=-1;}
  };

  this.display = function() {
    huaji(this.x, this.y, this.diameter, m);
  };
}