捕获物体
多边形以及不规则图形的捕获非常复杂,采用的方法是分离轴定理(SAT)和最小平移向量(MTV)。这里不展开介绍,有兴趣的小伙伴可以自行搜索了解一下。下面来介绍一下矩形和圆的捕获。
矩形的捕获
如果鼠标点击坐标落在矩形上,则说明捕获了这个矩形;如果鼠标点击坐标没有落在矩形上,则说明没有捕获到这个矩形。
if (mouse.x > rect.x && mouse.x < rect.x + rect.width && mouse.y > rect.y && mouse.y < rect.y + rect.height) { …… }
圆的捕获
判定鼠标与圆心之间的距离。如果距离小于圆的半径,说明鼠标落在了圆上面;如果距离大于或等于圆的半径,说明鼠标落在了圆的外面。
dx = mouse.x - ball.x; dy = mouse.y - ball.y; distance = Math.sqrt(dx*dx + dy*dy); if(distance < ball.radius){ …… }
捕获静止物体
js/ball.js 中添加 checkMouse(),专门用来检测是否捕获了小球
Ball.prototype = { checkMouse:function(mouse) { var dx = mouse.x - this.x; var dy = mouse.y - this.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < this.radius) { return true; } else { return false; } } }
捕获动态物体
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(0, cnv.height / 2, 20); var mouse = tools.getMouse(cnv); //isMouseDown用于标识鼠标是否按下的状态 var isMouseDown = false; var vx = 3; cnv.addEventListener("mousedown", function () { //判断鼠标点击坐标是否位于小球上,如果是,则isMouseDown为true if (ball.checkMouse(mouse)) { isMouseDown = true; alert("捕获成功"); } }, false); (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); //如果鼠标不是按下状态,则小球继续运动,否则就会停止 if (!isMouseDown) { ball.x += vx; } ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
使用一个变量isMouseDown来标识鼠标是否按下的状态。然后为Canvas添加一个mousedown事件,并且在事件中对按下鼠标的坐标进行判断。在动画循环中,如果鼠标不是按下状态,则小球继续运动,否则就会停止。
拖拽物体
(1)捕获物体:在鼠标按下(mousedown)时,判断鼠标坐标是否落在物体上面,如果落在,就添加两个事件:mousemove和moveup。
(2)移动物体:在鼠标移动(mousemove)中,更新物体坐标为鼠标坐标。
(3)松开物体:在鼠标松开(mouseup)时,移除mouseup事件(自身事件也得移除)和mousemove事件。
cnv.addEventListener("mousedown", function () { document.addEventListener("mousemove", onMouseMove, false); document.addEventListener("mouseup", onMouseUp, false); }, false);
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(cnv.width / 2, cnv.height / 2, 20); ball.fill(cxt); var mouse = tools.getMouse(cnv); var dx = 0, dy = 0; cnv.addEventListener("mousedown", function () { if (ball.checkMouse(mouse)) { //dx为鼠标与球心的水平偏移量 dx = mouse.x - ball.x; //dy为鼠标与球心的垂直偏移量 dy = mouse.y - ball.y; document.addEventListener("mousemove", onMouseMove, false); document.addEventListener("mouseup", onMouseUp, false); } }, false); function onMouseMove() { //更新小球坐标 ball.x = mouse.x - dx; ball.y = mouse.y - dy; //加入边界限制 //当小球碰到左边界时 if (ball.x < ball.radius) { ball.x = ball.radius; //当小球碰到右边界时 } else if (ball.x > cnv.width - ball.radius) { ball.x = cnv.width - ball.radius; } //当小球碰到上边界时 if (ball.y < ball.radius) { ball.y = ball.radius; //当小球碰到下边界时 } else if (ball.y > cnv.height - ball.radius) { ball.y = cnv.height - ball.radius; } } function onMouseUp() { document.removeEventListener("mouseup", onMouseUp, false); document.removeEventListener("mousemove", onMouseMove, false); } (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
抛掷物体
用鼠标选中一个物体,拖拽它向某个方向移动,松开鼠标后物体会沿着拖拽的方向继续前进。在抛掷物体时,必须在拖拽物体的过程中计算物体的速度向量,并且在释放物体时将这个速度向量赋给物体。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(cnv.width / 2, cnv.height / 2, 20); ball.fill(cxt); var mouse = tools.getMouse(cnv); var isMouseDown = false; var dx = 0, dy = 0; //oldX和oldY用于存储小球旧的坐标 var oldX, oldY; //初始速度vx和vy都为0 var vx = 0, vy = 0; //添加mousedown事件 cnv.addEventListener("mousedown", function () { //判断鼠标点击是否落在小球上 if (ball.checkMouse(mouse)) { //鼠标按下小球时,isMouseDown设置为true isMouseDown = true; //鼠标按下小球时,将当前鼠标位置赋值给oldX和oldY oldX = ball.x; oldY = ball.y; dx = mouse.x - ball.x; dy = mouse.y - ball.y; document.addEventListener("mousemove", onMouseMove, false); document.addEventListener("mouseup", onMouseUp, false); } }, false); function onMouseMove() { //鼠标移动时,更新小球坐标 ball.x = mouse.x - dx; ball.y = mouse.y - dy; } function onMouseUp() { //鼠标松开时,isMouseDown设置为false isMouseDown = false; document.removeEventListener("mouseup", onMouseUp, false); document.removeEventListener("mousemove", onMouseMove, false); } (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); if (isMouseDown) { //如果isMouseDown为true,用当前小球的位置减去上一帧的坐标 vx = ball.x - oldX; vy = ball.y - oldY; //如果isMouseDown为true,更新oldX和oldY为当前小球中心坐标 oldX = ball.x; oldY = ball.y; } else { //如果isMouseDown为false,小球沿着抛掷方向运动 ball.x += vx; ball.y += vy; } ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="300" height="200" style="border:1px solid silver;"></canvas> </body> </html>
加入边界检测
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height / 2, 20); ball.fill(cxt); var mouse = tools.getMouse(cnv); var isMouseDown = false; var dx = 0, dy = 0; //oldX和oldY用于存储小球旧的坐标 var oldX, oldY; //初始速度vx和vy都为0 var vx = 0, vy = 0; //添加mousedown事件 cnv.addEventListener("mousedown", function () { //判断鼠标点击是否落在小球上 if (ball.checkMouse(mouse)) { //鼠标按下小球时,isMouseDown设置为true isMouseDown = true; //鼠标按下小球时,将当前鼠标位置赋值给oldX和oldY oldX = ball.x; oldY = ball.y; dx = mouse.x - ball.x; dy = mouse.y - ball.y; document.addEventListener("mousemove", onMouseMove, false); document.addEventListener("mouseup", onMouseUp, false); } }, false); function onMouseMove() { //鼠标移动时,更新小球坐标 ball.x = mouse.x - dx; ball.y = mouse.y - dy; //加入边界限制 //当小球碰到左边界时 if (ball.x < ball.radius) { ball.x = ball.radius; //当小球碰到右边界时 } else if (ball.x > cnv.width - ball.radius) { ball.x = cnv.width - ball.radius; } //当小球碰到上边界时 if (ball.y < ball.radius) { ball.y = ball.radius; //当小球碰到下边界时 } else if (ball.y > cnv.height - ball.radius) { ball.y = cnv.height - ball.radius; } } function onMouseUp() { //鼠标松开时,isMouseDown设置为false isMouseDown = false; document.removeEventListener("mouseup", onMouseUp, false); document.removeEventListener("mousemove", onMouseMove, false); } (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); if (isMouseDown) { //如果isMouseDown为true,用当前小球的位置减去上一帧的坐标 vx = ball.x - oldX; vy = ball.y - oldY; //如果isMouseDown为true,更新oldX和oldY为当前小球中心坐标 oldX = ball.x; oldY = ball.y; } else { //如果isMouseDown为false,小球沿着抛掷方向运动 ball.x += vx; ball.y += vy; //边界反弹 //碰到右边界 if (ball.x > cnv.width - ball.radius) { ball.x = cnv.width - ball.radius; vx = -vx; //碰到左边界 } else if (ball.x < ball.radius) { ball.x = ball.radius; vx = -vx; } //碰到下边界 if (ball.y > cnv.height - ball.radius) { ball.y = cnv.height - ball.radius; vy = -vy; //碰到上边界 } else if (ball.y < ball.radius) { ball.y = ball.radius; vy = -vy; } } ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="300" height="200" style="border:1px solid silver;"></canvas> </body> </html>
加入重力和反弹消耗
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height, 20); ball.fill(cxt); var mouse = tools.getMouse(cnv); var isMouseDown = false; var dx = 0, dy = 0; //oldX和oldY用于存储小球旧的坐标 var oldX, oldY; //初始速度vx和vy都为0 var vx = 0, vy = 0; //加入重力和反弹消耗 var gravity = 1.5; var bounce = -0.8; cnv.addEventListener("mousedown", function () { //判断鼠标点击是否落在小球上 if (ball.checkMouse(mouse)) { //鼠标按下小球时,isMouseDown设置为true isMouseDown = true; //鼠标按下小球时,将当前鼠标位置赋值给oldX和oldY oldX = ball.x; oldY = ball.y; dx = mouse.x - ball.x; dy = mouse.y - ball.y; document.addEventListener("mousemove", onMouseMove, false); document.addEventListener("mouseup", onMouseUp, false); } }, false); function onMouseMove() { //鼠标移动时,更新小球坐标 ball.x = mouse.x - dx; ball.y = mouse.y - dy; //加入边界限制 //当小球碰到左边界时 if (ball.x < ball.radius) { ball.x = ball.radius; //当小球碰到右边界时 } else if (ball.x > cnv.width - ball.radius) { ball.x = cnv.width - ball.radius; } //当小球碰到上边界时 if (ball.y < ball.radius) { ball.y = ball.radius; //当小球碰到下边界时 } else if (ball.y > cnv.height - ball.radius) { ball.y = cnv.height - ball.radius; } } function onMouseUp() { //鼠标松开时,isMouseDown设置为false isMouseDown = false; document.removeEventListener("mouseup", onMouseUp, false); document.removeEventListener("mousemove", onMouseMove, false); } (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); if (isMouseDown) { //如果isMouseDown为true,用当前小球的位置减去上一帧的坐标 vx = ball.x - oldX; vy = ball.y - oldY; //如果isMouseDown为true,更新oldX和oldY为当前小球中心坐标 oldX = ball.x; oldY = ball.y; } else { //如果isMouseDown为false,小球沿着抛掷方向运动 vy += gravity; ball.x += vx; ball.y += vy; //边界检测 //碰到右边界 if (ball.x > canvas.width - ball.radius) { ball.x = canvas.width - ball.radius; vx = vx * bounce; //碰到左边界 } else if (ball.x < ball.radius) { ball.x = ball.radius; vx = vx * bounce; } //碰到下边界 if (ball.y > canvas.height - ball.radius) { ball.y = canvas.height - ball.radius; vy = vy * bounce; //碰到上边界 } else if (ball.y < ball.radius) { ball.y = ball.radius; vy = vy * bounce; } } ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="300" height="200" style="border:1px solid silver;"></canvas> </body> </html>
缓动动画
带有一定缓冲效果的动画。在动画过程中,物体在某一段时间会“渐进加速”或“渐进减速”,从而让物体运动看起来更为自然而逼真,实现思路如下:
(1)定义一个0~1之间的缓动系数easing。
(2)计算出物体与终点之间的距离。
(3)计算出当前速度,其中当前速度=距离×缓动系数。
(4)计算新的位置,其中新的位置=当前位置+当前速度。
(5)重复执行第2~4步,直到物体达到目标。
每一帧中都将物体与终点之间的距离乘以缓动系数,从而求出当前速度。随着距离的不断减小,速度也就不断减小
在摩擦力动画中,每一帧中,当前速度等于上一帧速度乘以摩擦系数,其中速度是按照固定比例改变的;但是在缓动动画中,每一帧中,当前速度等于距离乘以缓动系数,其中速度并不是按照固定比例改变的。
实际开发中,更倾向于使用缓动动画。因为相对摩擦力动画来说,缓动动画更加自然而平滑。
缓动动画不仅可以用于物体的运动,还可以应用于物体的其他各种属性,包括大小、颜色、透明度以及旋转等。
缓动动画的核心要点:
(1)当前速度 =(最终值 - 当前值)×缓动系数。
(2)新的值 = 当前值 + 当前速度。
var targetX = 任意位置; var targetY = 任意位置; //动画循环 var vx = (targetX – object.x) * easing; var vy = (targetY– object.y) * easing;
- targetX和targetY分别为目标的横坐标和纵坐标
- easing为缓动系数,取值0~1,当系数越接近于1时,小球移动得越快;当系数越接近于0时,小球移动得越慢。
- vx和vy分别为物体在x轴方向和y轴方向上的速度
水平/垂直缓动
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(0, cnv.height / 2); //定义终点的x轴坐标 var targetX = cnv.width * (3 / 4); //定义缓动系数 var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var vx = (targetX - ball.x) * easing; ball.x += vx; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
任意方向缓动
分解为水平和垂直方向缓动即可。
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(0, 0); //定义终点的x轴坐标和y轴坐标 var targetX = cnv.width * (3 / 4); var targetY = cnv.height * (1 / 2); //定义缓动系数 var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var vx = (targetX - ball.x) * easing; var vy = (targetY - ball.y) * easing; ball.x += vx; ball.y += vy; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
实战范例:小球缓动追随鼠标
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(cnv.width / 2, cnv.height / 2, 15, "#FF6699"); var mouse = tools.getMouse(cnv); var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var vx = (mouse.x - ball.x) * easing; var vy = (mouse.y - ball.y) * easing; ball.x += vx; ball.y += vy; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
实战范例:多小球缓动追随鼠标
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var bigBall = new Ball(cnv.width / 2, cnv.height / 2, 15, "# FF6699"); var smallBall = new Ball(cnv.width / 2, cnv.height / 2, 12, "#66CCFF"); var mouse = tools.getMouse(cnv); var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); //第1个小球跟随鼠标移动 var vx1 = (mouse.x - bigBall.x) * easing; var vy1 = (mouse.y - bigBall.y) * easing; bigBall.x += vx1; bigBall.y += vy1; bigBall.fill(cxt); //第2个小球跟随第1个小球移动 var vx2 = (bigBall.x - smallBall.x) * easing; var vy2 = (bigBall.y - smallBall.y) * easing; smallBall.x += vx2; smallBall.y += vy2; smallBall.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
常见应用:放大缩小
缓动动画作用于尺寸(此处为半径)的改变
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height / 2); var targetRadius = 36; var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var vRadius = (targetRadius - ball.radius) * easing; ball.radius += vRadius; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
常见应用:淡入淡出
缓动动画作用于透明度的改变
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(cnv.width / 2, cnv.height / 2, 30, "rgba(255,102,153,1.0)"); var opacity = 1.0; var targetOpacity = 0.0; var easing = 0.05; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var v = (targetOpacity - opacity) * easing; opacity += v; ball.color = "rgba(255,102,153," + opacity + ")"; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
常见应用:颜色渐变
缓动动画作用于颜色的改变
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(cnv.width / 2, cnv.height / 2, 30); ball.fill(cxt); var easing = 0.02; var red = 255; var green = 0; var blue = 0; var targetRed = 10; var targetGreen = 255; var targetBlue = 55; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var vRed = (targetRed - red) * easing; var vGreen = (targetGreen - green) * easing; var vBlue = (targetBlue - blue) * easing; red += vRed; green += vGreen; blue += vBlue; var color = "rgba(" + parseInt(red) + "," + parseInt(green) + ", " + parseInt(blue) + "," + "1.0)"; ball.color = color; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
弹性动画
物体滑动到终点后还会来回反弹一会儿,直至停止。
弹性动画中,跟距离成正比的是“加速度”。物体离终点越远,加速度越大。刚刚开始,由于加速度的影响,速度会快速增大。当物体接近终点时,加速度变得很小,但是它还在加速。由于加速度的影响,物体会越过终点。然后随着距离的变大,反向加速度也随之变大,就会把物体拉回来。物体在终点附近来回反弹一会儿,最终在摩擦力的作用下停止。
ax = (targetX - object.x) * spring; ay = (targetY - object.y) * spring; vx += ax; vy += ay; vx *= friction; vy *= friction; object.x += vx; object.y += vy;
弹性动画的语法与缓动动画的语法是非常相似的,只不过缓动动画操作的是“速度”,而弹性动画操作的是“加速度”。
无摩擦力的弹性动画
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化数据 var ball = new Ball(0, cnv.height / 2); var targetX = cnv.width / 2; var spring = 0.02; var vx = 0; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var ax = (targetX - ball.x) * spring; vx += ax; ball.x += vx; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
有摩擦力的弹性动画
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(0, cnv.height / 2); var targetX = cnv.width / 2; var spring = 0.02; var vx = 0; var friction = 0.95; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var ax = (targetX - ball.x) * spring; vx += ax; vx *= friction; ball.x += vx; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
弹性动画的鼠标追随
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height / 2); var mouse = tools.getMouse(cnv); var targetX = cnv.width / 2; var spring = 0.02; var vx = 0; var vy = 0; var f = 0.95; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); var ax = (mouse.x - ball.x) * spring; var ay = (mouse.y - ball.y) * spring; vx += ax; vy += ay; vx *= f; vy *= f; ball.x += vx; ball.y += vy; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
无重力绳球运动
在弹性动画的鼠标追随的基础上,加一条连线即可
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height / 2); var mouse = tools.getMouse(cnv); var targetX = cnv.width / 2; var spring = 0.02; var vx = 0; var vy = 0; var friction = 0.95; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); //加入弹性动画 var ax = (mouse.x - ball.x) * spring; var ay = (mouse.y - ball.y) * spring; vx += ax; vy += ay; vx *= friction; vy *= friction; ball.x += vx; ball.y += vy; ball.fill(cxt); //将鼠标以及小球中心连接成一条直线 cxt.beginPath(); cxt.moveTo(ball.x, ball.y); cxt.lineTo(mouse.x, mouse.y); cxt.stroke(); cxt.closePath(); })(); } </script> </head> <body> <canvas id="canvas" width="270" height="180" style="border:1px solid silver;"></canvas> </body> </html>
有重力绳球运动(类似悠悠球)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script src="js/ball.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var ball = new Ball(cnv.width / 2, cnv.height / 2); var mouse = tools.getMouse(cnv); var targetX = cnv.width / 2; var spring = 0.02; var vx = 0; var vy = 0; var friction = 0.95; //定义重力 var gravity = 1; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); //加入弹性动画 var ax = (mouse.x - ball.x) * spring; var ay = (mouse.y - ball.y) * spring; vx += ax; vy += ay; //加入重力影响 vy += gravity; vx *= friction; vy *= friction; ball.x += vx; ball.y += vy; ball.fill(cxt); //将鼠标以及小球中心连接成一条直线 cxt.beginPath(); cxt.moveTo(ball.x, ball.y); cxt.lineTo(mouse.x, mouse.y); cxt.stroke(); cxt.closePath(); })(); } </script> </head> <body> <canvas id="canvas" width="270" height="180" style="border:1px solid silver;"></canvas> </body> </html>