9、摩擦力
? ? 摩擦力是與速度向量相反的力,模擬摩擦力時(shí),沿著速度向量的方向減去與摩擦力相等的大小。這里注意的一點(diǎn),不能分別在 x、y 軸上減小速度向量,因?yàn)槿绻矬w正沿著某個(gè)角度運(yùn)動(dòng),就會(huì)出現(xiàn)物體在某條軸上的速度降為零,而繼續(xù)在另一條軸上運(yùn)動(dòng)的奇怪現(xiàn)場(chǎng)。
?
1、將 vx 與 vy 平方后求和,再開(kāi)平方;再通過(guò)計(jì)算 Math.atan2(vy, vx) 獲得角度:
let speed = Math.sqrt(vx * vx + vy * vy); let angle = Math.atan2(vy, vx);2、從速度中減去摩擦力大小,判斷速度不能為負(fù)值,否則會(huì)逆轉(zhuǎn)速度向量。如果摩擦力大于速度,則速度變?yōu)榱?#xff1a;
if(speed > friction) {speed -= friction; } else {speed = 0; }3、通過(guò)正余弦函數(shù)將角速度轉(zhuǎn)回 vx、vy 的格式:
vx = speed * Math.cos(angle); vy = speed * Math.sin(angle);?
完整代碼如下:
<!DOCTYPE html> <html> <head><meta charset="utf-8"><meta name="viewport" content="initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,width=device-width"><title></title><style>*{margin: 0;padding: 0}body {background-color: #eee}canvas {background-color: #fff}</style> </head> <body><canvas id="canvas" width="600" height="400">Your browser does not support HTML5 Canvas.</canvas><script>(function(){window.addEventListener("load", eventWindowLoaded, false);function eventWindowLoaded(){canvasApp();}function canvasSupport(e){return !!e.getContext;}function canvasApp(){let canvas = document.getElementById("canvas");if(!canvasSupport(canvas)){return ;}// startlet context = canvas.getContext("2d");drawScreen(canvas, context);}// write your codesfunction drawScreen(canvas, context){let ball = new Ball();let vx = Math.random() * 10 - 5,vy = Math.random() * 10 - 5;let friction = 0.1;let speed = Math.sqrt(vx * vx + vy * vy);let angle = Math.atan2(vy, vx);ball.x = canvas.width / 2;ball.y = canvas.height / 2;(function drawFrame() {window.requestAnimationFrame(drawFrame, canvas);context.clearRect(0, 0, canvas.width, canvas.height);if (speed > friction) {speed -= friction} else {speed = 0;}vx = speed * Math.cos(angle);vy = speed * Math.sin(angle);ball.x += vx;ball.y += vy;ball.draw(context);} ())}})();</script><script>function Ball(radius, color) {if (radius === undefined) {radius = 40;}if (color === undefined) {color = "#ff0000";}this.x = 0;this.y = 0;this.color = color;this.radius = radius;}Ball.prototype.draw = function(context) {context.save();context.translate(this.x, this.y);context.fillStyle = this.color;context.beginPath();context.arc(0, 0, this.radius, 0, 360 * Math.PI / 180, false);context.closePath();context.fill();context.restore();}</script> </body> </html>?
? ? 我們可以實(shí)現(xiàn)模擬摩擦力的一種簡(jiǎn)便方法,該方法只需兩行簡(jiǎn)單的乘法組成。將 x、y 軸上的速度向量乘以一個(gè)百分?jǐn)?shù)即可,一個(gè)接近 0.9 的系數(shù)就能夠很好地模擬出摩擦力的效果。
?? ?這樣,在每一幀中,vx 和 vy 的值都會(huì)降為上一幀中對(duì)應(yīng)值的 80%或90%。理論上,速度向量會(huì)無(wú)限接近零,而永遠(yuǎn)不會(huì)等于零。不過(guò),計(jì)算機(jī)在表達(dá)小數(shù)時(shí)只會(huì)精確到某個(gè)特定的精度,所以最終結(jié)果也會(huì)變?yōu)榱恪?/strong>
? ? 這一方法的好處是速度向量永遠(yuǎn)不會(huì)變?yōu)樨?fù)數(shù)。可以比較 vx 與一個(gè)指定的較小的值從而節(jié)省一些不必要的計(jì)算。
? ??
if (Math.abs(vx) > 0.001) {vx *= friction;ball.x += vx; }if (Math.abs(vy) > 0.001) {vy *= friction;ball.y += vy; }?
完整代碼如下:
<!DOCTYPE html> <html> <head><meta charset="utf-8"><meta name="viewport" content="initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,width=device-width"><title></title><style>*{margin: 0;padding: 0}body {background-color: #eee}canvas {background-color: #fff}</style> </head> <body><canvas id="canvas" width="600" height="400">Your browser does not support HTML5 Canvas.</canvas><script>(function(){window.addEventListener("load", eventWindowLoaded, false);function eventWindowLoaded(){canvasApp();}function canvasSupport(e){return !!e.getContext;}function canvasApp(){let canvas = document.getElementById("canvas");if(!canvasSupport(canvas)){return ;}// startlet context = canvas.getContext("2d");drawScreen(canvas, context);}// write your codesfunction drawScreen(canvas, context){let ball = new Ball();let vx = Math.random() * 10 - 5,vy = Math.random() * 10 - 5;let friction = 0.95;ball.x = canvas.width / 2;ball.y = canvas.height / 2;(function drawFrame() {window.requestAnimationFrame(drawFrame, canvas);context.clearRect(0, 0, canvas.width, canvas.height);if (Math.abs(vx) > 0.01) {vx *= friction;ball.x += vx;}if (Math.abs(vy) > 0.01) {vy *= friction;ball.y += vy;}ball.draw(context);} ())}})();</script><script>function Ball(radius, color) {if (radius === undefined) {radius = 40;}if (color === undefined) {color = "#ff0000";}this.x = 0;this.y = 0;this.color = color;this.radius = radius;}Ball.prototype.draw = function(context) {context.save();context.translate(this.x, this.y);context.fillStyle = this.color;context.beginPath();context.arc(0, 0, this.radius, 0, 360 * Math.PI / 180, false);context.closePath();context.fill();context.restore();}</script> </body> </html>?
總結(jié)
- 上一篇: Qt中添加背景图片的方法
- 下一篇: 直流无刷电机的调试与代码开源(配套资源)