亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

使用JavaScript實(shí)現(xiàn)小球按照貝塞爾曲線運(yùn)動(dòng)

 更新時(shí)間:2024年10月30日 10:37:04   作者:xvch  
要在 JavaScript 中實(shí)現(xiàn)一個(gè)按照貝塞爾曲線運(yùn)動(dòng)的小球,關(guān)鍵是要掌握貝塞爾公式的基本原理和實(shí)現(xiàn)方式,以及使用 JavaScript 處理動(dòng)畫和物理運(yùn)算,感興趣的小伙伴跟著小編一起來看看吧

介紹

要在 JavaScript 中實(shí)現(xiàn)一個(gè)按照貝塞爾曲線運(yùn)動(dòng)的小球,關(guān)鍵是要掌握貝塞爾公式的基本原理和實(shí)現(xiàn)方式,以及使用 JavaScript 處理動(dòng)畫和物理運(yùn)算。

以下是實(shí)現(xiàn)的核心步驟:

  • 構(gòu)建 HTML。

  • 繪制小球。

  • 實(shí)現(xiàn)貝塞爾曲線路徑。

  • 實(shí)現(xiàn)動(dòng)畫循環(huán)。

接下來,我們將詳細(xì)介紹這些步驟。

構(gòu)建 HTML

首先,我們需要構(gòu)建一個(gè)簡單的 HTML 文件,用于繪制我們的動(dòng)畫。

<!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>

代碼足夠簡單就行,我們只需要一個(gè) canvas 元素即可。

繪制小球

接下來,我們需要在 JavaScript 中獲取 canvas 元素,并使用 canvas 的 API 來繪制一個(gè)小球。

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();
}

由于我們需要讓小球沿著貝塞爾曲線運(yùn)動(dòng),所以在調(diào)用 drawBall 函數(shù)時(shí),需要傳遞最新的坐標(biāo)位置,因此我們需要給 drawBall 傳遞 x 和 y 兩個(gè)參數(shù)。

貝塞爾公式

關(guān)于貝塞爾公式,網(wǎng)上講解的文章博客多如牛毛,這里就不贅述了,直接上結(jié)論。

實(shí)現(xiàn)貝塞爾曲線路徑

接下來,我們來實(shí)現(xiàn) NN 階貝塞爾曲線路徑,并獲取曲線上的點(diǎn)。

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 函數(shù)第一個(gè)參數(shù) t 取值范圍是 0到 1,該參數(shù)決定了曲線上的點(diǎn)的位置。第二個(gè)參數(shù) arr 是控制點(diǎn)數(shù)組,該參數(shù)決定了貝塞爾曲線的階數(shù)(即 N),例如:arr 傳入的是 [p0, p1, p2, p3],那么對(duì)應(yīng)的貝塞爾曲線的階數(shù) N就等于 3。

實(shí)現(xiàn)小球運(yùn)動(dòng)

接下來,我們需要實(shí)現(xiàn)小球沿著貝塞爾曲線運(yùn)動(dòng),即不斷更新小球的坐標(biāo)位置,并調(diào)用 drawBall 函數(shù)來繪制小球。

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>

擴(kuò)展

在此基礎(chǔ)上,我們可以添加更多的小球,讓它們沿著隨機(jī)化的貝塞爾曲線運(yùn)動(dòng),從而形成更加復(fù)雜的動(dòng)畫效果。

<!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實(shí)現(xiàn)小球按照貝塞爾曲線運(yùn)動(dòng)的詳細(xì)內(nèi)容,更多關(guān)于JavaScript小球曲線運(yùn)動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • DIV任意拖動(dòng)的問題

    DIV任意拖動(dòng)的問題

    DIV任意拖動(dòng)的問題...
    2006-07-07
  • 微信JSSDK調(diào)用微信掃一掃功能的方法

    微信JSSDK調(diào)用微信掃一掃功能的方法

    這篇文章主要為大家詳細(xì)介紹了微信JSSDK調(diào)用微信掃一掃功能的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • 詳解JS中定時(shí)器setInterval和setTImeout的this指向問題

    詳解JS中定時(shí)器setInterval和setTImeout的this指向問題

    在js中setTimeout和setInterval都是用來定時(shí)的一個(gè)功能,下面這篇文章主要給介紹了JS中setInterval和setTImeout的this指向問題,文中通過示例介紹的很詳細(xì),有需要的朋友可以參考借鑒,一起來看看吧。
    2017-01-01
  • vscode?對(duì)?typescript代碼調(diào)試的步驟

    vscode?對(duì)?typescript代碼調(diào)試的步驟

    在VS?Code中,要對(duì)?TypeScript代碼進(jìn)行調(diào)試,需要先編譯?TypeScript?代碼為JavaScript代碼,這篇文章主要介紹了vscode對(duì)typescript代碼調(diào)試的方法,需要的朋友可以參考下
    2023-03-03
  • Javascript 生成指定范圍數(shù)值隨機(jī)數(shù)

    Javascript 生成指定范圍數(shù)值隨機(jī)數(shù)

    查手冊(cè)后才知道, 介紹的信息少得可憐吶, 沒有介紹生成 m-n 范圍的隨機(jī)數(shù)..., 就只是給你一個(gè) Math.random() 了事.
    2009-01-01
  • 使用element-ui的upload組件上傳代碼包時(shí)遇到的問題小結(jié)

    使用element-ui的upload組件上傳代碼包時(shí)遇到的問題小結(jié)

    這篇文章主要介紹了使用element-ui的upload組件上傳代碼包時(shí)遇到的問題及總結(jié),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • 探究Javascript模板引擎mustache.js使用方法

    探究Javascript模板引擎mustache.js使用方法

    這篇文章主要為大家介紹了Javascript模板引擎mustache.js使用方法,mustache.js是一個(gè)簡單強(qiáng)大的Javascript模板引擎,使用它可以簡化在js代碼中的html編寫,壓縮后只有9KB,非常值得在項(xiàng)目中使用,感興趣的小伙伴們可以參考一下
    2016-01-01
  • 解決Extjs下拉框不顯示的問題

    解決Extjs下拉框不顯示的問題

    一個(gè)父容器也是window的window下的comboBox在頁面中點(diǎn)擊無效,但是在控制臺(tái)中查看它的store卻是有值的,問題在于沒有顯示。下面小編給大家分享Extjs下拉框不顯示的問題,需要的的朋友參考下吧
    2017-06-06
  • JavaScrip如何安全使用Payment Request API詳解

    JavaScrip如何安全使用Payment Request API詳解

    這篇文章主要為大家介紹了JavaScrip如何安全使用Payment Request API詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • JS定時(shí)器如何實(shí)現(xiàn)提交成功提示功能

    JS定時(shí)器如何實(shí)現(xiàn)提交成功提示功能

    這篇文章主要介紹了JS定時(shí)器如何實(shí)現(xiàn)提交成功提示功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評(píng)論