使用canvas實現(xiàn)有趣的彈簧效果
先上效果
兩個小球之間有一根彈簧,這里有一條線表示,其中左球固定,在點擊開始后,右球開始做自由落體
思路
先做受力分析
經(jīng)過受力分析可以發(fā)現(xiàn),整個系統(tǒng)一共有三個力在起作用,我們分別把他們求出來并合成為一個力,然后這個力的加速度即可
重力
右邊小球全程受到方向向下的重力,其公式為
G = m * g
彈力
右邊小球全程受到從自身中心指向左邊小球中心方向的的彈力,其公式為
胡克定律
F = -△x * k
空氣阻力
可以簡化成和速度方向相反,乘一個小于1的阻力系數(shù)的力
// dragCoefficient值越大說明阻力越大 F = -v * dragCoefficient
我們先創(chuàng)建重力的單位向量代表重力的方向,因為重力永遠是垂直向下的所以向量其單位向量是(0, 1),然后給定一個重力大小,根據(jù)重力公式,質量乘重力加速度即可,這里質量我給了 10,重力加速度給 9.8,代碼如下
// 獲取重力單位向量 function getGravityNorVector() { return { x: 0, y: 1, }; } // 獲取重力大小 function getGravitySize() { return m * g; }
然后創(chuàng)建彈力的單位向量表示彈力的方向,其方向永遠是右球的球心指向左球的球心,其大小根據(jù)胡克定律給到,即形變距離 乘以 彈簧彈性系數(shù)
// 獲取彈力單位向量 function getElasticityNorVector() { // 左球球心坐標減右球球心坐標,然后做向量歸一化 return normalized(createVector(originPosition, targetPosition)); } // 獲取彈力大小 function getElasticitySize() { // 計算Δx const offsetX = length(createVector(originPosition, targetPosition)) - originElasticitySize; // 胡克定律,只要大小,所以取絕對值 return Math.abs(-offsetX * K); }
然后我們計算空氣阻力,其方向和速度方向相反,阻力系數(shù)我給了個 0.1,由于一開始初速度為 0,所以阻力為 0,只用等到動起來有速度的時候才會產(chǎn)生阻力
// 空氣阻力,dragCoefficient為阻力系數(shù),輸出是一個向量 const other = { x: -vx * dragCoefficient, y: -vy * dragCoefficient, };
現(xiàn)在我們所有力的大小和方向都求出來了,然后根據(jù)向量平行四邊形法則,先合成彈力和重力
// 單位向量 * 向量長度可以得到矢量力,輸出是一個向量 const elasticityAndGravity = add( mul(getElasticitySize(), getElasticityNorVector()), mul(getGravitySize(), getGravityNorVector()) );
然后再和空氣阻力合成最終的力
// 所有力的合成,輸出是一個向量 const total = add(elasticityAndGravity, other);
然后再把合成后的力分解成水平和垂直的兩個分力,這里用到向量投影算法就能實現(xiàn),即可以先通過向量點積的形式,求出與水平單位向量(1,0)和垂直單位向量(0,1)的余弦值,然后用合成力的大小乘以這個余弦值得到投影到水平方向和垂直方向的大小,再用這個大小分別乘以水平單位向量(1,0)和垂直單位向量(0,1)就能得到水平和垂直的兩個分力向量了
// 獲取力在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 ); // 分別點擊求向量在水平單位向量和垂直單位向量的余弦值 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;
把得到的兩個分力分別除以質量 m
,目前 m
給的是 10,得到 x 和 y 方向的加速度
// 獲取水平和垂直方向加速度 const xAcceleration = result.xVector.x / m; const yAcceleration = result.yVector.y / m;
然后再每一幀渲染的時候,把加速度加到速度上,右球的坐標加上速度,即可以渲染出效果,這里除以100是防止速度太快
vx += xAcceleration; vy += yAcceleration; targetPosition.x += vx / 100; targetPosition.y += vy / 100;
就能得到最終這個效果了
到此這篇關于使用canvas實現(xiàn)有趣的彈簧效果的文章就介紹到這了,更多相關canvas彈簧內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript面試之如何實現(xiàn)數(shù)組拍平(扁平化)方法
數(shù)組扁平化是指將一個多維數(shù)組變?yōu)橐痪S數(shù)組,下面這篇文章主要給大家介紹了關于JavaScript面試之如何實現(xiàn)數(shù)組拍平(扁平化)方法的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2021-11-11教你如何解密js/vbs/vbscript加密的編碼異處理小結
教你如何解密js/vbs/vbscript加密的編碼異處理加密代碼 是一篇非常不錯的加密解密原理,希望大家仔細研究2008-06-06chrome瀏覽器當表單自動填充時如何去除瀏覽器自動添加的默認樣式
很多朋友都遇到這個問題:當使用chrome瀏覽器表單自動填充時都會自動添加默認的樣式,該如何去除默認樣式呢?看看小編是怎么去除的,需要的朋友一起學習吧2015-10-10