捕获物体

多边形以及不规则图形的捕获非常复杂,采用的方法是分离轴定理(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为trueif (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都为0var vx = 0, vy = 0;//添加mousedown事件cnv.addEventListener("mousedown", function () {//判断鼠标点击是否落在小球上if (ball.checkMouse(mouse)) {//鼠标按下小球时,isMouseDown设置为trueisMouseDown = true;//鼠标按下小球时,将当前鼠标位置赋值给oldX和oldYoldX = 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设置为falseisMouseDown = 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都为0var vx = 0, vy = 0;//添加mousedown事件cnv.addEventListener("mousedown", function () {//判断鼠标点击是否落在小球上if (ball.checkMouse(mouse)) {//鼠标按下小球时,isMouseDown设置为trueisMouseDown = true;//鼠标按下小球时,将当前鼠标位置赋值给oldX和oldYoldX = 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设置为falseisMouseDown = 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都为0var vx = 0, vy = 0;//加入重力和反弹消耗var gravity = 1.5;var bounce = -0.8;cnv.addEventListener("mousedown", function () {//判断鼠标点击是否落在小球上if (ball.checkMouse(mouse)) {//鼠标按下小球时,isMouseDown设置为trueisMouseDown = true;//鼠标按下小球时,将当前鼠标位置赋值给oldX和oldYoldX = 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设置为falseisMouseDown = 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>

canvas系列教程07 ——捕获、拖拽、抛掷、缓动动画、弹性动画相关推荐

  1. 【微信小程序-原生开发】实用教程20 - 生成海报(实战范例为生成活动海报,内含生成指定页面的小程序二维码,保存图片到手机,canvas 系列教程)

    可在系列教程的基础上继续开发,也可以单独使用 [微信小程序-原生开发]系列教程 效果预览 代码实现 点击触发生成海报 在活动详情页,指定点击某图标/按钮,触发跳转到生成海报的页面 pages\comp ...

  2. [js高手之路] html5 canvas系列教程 - 线条样式(lineWidth,lineCap,lineJoin,setLineDash)

    上文,写完弧度与贝塞尔曲线[js高手之路] html5 canvas系列教程 - arcTo(弧度与二次,三次贝塞尔曲线以及在线工具),本文主要是关于线条的样式设置 lineWidth: 设置线条的宽 ...

  3. [js高手之路] html5 canvas系列教程 - 掌握画直线图形的常用API

    我们接着上文[js高手之路] html5 canvas系列教程 - 认识canvas以及基本使用方法继续. 一.直线的绘制 cxt.moveTo( x1, y1 ): 将画笔移动到x1, y1这个点 ...

  4. canvas图形放大缩小鼠标拖拽

    canvas图形放大缩小鼠标拖拽 在网上找的都是放大缩小,或者鼠标拖拽,没有两者都满足的 一开始我天真的以为两个合并就可以了,但其实当鼠标松开和点击的时候,坐标原点是会变的,就是每次拖拽都是清除之前, ...

  5. HTML弧度文本,[js高手之路] html5 canvas系列教程 - 文本样式(strokeText,fillText,measureText,textAlign,textBaseline)...

    canvas提供两种输出文本的方式: strokeText:描边文本 fillText:填充文本 fillStyle配合fillText使用,strokeStyle配合strokeText使用 str ...

  6. 前端画圆弧html弧线的像素,[js高手之路] html5 canvas系列教程 - arc绘制曲线图形(曲线,弧线,圆形)...

    arc:画弧度 cxt.arc( x, y, 半径, 开始角度,结束角度,是否逆时针 ); x, y: 为弧度的中心横坐标和纵坐标,如果这是画一个圆.那么x,y就是圆的圆心. 开始角度与结束角度都是以 ...

  7. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二)让物体动起来②

    第二种方法,CompositionTarget动画,官方描述为:CompositionTarget对象可以根据每个帧回调来创建自定义动画.其实直接点,CompositionTarget创建的动画是基于 ...

  8. HTML5开发 页游/手游动画及游戏系列教程(Game Tutorial):(一)物体动起来吧

    前言 所谓高手,也就是熟悉别人制定的游戏规则.并且能在规则内跳舞的人.(随笔,转自王哲的博客) 09年的时候,为了跳槽和兴趣,转型游戏行业,因此去网上找资料学习各种游戏相关的资料.也是缘分吧,看到了深 ...

  9. javascript动画系列第一篇——模拟拖拽

    前面的话 从本文开始,介绍javascript动画系列.javascript本身是具有原生拖放功能的,但是由于兼容性问题,以及功能实现的方式,用的不是很广泛.javascript动画广泛使用的还是模拟 ...

最新文章

  1. 【Android 逆向】Android 权限 ( adb 降权相关的属性 | ro.secure 属性 | ro.debuggable 属性 | service.adb.root 属性 )
  2. Queue 队列的用法
  3. iceworks-cli构建模块说明
  4. SAP CRM和Cloud for Customer的organization unit
  5. linux下cabal安装教程,Centos 7 安装shellcheck
  6. Confluence 6 匿名用户
  7. unity3d 取锚点位置_周三手机课实时共享位置,方便朋友找到见面地点
  8. 第十一届蓝桥杯python试题_Python描述 第十一届蓝桥杯省赛第一场 试题 I: 字符串编码...
  9. 前阿里财务人告诉你:抛弃Excel,原来报表竟然还能这么快
  10. python标准库os.path中_Python零基础入门学习19:常用标准库之os.path子库
  11. 1、检测是用那个浏览器打开的
  12. PHP微信公众号开发常用功能
  13. ECSHOP首页调用文章内的缩略图
  14. mysql 占比函数_MYSQL 八大优化方案
  15. java面试宝典app_Java面试宝典
  16. Python爬虫新手入门教学(三):爬取链家二手房数据
  17. 【深度学习】CRNN 文字识别端对端模型 CTC损失
  18. SteamAchievementManager刷steam游戏成就新手教程
  19. 创建一个简单OIO模式的socket服务端
  20. 房间类游戏后台框架(一)—介绍

热门文章

  1. GloVe 教程之实战入门+python gensim 词向量
  2. springcloud-ribbon重试机制详解
  3. 计算机理论与实践相结合,初中信息技术教学如何实现理论和实践的结合
  4. 扒一扒编程语言排行榜
  5. 高完整性系统工程(一): Safety Engineering, HAZOP Fault Tree Analysis
  6. 台式计算机不用待机还是关机好,电脑长时间待机的坏处 不关机对电脑的损害大吗...
  7. 计算机系统结构实践教程(第二版)张晨曦
  8. 关于简单的三个数降序
  9. 计算机毕业设计Python+uniapp考研闯关微信小程序(小程序+源码+LW)
  10. 分布式接口幂等性、分布式限流总结整理