交互
实时获取鼠标在Canvas中的坐标
//将tools定义为window对象的属性,该属性的值是一个对象 window.tools = {}; //获取鼠标位置 window.tools.getMouse = function (element) { //定义一个mouse的对象 var mouse = { x: 0, y: 0 }; //为传入的元素添加mousemove事件 addEvent(element, "mousemove", function (e) { var x, y; //在IE中,event对象是作为window对象的一个属性存在 var e = e || window.event; //获取鼠标当前位置,并作兼容处理 //兼容Firefox、chrome、IE9及以上 if (e.pageX || e.pageY) { x = e.pageX; y = e.pageY; } //兼容IE8及以下,以及混杂模式下的Chrome和Safari else { x = e.clientX + document.body.scrollLeft || document.documentElement.scrollLeft; y = e.clientY + document.body.scrollTop || document.documentElement.scrollTop; } //将当前的坐标值减去canvas元素的偏移位置,则x、y为鼠标在canvas中的相对坐标 x -= element.offsetLeft; y -= element.offsetTop; mouse.x = x; mouse.y = y; }) //返回值为mouse对象 return mouse; }
var txt = $$("txt"); var mouse = tools.getMouse(cnv); cnv.addEventListener("mousemove", function () { txt.innerHTML = "鼠标当前坐标为:(" + mouse.x + "," + mouse.y + ")"; }, false);
通过键盘控制图形移动
封装【获取键盘控制方向】的函数,写在 js/tools.js 中
//获取键盘控制方向 window.tools.getKey = function () { var key = {}; window.addEventListener("keydown", function (e) { if (e.keyCode == 38 || e.keyCode == 87) { key.direction = "up"; } else if (e.keyCode == 39 || e.keyCode == 68) { key.direction = "right"; } else if (e.keyCode == 40 || e.keyCode == 83) { key.direction = "down"; } else if (e.keyCode == 37 || e.keyCode == 65) { key.direction = "left"; } else { key.direction = ""; } }, false); return key; }
按键 |
|
W(上) |
87 |
S(下) |
83 |
A(左) |
65 |
D(右) |
68 |
↑ |
38 |
↓ |
40 |
← |
37 |
→ |
39 |
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化一个圆形 drawBall(cnv.width / 2, cnv.height / 2); //初始化变量 var x = 100; var y = 75; //获取按键方向 var key = tools.getKey(); //添加鼠标按下事件 window.addEventListener("keydown", function (e) { //清除整个Canvas,以便重绘新的圆形 cxt.clearRect(0, 0, cnv.width, cnv.height); //根据key.direction的值,判断小球移动方向 switch (key.direction) { case "up": y -= 2; drawBall(x, y); break; case "down": y += 2; drawBall(x, y); break; case "left": x -= 2; drawBall(x, y); break; case "right": x += 2; drawBall(x, y); break; //default值 default: drawBall(x, y); } }, false); //定义绘制小球的函数 function drawBall(x, y) { cxt.beginPath(); cxt.arc(x, y, 20, 0, 360 * Math.PI / 180, true); cxt.closePath(); cxt.fillStyle = "#6699FF"; cxt.fill(); } } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
按键盘上的方向键控制图形移动
switch语句,一定要加入default值的表达式,不然如果按下的是其他按键,小球就会消失了(没有重绘)。
switch (key.direction) { case "up": …… case "down": …… case "left": …… case "right": …… default: …… }
动画
原理:通过 requestAnimationFrame()方法,循环清除画布,并重绘动画后的新图形。
requestAnimationFrame() 与 setInterval() 功能类似,但 setInterval() 存在性能问题,且需手动设置循环间隔时间,而requestAnimationFrame() 无需手动设置,它会自动根据浏览器绘制的帧率进行调整。
重要提醒:
(1)对于需要不断改变的变量,一般在动画循环之前先定义。
(2)对于需要不断改变的变量,一般在动画循环中图形绘制之后才递增或递减。
开发技巧:复杂的动画效果从x轴和y轴两个方向来考虑,实现的思路会变得非常清晰。
封装【requestAnimationFrame()方法兼容代码】的函数,写在 js/tools.js 中
window.requestAnimationFrame = ( window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function (callback) { return window.setTimeout(callback, 1000/60); } );
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //初始化变量,也就是初始化圆的x轴坐标为0 var x = 0; //动画循环 (function frame() { window.requestAnimationFrame(frame); //每次动画循环都先清空画布,再重绘新的图形 cxt.clearRect(0, 0, cnv.width, cnv.height); //绘制圆 cxt.beginPath(); cxt.arc(x, 70, 20, 0, 360 * Math.PI / 180, true); cxt.closePath(); cxt.fillStyle = "#6699FF"; cxt.fill(); //变量递增 x += 2; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
物理动画
物理动画,即模拟现实世界的一种动画效果。在物理动画中,物体会遵循牛顿运动定律,如射击游戏中打出去的炮弹会随着重力而降落。
追随鼠标旋转
原理:每次鼠标移动的时候,计算鼠标当前位置与箭头中心的夹角,然后把这个夹角作为箭头旋转的角度,重绘箭头即可。
封装【绘制箭头】的函数,写在 js/arrow.js 中
function Arrow(x,y,color,angle) { //箭头中心x坐标,默认值为0 this.x = x || 0; //箭头中心y坐标,默认值为0 this.y = y || 0; //颜色,默认值为"#FF0099" this.color = color || "#FF0099"; //旋转角度,默认值为0 this.angle = angle || 0; } Arrow.prototype = { stroke: function (cxt) { cxt.save(); cxt.translate(this.x, this.y); cxt.rotate(this.angle); cxt.strokeStyle = this.color; cxt.beginPath(); cxt.moveTo(-20, -10); cxt.lineTo(0, -10); cxt.lineTo(0, -20); cxt.lineTo(20, 0); cxt.lineTo(0, 20); cxt.lineTo(0, 10); cxt.lineTo(-20, 10); cxt.closePath(); cxt.stroke(); cxt.restore(); }, fill: function (cxt) { cxt.save(); cxt.translate(this.x, this.y); cxt.rotate(this.angle); cxt.fillStyle = this.color; cxt.beginPath(); cxt.moveTo(-20, -10); cxt.lineTo(0, -10); cxt.lineTo(0, -20); cxt.lineTo(20, 0); cxt.lineTo(0, 20); cxt.lineTo(0, 10); cxt.lineTo(-20, 10); cxt.closePath(); cxt.fill(); cxt.restore(); } };
<!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/arrow.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //实例化一个箭头,中点坐标为画布中心坐标 var arrow = new Arrow(cnv.width / 2, cnv.height / 2); //获取鼠标坐标 var mouse = tools.getMouse(cnv); (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); var dx = mouse.x - cnv.width / 2; var dy = mouse.y - cnv.height / 2; //使用Math.atan2()方法计算出鼠标与箭头中心的夹角 arrow.angle = Math.atan2(dy, dx); arrow.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
实时计算两点间的距离
dx = x2 - x1; dy = y2 - y1; distance = Math.sqrt(dx*dx + dy*dy);
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/tools.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); var text = document.getElementById("p1"); var x = cnv.width / 2; var y = cnv.height / 2; var mouse = tools.getMouse(cnv); (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); cxt.save(); cxt.beginPath(); cxt.moveTo(x, y); //mouse.x表示鼠标的x轴坐标,mouse.y表示鼠标的y轴坐标 cxt.lineTo(mouse.x, mouse.y); cxt.closePath(); cxt.strokeStyle = "red"; cxt.stroke(); cxt.restore(); var dx = mouse.x - x; var dy = mouse.y - y; var distance = Math.sqrt(dx * dx + dy * dy); text.innerText = "鼠标与中点距离为:" + distance; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> <p id="p1"></p> </body> </html>
圆周运动
正圆运动
通过圆心坐标和角度,可以计算出圆周上任意一点的坐标
封装【绘制球】的函数,写在新建 js/ball.js 中
function Ball(x,y,radius,color) { //小球中心的x坐标,默认值为0 this.x = x || 0; //小球中心的y坐标,默认值为0 this.y = y || 0; //小球半径,默认值为12 this.radius = radius || 12; //小球颜色,默认值为"#6699FF" this.color = color || "#6699FF"; this.scaleX = 1; this.scaleY = 1; } Ball.prototype = { //绘制"描边"小球 stroke: function (cxt) { cxt.save(); cxt.scale(this.scaleX, this.scaleY); cxt.strokeStyle = this.color; cxt.beginPath(); cxt.arc(this.x, this.y, this.radius, 0, 360 * Math.PI / 180, false); cxt.closePath(); cxt.stroke(); cxt.restore(); }, //绘制"填充"小球 fill: function (cxt) { cxt.save(); cxt.translate(this.x, this.y); cxt.rotate(this.rotation); cxt.scale(this.scaleX, this.scaleY); cxt.fillStyle = this.color; cxt.beginPath(); cxt.arc(0, 0, this.radius, 0, 360 * Math.PI / 180, false); cxt.closePath(); cxt.fill(); cxt.restore(); } }
范例代码:
<!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"); //实例化一个小球,中心坐标为(100,25),半径、颜色都取默认值 var ball = new Ball(100, 25); var centerX = cnv.width / 2; var centerY = cnv.height / 2; var radius = 50; var angle = 0; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); //绘制圆形 cxt.beginPath(); cxt.arc(centerX, centerY, 50, 0, 360 * Math.PI / 180, false); cxt.closePath(); cxt.stroke(); //计算小球坐标 ball.x = centerX + Math.cos(angle) * radius; ball.y = centerY + Math.sin(angle) * radius; ball.fill(cxt); //角度递增 angle += 0.05; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
椭圆运动
x = centerX + Math.cos(angle)*radiusX; y = centerY + Math.sin(angle)*radiusY;
范例代码:
<!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(100, 25); var centerX = cnv.width / 2; var centerY = cnv.height / 2; var radiusX = 60; var radiusY = 40; var angle = 0; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); //计算小球坐标 ball.x = centerX + Math.cos(angle) * radiusX; ball.y = centerY + Math.sin(angle) * radiusY; ball.fill(cxt); //角度递增 angle += 0.05; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
左右摆动
x = centerX + Math.sin(angle) * range; angle += speed;
- (centerX,centerY)表示物体中心坐标
- angle表示角度(弧度制)
- range表示振幅
- speed表示角度改变的大小。
<!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 angle = 0; var range = 80; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x = cnv.width / 2 + Math.sin(angle) * range; ball.fill(cxt); //角度递增 angle += 0.05; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
上下波动前进
y = centerY + Math.sin(angle) * range; angle += speed;
- (centerX,centerY)表示物体中心坐标
- angle表示角度(弧度制)
- range表示振幅
- speed表示角度改变的大小。
<!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 angle = 0; var range = 40; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += 1; ball.y = cnv.height / 2 + Math.sin(angle) * range; ball.fill(cxt); //角度递增 angle += 0.05; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
放大缩小(脉冲)
scaleX = 1 + Math.sin(angle) * range; scaleY = 1 + Math.sin(angle) * range; angle += speed;
- scaleX表示物体x轴方向缩放的倍数
- scaleY表示物体y轴方向缩放的倍数
- angle表示角度(弧度制)
- range表示振幅
- speed表示角度改变的大小
<!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, 25); var range = 0.5; var angle = 0; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.scaleX = 1 + Math.sin(angle) * range; ball.scaleY = 1 + Math.sin(angle) * range; ball.fill(cxt); //角度递增 angle += 0.05; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
匀速直线运动
匀速直线运动——物体在一条直线上运动,并且物体在任何相等时间间隔内通过的位移是相等的。
匀速运动是一种加速度为0的运动。匀速运动只有一种,那就是:匀速直线运动。很多人以为“匀速圆周运动”也是匀速运动,其实这是错误的。事实上,匀速圆周运动准确来说应该是匀速率圆周运动或者匀角速度运动。它的加速度是不为0的,因此匀速圆周运动并不是匀速运动。
水平/垂直匀速直线运动
object.x + = vx; objectobject.x表示物体x轴坐标
- object.x表示物体x轴坐标
- object.y表示物体y轴坐标
- vx表示x轴方向的速度大小
- vy表示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轴速度为2,也就是每帧向正方向移动2px var vx = 2; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
任意方向的匀速直线运动
使用速度分解实现
vx = speed * Math.cos(angle * Math.PI/180); vy = speed * Math.sin(angle * Math.PI/180); object.x += vx; object.y += vy;
- object.x表示物体x轴坐标
- object.y表示物体y轴坐标
- vx表示x轴方向的速度大小
- vy表示y轴方向的速度大小
- speed表示任意方向的速度大小
- angle表示该速度的方向与x轴正方向的夹角
<!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(); var speed = 2; //速度方向与x轴正方向角度为30° var vx = speed * Math.cos(30 * Math.PI / 180); var vy = speed * Math.sin(30 * Math.PI / 180); (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); 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/arrow.js"></script> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //实例化一个箭头,箭头中心坐标为画布中心坐标 var arrow = new Arrow(cnv.width / 2, cnv.height / 2); var mouse = tools.getMouse(cnv); var speed = 1.5; var angle = 0; (function drawFrame() { window.requestAnimationFrame(drawFrame, cnv); cxt.clearRect(0, 0, cnv.width, cnv.height); //计算出鼠标与箭头中心之间的夹角 var dx = mouse.x - cnv.width / 2; var dy = mouse.y - cnv.height / 2; angle = Math.atan2(dy, dx); var vx = Math.cos(angle) * speed; var vy = Math.sin(angle) * speed; arrow.x += vx; arrow.y += vy; arrow.angle = angle; arrow.fill(cxt); })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
首先初始化速度(speed)和角度(angle),然后将鼠标当前坐标减去箭头的坐标,得到dx、dy,之后再使用Math.atan2()得到夹角度数,最后使用三角函数将速度分解为x和y两个方向的分速度。
加/减速直线运动
水平或垂直加/减速直线运动
加速运动,指的是方向相同、速度大小变化的运动。速度递增的是加速运动,速度递减的是减速运动。
加速度,指的是单位时间内速度改变的矢量。
vx += ax; vy += ay; object.x += vx; object.y += vy;
- (object.x,object.y) 为物体的坐标
- vx表示x轴方向的速度大小
- vy表示y轴方向的速度大小
- ax表示x轴方向加速度,ay表示y轴方向加速度。当ax大于0时,物体向右做匀加速运动;当ax小于0时,物体向左做匀加速运动;当ax等于0时,物体按原来速度运动。ay跟ax是一样的。
<!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 vx = 0; var ax = 0.2; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.fill(cxt); vx += ax; })(); } </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); //初始化x轴速度以及加速度 var vx = 8; var ax = -0.2; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.fill(cxt); vx += ax; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
由于小球最开始的时候在x轴上有一个正方向的初始速度(varvx=8;),因此小球一开始会向右运动。但是由于加速度为负值,所以小球一开始向右做的是匀减速运动。当速度减到0的时候,此时加速度却不为0,接下来小球会继续向左做匀加速运动。
任意方向加/减速直线运动
分解加速度即可
ax = a * Math.cos(angle * Math.PI/180); ay = a * Math.sin(angle * Math.PI/180); vx += ax; vy += ay; object.x += vx; object.y += vy;
- (object.x,object.y) 为物体的坐标
- vx表示x轴方向的速度大小
- vy表示y轴方向的速度大小
- ax表示x轴方向加速度
- ay表示y轴方向加速度。
- a表示任意方向的加速度大小
- angle表示该加速度的方向与x轴正方向的夹角
<!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(); var a = 0.2; //计算出x轴和y轴2个方向的加速度 var ax = a * Math.cos(30 * Math.PI / 180); var ay = a * Math.sin(30 * Math.PI / 180); var vx = 0; var vy = 0; (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.y += vy; ball.fill(cxt); vx += ax; vy += ay; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
重力
因地球引力引起的加速度,运动规律与加速运动相同。
vy += gravity; object.y += vy;
抛物线运动
在x轴方向做的是匀速运动,在y轴方向做的是减加速运动(受到重力影响)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script src="js/utils.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); var vx = 4; var vy = -5; var gravity = 0.2; (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.y += vy; ball.fill(cxt); //变量递增 vy += gravity; })(); } </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, 0); //y轴初始速度为0,重力加速度为0.2,反弹系数为-0.8 var vy = 0; var gravity = 0.2; var bounce = -0.8; (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.y += vy; //边界检测 if (ball.y > cnv.height - ball.radius) { ball.y = cnv.height - ball.radius; //速度反向并且减小 vy = vy * bounce; } ball.fill(cxt); vy += gravity; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
if(ball.y>cnv.height-ball.radius){}是一个边界检测,表示当“小球y轴坐标”大于“画布高度减去小球半径”时执行的操作。
小球碰到地面都会反弹,由于反弹会有速度损耗,并且小球y轴速度方向会变为反方向,因此需要乘以一个反弹系数bounce。反弹系数取值一般为-1.0~0之间的任意数。
- 反弹之后,速度方向变为相反方向了,所以反弹系数是负数呢
- 反弹之后,速度只会变小,所以反弹系数取值为-1.0~0之间任意数,而不能是-2、-3
前抛落地反弹
在水平方向上加个速度即可
<!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); var vx = 3; var vy = -6; var gravity = 0.2; var bounce = -0.75; (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.y += vy; //边界检测 if ((ball.y + ball.radius) > cnv.height) { ball.y = cnv.height - ball.radius; vy = vy * bounce; } ball.fill(cxt); //变量递增 vy += gravity; })(); } </script> </head> <body> <canvas id="canvas" width="300" height="150" style="border:1px solid silver;"></canvas> </body> </html>
摩擦力
摩擦力,指阻碍物体相对运动的力。其中摩擦力的方向与物体相对运动的方向相反。摩擦力只会改变速度的大小而不会改变它的方向。换句话说,摩擦力只能将物体的速度降至0,但它无法让物体掉头往相反的方向移动。
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); //初始化x轴方向速度为2,摩擦系数为0.95 var vx = 8; var friction = 0.95; (function frame() { window.requestAnimationFrame(frame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.fill(cxt); //变量改变 vx *= friction; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>
- 任意方向运动遇到摩擦力
当物体沿任意方向运动时,如果我们加入摩擦力因素,那么每次都是先把该方向的速度分解为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(); var speed = 8; var vx = speed * Math.cos(30 * Math.PI / 180); var vy = speed * Math.sin(30 * Math.PI / 180); var friction = 0.95; (function drawFrame() { window.requestAnimationFrame(drawFrame); cxt.clearRect(0, 0, cnv.width, cnv.height); ball.x += vx; ball.y += vy; ball.fill(cxt); //变量改变 vx *= friction; vy *= friction; })(); } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px solid silver;"></canvas> </body> </html>