使用canvas實(shí)現(xiàn)有趣的彈簧效果
先上效果
兩個(gè)小球之間有一根彈簧,這里有一條線表示,其中左球固定,在點(diǎn)擊開始后,右球開始做自由落體

思路
先做受力分析

經(jīng)過受力分析可以發(fā)現(xiàn),整個(gè)系統(tǒng)一共有三個(gè)力在起作用,我們分別把他們求出來并合成為一個(gè)力,然后這個(gè)力的加速度即可
重力
右邊小球全程受到方向向下的重力,其公式為
G = m * g
彈力
右邊小球全程受到從自身中心指向左邊小球中心方向的的彈力,其公式為
胡克定律
F = -△x * k
空氣阻力
可以簡化成和速度方向相反,乘一個(gè)小于1的阻力系數(shù)的力
// dragCoefficient值越大說明阻力越大 F = -v * dragCoefficient
我們先創(chuàng)建重力的單位向量代表重力的方向,因?yàn)橹亓τ肋h(yuǎn)是垂直向下的所以向量其單位向量是(0, 1),然后給定一個(gè)重力大小,根據(jù)重力公式,質(zhì)量乘重力加速度即可,這里質(zhì)量我給了 10,重力加速度給 9.8,代碼如下
// 獲取重力單位向量
function getGravityNorVector() {
return {
x: 0,
y: 1,
};
}
// 獲取重力大小
function getGravitySize() {
return m * g;
}
然后創(chuàng)建彈力的單位向量表示彈力的方向,其方向永遠(yuǎn)是右球的球心指向左球的球心,其大小根據(jù)胡克定律給到,即形變距離 乘以 彈簧彈性系數(shù)
// 獲取彈力單位向量
function getElasticityNorVector() {
// 左球球心坐標(biāo)減右球球心坐標(biāo),然后做向量歸一化
return normalized(createVector(originPosition, targetPosition));
}
// 獲取彈力大小
function getElasticitySize() {
// 計(jì)算Δx
const offsetX =
length(createVector(originPosition, targetPosition)) - originElasticitySize;
// 胡克定律,只要大小,所以取絕對(duì)值
return Math.abs(-offsetX * K);
}
然后我們計(jì)算空氣阻力,其方向和速度方向相反,阻力系數(shù)我給了個(gè) 0.1,由于一開始初速度為 0,所以阻力為 0,只用等到動(dòng)起來有速度的時(shí)候才會(huì)產(chǎn)生阻力
// 空氣阻力,dragCoefficient為阻力系數(shù),輸出是一個(gè)向量
const other = {
x: -vx * dragCoefficient,
y: -vy * dragCoefficient,
};
現(xiàn)在我們所有力的大小和方向都求出來了,然后根據(jù)向量平行四邊形法則,先合成彈力和重力
// 單位向量 * 向量長度可以得到矢量力,輸出是一個(gè)向量 const elasticityAndGravity = add( mul(getElasticitySize(), getElasticityNorVector()), mul(getGravitySize(), getGravityNorVector()) );
然后再和空氣阻力合成最終的力
// 所有力的合成,輸出是一個(gè)向量 const total = add(elasticityAndGravity, other);
然后再把合成后的力分解成水平和垂直的兩個(gè)分力,這里用到向量投影算法就能實(shí)現(xiàn),即可以先通過向量點(diǎn)積的形式,求出與水平單位向量(1,0)和垂直單位向量(0,1)的余弦值,然后用合成力的大小乘以這個(gè)余弦值得到投影到水平方向和垂直方向的大小,再用這個(gè)大小分別乘以水平單位向量(1,0)和垂直單位向量(0,1)就能得到水平和垂直的兩個(gè)分力向量了
// 獲取力在x軸和y軸分量向量
function getXYAxisVector(fNorVector, fSize) {
const yAxisNorVector = createVector(
{
x: targetPosition.x,
y: targetPosition.y - 1,
},
targetPosition
);
const xAxisNorVector = createVector(
{
x: targetPosition.x - 1,
y: targetPosition.y,
},
targetPosition
);
// 分別點(diǎn)擊求向量在水平單位向量和垂直單位向量的余弦值
const cosYAxis = dot(yAxisNorVector, fNorVector);
const cosXAxis = dot(xAxisNorVector, fNorVector);
return {
yVector: mul(fSize * cosYAxis, yAxisNorVector),
xVector: mul(fSize * cosXAxis, xAxisNorVector),
};
}
// 獲取水平和垂直分力向量
const result = getXYAxisVector(normalized(total), length(total));
然后根據(jù)公式
F = m * a;
把得到的兩個(gè)分力分別除以質(zhì)量 m,目前 m 給的是 10,得到 x 和 y 方向的加速度
// 獲取水平和垂直方向加速度 const xAcceleration = result.xVector.x / m; const yAcceleration = result.yVector.y / m;
然后再每一幀渲染的時(shí)候,把加速度加到速度上,右球的坐標(biāo)加上速度,即可以渲染出效果,這里除以100是防止速度太快
vx += xAcceleration; vy += yAcceleration; targetPosition.x += vx / 100; targetPosition.y += vy / 100;
就能得到最終這個(gè)效果了

到此這篇關(guān)于使用canvas實(shí)現(xiàn)有趣的彈簧效果的文章就介紹到這了,更多相關(guān)canvas彈簧內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript面試之如何實(shí)現(xiàn)數(shù)組拍平(扁平化)方法
數(shù)組扁平化是指將一個(gè)多維數(shù)組變?yōu)橐痪S數(shù)組,下面這篇文章主要給大家介紹了關(guān)于JavaScript面試之如何實(shí)現(xiàn)數(shù)組拍平(扁平化)方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-11-11
教你如何解密js/vbs/vbscript加密的編碼異處理小結(jié)
教你如何解密js/vbs/vbscript加密的編碼異處理加密代碼 是一篇非常不錯(cuò)的加密解密原理,希望大家仔細(xì)研究2008-06-06
微信小程序錯(cuò)誤this.setData報(bào)錯(cuò)及解決過程
這篇文章主要介紹了微信小程序錯(cuò)誤this.setData報(bào)錯(cuò)及解決過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09
js實(shí)現(xiàn)拖動(dòng)緩動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)拖動(dòng)緩動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01
JavaScript實(shí)現(xiàn)簡單驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡單驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
chrome瀏覽器當(dāng)表單自動(dòng)填充時(shí)如何去除瀏覽器自動(dòng)添加的默認(rèn)樣式
很多朋友都遇到這個(gè)問題:當(dāng)使用chrome瀏覽器表單自動(dòng)填充時(shí)都會(huì)自動(dòng)添加默認(rèn)的樣式,該如何去除默認(rèn)樣式呢?看看小編是怎么去除的,需要的朋友一起學(xué)習(xí)吧2015-10-10

