上一篇基本已經對canvas打好了基礎,本篇主要將引入經典物理概念速度和加速度,探討他們在編程動畫中的應用。
在閱讀以前請先自行了解速度和加速度的基礎知識,以及向量與向量加法。
本人能力有限,歡迎牛人共同討論,批評指正。javascript
【科普】速度是描述物體運動快慢和方向的物理量。物理學中提到物體的速度一般是指其瞬時速度。速度在國際單位制中的單位是米每秒,國際符號是m/s,中文符號是米/秒。相對論框架中,物體的速度上限是光速。
在動畫編程中,速度是最基礎的要素,在本系列教程的第2篇講到三角函數時就有所體現。html
見下圖,咱們這裏要討論的計算機動畫中的速度跟物理學上概念類似,都是矢量,也就是既有大小又有方向,而方向的體現就是其值的正負,回顧系列第1篇中講到的座標系,沿着正半軸運動速度就是正,沿着負半軸運動速度就是負。
另一點不一樣就是單位,不必定會以時間爲單位,多是以幀爲單位,好比「像素/幀」。
也正由於速度是矢量,那任何一個速度均可以分解爲x軸和y軸上的速度,這就是編程動畫基本思想。 java
將系列第2篇的「一個會跟蹤鼠標位置的箭頭」改形成「跟隨鼠標的箭頭」。代碼很基礎,看註釋就行,基本思路:git
特別說明,由於這個例子中的動畫循環是基於幀,因此速度單位是像素每幀。
完整例子:跟隨鼠標的箭頭github
/** * 跟隨鼠標的箭頭 * */ window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const mouse = utils.captureMouse(canvas); const arrow = new Arrow(); // 設定速度 const speed = 3; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); // 計算鼠標與箭頭的相對距離 const dx = mouse.x - arrow.x; const dy = mouse.y - arrow.y; // 求箭頭指向鼠標的夾角 const angle = Math.atan2(dy, dx); // 將速度分解到x軸和y軸 const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; // 設置箭頭的角度 arrow.rotation = angle; // 將分解後的速度加到箭頭的兩軸位置上 arrow.x += vx; arrow.y += vy; // 從新繪製箭頭 arrow.draw(context); }()); };
【科普】加速度是物理學中的一個物理量,是一個矢量,主要應用於經典物理當中,通常用字母a表示,在國際單位制中的單位爲米每二次方秒。加速度是速度矢量對於時間的變化率,描述速度的方向和大小變化的快慢。
計算機動畫中的加速度就是速度的變化量,跟前面的速度同樣是矢量,也能夠分解爲x軸和y軸上的加速度,方法同上。單位能夠是像素每二次方幀,與「力學」有很大聯繫。
加速度可讓運動更加天然,在計算機動畫中模擬真實運動是必要的基礎。
請明確加速度是速度的變化量,也就是加速度的方向與速度相同即加速,方向相反即減速,若是加速度爲零,速度將恆定,物體作勻速直線運動。spring
繼續改造前面的例子跟隨鼠標的箭頭爲「往鼠標方向加速的箭頭」。改造量不大,就是把加速度分解後疊加給速度,基本思路:編程
完整例子:往鼠標方向加速的箭頭
觀察實例,你會發現這個箭頭雖然運動比前面例子天然了很多,但卻永遠都不會停下,這是因爲這裏的加速度不變的,而現實中因爲摩擦力等因素加速度是會被削減的。canvas
/** * 往鼠標方向加速的箭頭 * */ window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const mouse = utils.captureMouse(canvas); const arrow = new Arrow(); // 初始化速度 let vx = 0; let vy = 0; // 設定加速度 const force = 0.02; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); // 計算鼠標與箭頭的相對距離 const dx = mouse.x - arrow.x; const dy = mouse.y - arrow.y; // 求箭頭指向鼠標的夾角 const angle = Math.atan2(dy, dx); // 將加速度分解到x軸和y軸 const ax = Math.cos(angle) * force; const ay = Math.sin(angle) * force; // 設置箭頭的角度 arrow.rotation = angle; // 將分解後的加速度加到箭頭的兩軸速度上 vx += ax; vy += ay; // 將分解後的速度加到箭頭的兩軸位置上 arrow.x += vx; arrow.y += vy; // 從新繪製箭頭 arrow.draw(context); }()); };
這裏會介紹兩個較高級的常見技術,緩動和彈動。
所謂比例運動,就是運動程度與目標點距離是成正比,簡單來講就是「距離越遠,運動程度越大」,這裏的運動程度是指但不侷限於速度和加速度的與運動有關的變量。框架
緩動是指物體的速度與它到目標點的距離成比例,即基於距離的比例速度,這個比例會影響速度的大小。
緩動的運動特質不止一種,你能夠先快後慢,也能夠先慢後快,還能夠先慢後快再慢等,咱們這裏只以最簡單的先快後慢爲例,即距離越大,速度越大,距離縮進到0,速度也爲0。 函數
仍是改造前面的跟隨鼠標的箭頭,代碼以下,基本思路:
完整例子:緩動到鼠標位置的箭頭
/** * 往鼠標方向緩動的箭頭 * */ window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const mouse = utils.captureMouse(canvas); const arrow = new Arrow(); // 比例係數 const easing = 0.05; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); // 計算鼠標與箭頭的相對距離 const dx = mouse.x - arrow.x; const dy = mouse.y - arrow.y; // 求箭頭指向鼠標的夾角 const angle = Math.atan2(dy, dx); // 根據距離緩動 const vx = dx * easing; const vy = dy * easing; // 設置箭頭的角度 arrow.rotation = angle; // 將分解後的速度加到箭頭的兩軸位置上 arrow.x += vx; arrow.y += vy; // 從新繪製箭頭 arrow.draw(context); }()); };
彈動是指物體的加速度與它到目標點的距離成比例,即基於距離的比例加速度,這個比例會影響加速度的大小。
彈動會使運動天然且有靈性,你會發現物體會衝過目標點,而後開始回彈,往復。這樣就能模擬出彈簧或橡皮筋的效果。
特別注意,距離爲0時加速度也爲0,但速度不必定爲0。
仍是改造前面的往鼠標方向加速的箭頭,代碼以下,你會發現這個跟前面的加速度例子很像,都是不斷的往復運動,其緣由都是加速度和速度很難同時爲0致使的,這裏咱們加了削減係數讓它停下來,基本思路:
完整例子:往鼠標方向彈動的箭頭
/** * 往鼠標方向彈動的箭頭 * */ window.onload = function () { const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); const mouse = utils.captureMouse(canvas); const arrow = new Arrow(); // 設定彈動係數 const spring = 0.02; // 初始化速度 let vx = 0; let vy = 0; // 削減係數 const friction = 0.95; (function drawFrame() { window.requestAnimationFrame(drawFrame, canvas); context.clearRect(0, 0, canvas.width, canvas.height); // 計算鼠標與箭頭的相對距離 const dx = mouse.x - arrow.x; const dy = mouse.y - arrow.y; // 求箭頭指向鼠標的夾角 const angle = Math.atan2(dy, dx); // 根據距離彈動 const ax = dx * spring; const ay = dy * spring; // 設置箭頭的角度 arrow.rotation = angle; // 將分解後的加速度加到箭頭的兩軸速度上 vx += ax; vy += ay; // 削減速度 vx *= friction; vy *= friction; // 將分解後的速度加到箭頭的兩軸位置上 arrow.x += vx; arrow.y += vy; // 從新繪製箭頭 arrow.draw(context); }()); };