介绍
要在 javascript
中实现一个按照贝塞尔曲线运动的小球,关键是要掌握贝塞尔公式的基本原理和实现方式,以及使用 javascript
处理动画和物理运算。
以下是实现的核心步骤:
构建
html
。绘制小球。
实现贝塞尔曲线路径。
实现动画循环。
接下来,我们将详细介绍这些步骤。
构建 html
首先,我们需要构建一个简单的 html
文件,用于绘制我们的动画。
<!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>canvas</title> <style> body { font-family: arial, sans-serif; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; } canvas { border-radius: 15px; background-color: #ffffff; } </style> </head> <body> <canvas id="demo-canvas" width="800" height="600"></canvas> <script> </script> </body> </html>
代码足够简单就行,我们只需要一个 canvas
元素即可。
绘制小球
接下来,我们需要在 javascript
中获取 canvas
元素,并使用 canvas
的 api
来绘制一个小球。
const canvas = document.getelementbyid('demo-canvas'); const ctx = canvas.getcontext('2d'); const ball = { radius: 20, color: '#ff0000', }; function drawball(x, y) { ctx.beginpath(); ctx.arc(x, y, ball.radius, 0, math.pi * 2); ctx.fillstyle = ball.color; ctx.fill(); }
由于我们需要让小球沿着贝塞尔曲线运动,所以在调用 drawball
函数时,需要传递最新的坐标位置,因此我们需要给 drawball
传递 x
和 y
两个参数。
贝塞尔公式
关于贝塞尔公式,网上讲解的文章博客多如牛毛,这里就不赘述了,直接上结论。
实现贝塞尔曲线路径
接下来,我们来实现 nn 阶贝塞尔曲线路径,并获取曲线上的点。
function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); } function binomialcoefficient(n, i) { let res = factorial(n) / (factorial(i) * factorial(n - i)); return math.floor(res); } function bernsteinpolynomial(n, i, t) { return binomialcoefficient(n, i) * math.pow(1 - t, n - i) * math.pow(t, i); } function getpointonbeziercurve(t, arr) { let x = 0; let y = 0; for (let i = 0; i < arr.length; i++) { let bernstein = bernsteinpolynomial(arr.length - 1, i, t); x += bernstein * arr[i].x; y += bernstein * arr[i].y; } return { x, y }; }
其中,getpointonbeziercurve
函数第一个参数 t
取值范围是 0到 1,该参数决定了曲线上的点的位置。第二个参数 arr
是控制点数组,该参数决定了贝塞尔曲线的阶数(即 n),例如:arr
传入的是 [p0, p1, p2, p3]
,那么对应的贝塞尔曲线的阶数 n就等于 3。
实现小球运动
接下来,我们需要实现小球沿着贝塞尔曲线运动,即不断更新小球的坐标位置,并调用 drawball
函数来绘制小球。
let t = 0; const points = [ { x: 100, y: 50 }, { x: 200, y: 300 }, { x: 700, y: -20 }, { x: 500, y: 500 }, ]; function animate() { ctx.clearrect(0, 0, canvas.width, canvas.height); const point = getpointonbeziercurve(t, points); drawball(point.x, point.y); t += 0.01; if (t > 1) { settimeout(() => { t = 0; requestanimationframe(animate); }, 1000); } else { requestanimationframe(animate); } } animate();
展示
完整代码
<!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>canvas</title> <style> body { font-family: arial, sans-serif; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; } canvas { border-radius: 15px; background-color: #ffffff; } </style> </head> <body> <canvas id="demo-canvas" width="800" height="600"></canvas> <script> const canvas = document.getelementbyid('demo-canvas'); const ctx = canvas.getcontext('2d'); const ball = { radius: 20, color: '#ff0000', }; function drawball(x, y) { ctx.beginpath(); ctx.arc(x, y, ball.radius, 0, math.pi * 2); ctx.fillstyle = ball.color; ctx.fill(); } function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); } function binomialcoefficient(n, i) { let res = factorial(n) / (factorial(i) * factorial(n - i)); return math.floor(res); } function bernsteinpolynomial(n, i, t) { return binomialcoefficient(n, i) * math.pow(1 - t, n - i) * math.pow(t, i); } function getpointonbeziercurve(t, arr) { let x = 0; let y = 0; for (let i = 0; i < arr.length; i++) { let bernstein = bernsteinpolynomial(arr.length - 1, i, t); x += bernstein * arr[i].x; y += bernstein * arr[i].y; } return { x, y }; } let t = 0; const points = [ { x: 100, y: 50 }, { x: 200, y: 300 }, { x: 700, y: -20 }, { x: 500, y: 500 }, ]; function animate() { ctx.clearrect(0, 0, canvas.width, canvas.height); const point = getpointonbeziercurve(t, points); drawball(point.x, point.y); t += 0.01; if (t > 1) { settimeout(() => { t = 0; requestanimationframe(animate); }, 1000); } else { requestanimationframe(animate); } } animate(); </script> </body> </html>
扩展
在此基础上,我们可以添加更多的小球,让它们沿着随机化的贝塞尔曲线运动,从而形成更加复杂的动画效果。
<!doctype html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>canvas</title> <style> body { font-family: arial, sans-serif; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; } canvas { border-radius: 15px; background-color: #ffffff; } </style> </head> <body> <canvas id="canvas" width="800" height="600"></canvas> <script> const canvas = document.getelementbyid('canvas'); const ctx = canvas.getcontext('2d'); function getrandompoints() { const randomnumber = (min, max) => { const randombuffer = new uint32array(1); window.crypto.getrandomvalues(randombuffer); const number = randombuffer[0] / (0xffffffff + 1); return math.floor(number * (max - min) + min); } let points = [ { x: parseint(canvas.width / 5), y: parseint(canvas.height / 2), }, { x: parseint(canvas.width / 5 * 4), y: parseint(canvas.height / 2), }, ]; const count = randomnumber(2, 5); const minx = -100, maxx = 900, miny = -100, maxy = 700; for (let i = 0; i < count; i++) { points.splice(i + 1, 0, { x: randomnumber(minx, maxx), y: randomnumber(miny, maxy) }); } return points; } function factorial(n) { return n <= 1 ? 1 : n * factorial(n - 1); } function binomialcoefficient(n, i) { let res = factorial(n) / (factorial(i) * factorial(n - i)); return math.floor(res); } function bernsteinpolynomial(n, i, t) { return binomialcoefficient(n, i) * math.pow(1 - t, n - i) * math.pow(t, i); } function getpointonbeziercurve(t, arr) { let x = 0; let y = 0; for (let i = 0; i < arr.length; i++) { let bernstein = bernsteinpolynomial(arr.length - 1, i, t); x += bernstein * arr[i].x; y += bernstein * arr[i].y; } return { x, y }; } const radius = 20; const colors = ['green', 'purple', 'orange']; let t = 0.0; let points = [getrandompoints(), getrandompoints(), getrandompoints()]; function animate() { ctx.clearrect(0, 0, canvas.width, canvas.height); for (let i = 0; i < points.length; i++) { let pos = getpointonbeziercurve(t, points[i]); ctx.beginpath(); ctx.arc(pos.x, pos.y, radius, 0, 2 * math.pi); ctx.fillstyle = colors[i]; ctx.fill(); } t += 0.01; if (t > 1) { settimeout(() => { t = 0; points = [getrandompoints(), getrandompoints(), getrandompoints()]; requestanimationframe(animate); }, 1000); } else { requestanimationframe(animate); } } animate(); </script> </body> </html>
展示
以上就是使用javascript实现小球按照贝塞尔曲线运动的详细内容,更多关于javascript小球曲线运动的资料请关注代码网其它相关文章!
发表评论