canvas弹动

时间:2023-03-08 20:26:05

弹动,和缓动类似,不过是在终点前反复运动几次达到反弹的效果,具体的算法就是用目标点(target)和物体(mouse)的距离乘以系数累加至坐标上,这样就会有简单的弹动效果,但是一般的弹动效果都是慢慢变弱直至没有,所以我们的弹动需要乘以摩擦力(friction)来达到效果,此处举一例

canvas弹动

如图所示的图形便是一个可以拉的弹簧球效果,但是因为弹簧本身是有体积的,所以在程序中我们需要算出它的身躯是往哪个方向的,也就是角度(angle),之后算出我们拉长了它多少,然后弹性的返回到它身躯的地方(target)。

还是老规矩,上代码

var canvas = document.getElementById("canvas");
var cxt = canvas.getContext("2d");
var mouse = {
x: canvas.width / 2,
y: canvas.height / 2
}
var isDown = false;
var balles = [];
var friction = 0.95;
var ballA = new Ball(mouse.x, mouse.y - 40, 10);
balles.push(ballA);
var springLength = 50;
var spring = 0.03;

function Ball(x, y, radius, speed) {
this.x = x;
this.y = y;
this.radius = radius;
this.speed = speed;
this.vx = 0;
this.vy = 0;
}
var angle;
var dx = dy = 0;

function animation() {
cxt.clearRect(0, 0, canvas.width, canvas.height)
cxt.beginPath();
cxt.fillStyle = "#fff";
if(isRun) {
dx = ballA.x - mouse.x;
dy = ballA.y - mouse.y;
angle = Math.atan2(dy, dx);
targetX = mouse.x + Math.cos(angle) * springLength;
targetY = mouse.y + Math.sin(angle) * springLength;
ballA.vx += (targetX - ballA.x) * spring;
ballA.vy += (targetY - ballA.y) * spring;
ballA.vx *= friction;
ballA.vy *= friction;
ballA.x += ballA.vx;
ballA.y += ballA.vy;
if(ballA.vx > 0 && ballA.vx < 0.001) {
isRun = false;
}
}
cxt.arc(ballA.x, ballA.y, ballA.radius, 0, Math.PI * 2, true);
cxt.fill();
cxt.closePath();
cxt.beginPath();
cxt.strokeStyle = "#fff";
cxt.moveTo(canvas.width / 2, canvas.height / 2);
cxt.lineTo(ballA.x, ballA.y)
cxt.stroke();
cxt.closePath()
requestAnimationFrame(animation);
}
animation();

function move(event) {
if(isDown) {
ballA.x = event.point.x;
ballA.y = event.point.y;
}
}

function up(event) {
if(isDown) {
isRun = true;
}
isDown = false;
}

function down(event) {
if(tool.isMoveRadius(event.point, ballA, ballA.radius)) {
isDown = true;
}
isRun = false;
}
var isRun = false;
tool.MT(canvas, move, down, up);