【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);
};
}
运行效果:https://editor.p5js.org/weihao/sketches/SyvVYveam
参考文献:p5.js官方文档
https://p5js.org/zh-Hans/examples/motion-bouncy-bubbles.html
以上是 【JS】使用p5.js画出动画滑稽碰撞图 的全部内容, 来源链接: utcz.com/a/68405.html