使用p5.js畫出動畫滑稽碰撞圖
阿新 • • 發佈:2018-12-20
使用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); }; }