国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【30分鐘學(xué)完】canvas動(dòng)畫|游戲基礎(chǔ)(7):動(dòng)量守恒與多物體碰撞

Dr_Noooo / 3318人閱讀

摘要:科普動(dòng)量是守恒量。動(dòng)量守恒定律表示為一個(gè)系統(tǒng)不受外力或者所受外力之和為零,這個(gè)系統(tǒng)中所有物體的總動(dòng)量保持不變。動(dòng)量守恒定律可由機(jī)械能對空間平移對稱性推出。在可以忽略碰撞以外的因素時(shí),動(dòng)量是守恒的。

前言

一路沿著本系列教程學(xué)習(xí)的朋友可能會(huì)發(fā)現(xiàn),前面教程中都盡量避免提及質(zhì)量的概念,很多運(yùn)動(dòng)概念也時(shí)刻提醒大家這不是真實(shí)的物體運(yùn)動(dòng)。因?yàn)檎鎸?shí)的物體運(yùn)動(dòng)其實(shí)跟質(zhì)量都是密不可分的,而且質(zhì)量的引入自然必須提及力學(xué)概念,所以為了不內(nèi)容冗余才忽略了質(zhì)量。
從本篇開始,將會(huì)正式引入物理力學(xué)概念,給每個(gè)物體賦予質(zhì)量概念,為了更加真實(shí)的模擬現(xiàn)實(shí)環(huán)境的物體運(yùn)動(dòng)。
閱讀本篇前請先打好前面的基礎(chǔ)。
本人能力有限,歡迎牛人共同討論,批評指正。

動(dòng)量與動(dòng)量守恒
【科普】一般而言,一個(gè)物體的動(dòng)量指的是這個(gè)物體在它運(yùn)動(dòng)方向上保持運(yùn)動(dòng)的趨勢。動(dòng)量實(shí)際上是牛頓第一定律的一個(gè)推論。

動(dòng)量即是“物體運(yùn)動(dòng)的量”,是物體的質(zhì)量和速度的乘積,是矢量,能夠反應(yīng)出運(yùn)動(dòng)的效果,一般用p表示。舉個(gè)例子,低速運(yùn)動(dòng)的重物,跟高速運(yùn)動(dòng)的子彈,擁有相同的威力。

p = m * v
【科普】動(dòng)量是守恒量。動(dòng)量守恒定律表示為:一個(gè)系統(tǒng)不受外力或者所受外力之和為零,這個(gè)系統(tǒng)中所有物體的總動(dòng)量保持不變。它的一個(gè)推論為:在沒有外力干預(yù)的情況下,任何系統(tǒng)的質(zhì)心都將保持勻速直線運(yùn)動(dòng)或靜止?fàn)顟B(tài)不變。動(dòng)量守恒定律可由機(jī)械能對空間平移對稱性推出。

動(dòng)量守恒即系統(tǒng)在碰撞前的總動(dòng)量等于系統(tǒng)在碰撞后的總動(dòng)量。其中的系統(tǒng)簡單理解就是物體的集合。在可以忽略碰撞以外的因素時(shí),動(dòng)量是守恒的。

(m0 * v0) + (m1 * v1) = (m0 * v0Final) + (m1 * v1Final)

這條公式是我們計(jì)算碰撞后速度的基礎(chǔ),因?yàn)槲覀兗俣ㄎ覀兊奈矬w都是剛體,并且忽略外力做碰撞。現(xiàn)在只要推導(dǎo)出末速度v0Final和v1Final的公式,就可以應(yīng)用到我們的模擬碰撞的編程動(dòng)畫中。推導(dǎo)過程如下:

其實(shí)推導(dǎo)過程不重要,只要記得結(jié)論:

v1Final = (2 * m0 * v0) + v1 * (m1 - m0) / (m0 + m1)
v0Final = (2 * m1 * v1) - v0 * (m0 - m1) / (m0 + m1)
// 二者可直接轉(zhuǎn)換
v1Final = (v0 - v1) + v0Final
單軸碰撞

我們開始使用前面推導(dǎo)出的公式,先來個(gè)最簡單的單軸碰撞例子,這里演示了兩個(gè)球相撞的效果,mass定義了他們的質(zhì)量,由于他們初始速度相同,所以依據(jù)動(dòng)量守恒碰撞后ball0的速度變?yōu)?1/3,而ball1的速度變?yōu)?/3。

【PS】這里有個(gè)細(xì)節(jié),碰撞時(shí)可能出現(xiàn)球已經(jīng)重疊的情況,這個(gè)例子只是簡單將末速度加給碰撞后的球,用以彈開他們,這是不嚴(yán)謹(jǐn)?shù)行У淖龇ā?/pre>

完整示例:單軸碰撞

/**
 * 單軸碰撞
 * */
window.onload = function () {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const ball0 = new Ball();
  const ball1 = new Ball();
  // 定義ball0的屬性
  ball0.mass = 2;
  ball0.x = 50;
  ball0.y = canvas.height / 2;
  ball0.vx = 1;
  // 定義ball1的屬性
  ball1.mass = 1;
  ball1.x = 300;
  ball1.y = canvas.height / 2;
  ball1.vx = -1;

  (function drawFrame() {
    window.requestAnimationFrame(drawFrame, canvas);
    context.clearRect(0, 0, canvas.width, canvas.height);
    // 移動(dòng)兩個(gè)物體的位置
    ball0.x += ball0.vx;
    ball1.x += ball1.vx;
    const dist = ball1.x - ball0.x;
    // 碰撞檢測
    if (Math.abs(dist) < ball0.radius + ball1.radius) {
      // 運(yùn)用動(dòng)量守恒計(jì)算碰撞后速度
      const vxTotal = ball0.vx - ball1.vx;
      ball0.vx = ((ball0.mass - ball1.mass) * ball0.vx + 2 * ball1.mass * ball1.vx) / (ball0.mass + ball1.mass);
      ball1.vx = vxTotal + ball0.vx;
      // 將速度加到兩物體的位置上實(shí)現(xiàn)彈開
      ball0.x += ball0.vx;
      ball1.y += ball1.vx;
    }
    // 繪制兩球
    ball0.draw(context);
    ball1.draw(context);
  }());
};
雙軸碰撞

現(xiàn)實(shí)情況很少會(huì)出現(xiàn)單軸碰撞,如果兩個(gè)軸上都有速度,處理起來會(huì)比較麻煩,把速度分解出來再代入動(dòng)量守恒公式,這里運(yùn)用到上一篇中關(guān)于坐標(biāo)旋轉(zhuǎn)的知識(shí)。

基本思路:

使用旋轉(zhuǎn)公式,以其中一個(gè)物體為原點(diǎn),旋轉(zhuǎn)整個(gè)系統(tǒng),將兩物體的中心連線置為水平場景;

求出物體x軸上的速度;

使用動(dòng)量守恒計(jì)算x軸上的碰撞后速度;

再旋轉(zhuǎn)回來。

示例是兩個(gè)隨機(jī)初始速度的球在空間內(nèi)碰撞,碰到邊界也會(huì)反彈,由于代碼量較大,這里只截取部分核心代碼:
注意:旋轉(zhuǎn)是以ball0為原點(diǎn)進(jìn)行的,也就是說旋轉(zhuǎn)中的所有位置和速度都是相對于ball0的,所有回旋后的位置和速度需要轉(zhuǎn)換成相對于相對區(qū)域位置。
完整示例:雙軸碰撞

// 坐標(biāo)旋轉(zhuǎn)函數(shù)
function rotate(x, y, sin, cos, reverse) {
  return {
    x: (reverse) ? (x * cos + y * sin) : (x * cos - y * sin),
    y: (reverse) ? (y * cos - x * sin) : (y * cos + x * sin),
  };
}
// 檢查碰撞
function checkCollision() {
  const dx = ball1.x - ball0.x;
  const dy = ball1.y - ball0.y;
  const dist = Math.sqrt(dx ** 2 + dy ** 2);

  // 基于距離的碰撞檢測
  if (dist < ball0.radius + ball1.radius) {
    // 以ball0為中心點(diǎn)旋轉(zhuǎn)
    const angle = Math.atan2(dy, dx);
    const sin = Math.sin(angle);
    const cos = Math.cos(angle);
    // ball0在中心點(diǎn)
    const pos0 = {
      x: 0,
      y: 0,
    };
    // 依據(jù)ball1與ball0的相對距離計(jì)算旋轉(zhuǎn)后的坐標(biāo)(反向)
    const pos1 = rotate(dx, dy, sin, cos, true);
    // 旋轉(zhuǎn)ball0的速度(反向)
    const vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true);
    // 旋轉(zhuǎn)ball1的速度(反向)
    const vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true);
    // 計(jì)算相對速度
    const vxTotal = vel0.x - vel1.x;
    // 計(jì)算相撞后速度
    vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);
    vel1.x = vxTotal + vel0.x;
    // 計(jì)算相撞后位置
    pos0.x += vel0.x;
    pos1.x += vel1.x;

    // 回旋位置
    const pos0F = rotate(pos0.x, pos0.y, sin, cos, false);
    const pos1F = rotate(pos1.x, pos1.y, sin, cos, false);

    // 將相對ball0位置轉(zhuǎn)換為相對區(qū)域位置
    ball1.x = ball0.x + pos1F.x;
    ball1.y = ball0.y + pos1F.y;
    ball0.x += pos0F.x;
    ball0.y += pos0F.y;
    // 回旋速度
    const vel0F = rotate(vel0.x, vel0.y, sin, cos, false);
    const vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
    ball0.vx = vel0F.x;
    ball0.vy = vel0F.y;
    ball1.vx = vel1F.x;
    ball1.vy = vel1F.y;
  }
}
多物體碰撞

加入多個(gè)物體,只是把兩個(gè)物體的碰撞檢測,改變成所有物體兩兩間做碰撞檢測。

基本思路:

先遍歷一次物體集,讓物體移動(dòng)并處理邊界碰撞;

再遍歷一次物體集,兩兩物體做碰撞檢測并求出碰撞后的速度和位置;

最后一次遍歷物體集,繪制他們。

依據(jù)這個(gè)思路我們得到了這樣一個(gè)示例,球的質(zhì)量、大小和初始速度都是隨機(jī)的,碰撞代碼基本和前面是一樣的。
完整示例:多物體碰撞(無處理重疊)

仔細(xì)觀察示例,會(huì)發(fā)現(xiàn)這里會(huì)出現(xiàn)一個(gè)問題:小球會(huì)重疊到一起并且無法分離。這是由如下原因造成的:

程序依照三個(gè)小球的速度移動(dòng)他們;

程序檢測ball0和ball1,ball0和ball2,發(fā)現(xiàn)他們并沒有碰撞;

程序檢測ball1和ball2。因?yàn)樗麄儼l(fā)生了碰撞,所以他們的速度和位置都要重新計(jì)算,然后彈開。但這不巧讓ball1和ball0 接觸上了。然而,由于這一組合已經(jīng)過檢測,所以忽略了這一事實(shí);

在下一輪循環(huán)中,程序依然按照他們的速度移動(dòng)小球。這樣就使得ball0和ball1更加靠近了;

現(xiàn)在程序檢測到ball0和ball1碰撞了,重新計(jì)算速度和位置后,想要將他們分開,卻會(huì)出現(xiàn)無法完全分開的情況,就卡到了一起。

【PS】為什么無法完全分開?因?yàn)槲覀兎珠_兩物體的做法是將新速度加到新位置上,如果舊位置已經(jīng)重疊,那就永遠(yuǎn)無法分離了。

改變分開兩物體的處理辦法就能解決這個(gè)問題,這里有個(gè)較為簡單但不是很精確的辦法:

先求給出總速度絕對值;

再求出重疊部分的長度;

以相撞后速度在總速度的比例移開兩個(gè)物體。

完整示例:多物體碰撞
改造后核心代碼如下:

function checkCollision(ball0, ball1) {
  const dx = ball1.x - ball0.x;
  const dy = ball1.y - ball0.y;
  const dist = Math.sqrt(dx ** 2 + dy ** 2);

  // 基于距離的碰撞檢測
  if (dist < ball0.radius + ball1.radius) {
    // 以ball0為中心點(diǎn)旋轉(zhuǎn)
    const angle = Math.atan2(dy, dx);
    const sin = Math.sin(angle);
    const cos = Math.cos(angle);
    // ball0在中心點(diǎn)
    const pos0 = {
      x: 0,
      y: 0,
    };
    // 依據(jù)ball1與ball0的相對距離計(jì)算旋轉(zhuǎn)后的坐標(biāo)(反向)
    const pos1 = rotate(dx, dy, sin, cos, true);
    // 旋轉(zhuǎn)ball0的速度(反向)
    const vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true);
    // 旋轉(zhuǎn)ball1的速度(反向)
    const vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true);
    // 計(jì)算相對速度
    const vxTotal = vel0.x - vel1.x;
    // 計(jì)算相撞后速度
    vel0.x = ((ball0.mass - ball1.mass) * vel0.x + 2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);
    vel1.x = vxTotal + vel0.x;
    // 計(jì)算出絕對速度和重疊量,分離避免物體重疊
    const absV = Math.abs(vel0.x) + Math.abs(vel1.x);
    const overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
    pos0.x += vel0.x / absV * overlap;
    pos1.x += vel1.x / absV * overlap;

    // 回旋位置
    const pos0F = rotate(pos0.x, pos0.y, sin, cos, false);
    const pos1F = rotate(pos1.x, pos1.y, sin, cos, false);

    // 將相對ball0位置轉(zhuǎn)換為相對區(qū)域位置
    ball1.x = ball0.x + pos1F.x;
    ball1.y = ball0.y + pos1F.y;
    ball0.x += pos0F.x;
    ball0.y += pos0F.y;
    // 回旋速度
    const vel0F = rotate(vel0.x, vel0.y, sin, cos, false);
    const vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
    ball0.vx = vel0F.x;
    ball0.vy = vel0F.y;
    ball1.vx = vel1F.x;
    ball1.vy = vel1F.y;
  }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94051.html

相關(guān)文章

  • 30分鐘學(xué)完canvas動(dòng)畫|游戲基礎(chǔ)(7):動(dòng)量守恒與多物體碰撞

    摘要:科普動(dòng)量是守恒量。動(dòng)量守恒定律表示為一個(gè)系統(tǒng)不受外力或者所受外力之和為零,這個(gè)系統(tǒng)中所有物體的總動(dòng)量保持不變。動(dòng)量守恒定律可由機(jī)械能對空間平移對稱性推出。在可以忽略碰撞以外的因素時(shí),動(dòng)量是守恒的。 前言 一路沿著本系列教程學(xué)習(xí)的朋友可能會(huì)發(fā)現(xiàn),前面教程中都盡量避免提及質(zhì)量的概念,很多運(yùn)動(dòng)概念也時(shí)刻提醒大家這不是真實(shí)的物體運(yùn)動(dòng)。因?yàn)檎鎸?shí)的物體運(yùn)動(dòng)其實(shí)跟質(zhì)量都是密不可分的,而且質(zhì)量的引入自...

    scq000 評論0 收藏0
  • 30分鐘學(xué)完canvas動(dòng)畫|游戲基礎(chǔ)(4):邊界與碰撞

    摘要:越界是常見的場景,一般會(huì)有兩種場景的越界一是整個(gè)物體移出區(qū)域,二是物體接觸到區(qū)域邊界。基本思路檢查物體是否越過任意邊界如果發(fā)生越界,立即將物體置回邊界反轉(zhuǎn)物體的速度向量的方向。核心代碼如下完整示例兩圓基于距離的碰撞演示 前言 本系列前幾篇中常出現(xiàn)物體跑到畫布外的情況,本篇就是為了解決這個(gè)問題。 閱讀本篇前請先打好前面的基礎(chǔ)。 本人能力有限,歡迎牛人共同討論,批評指正。 越界檢測 假...

    寵來也 評論0 收藏0
  • 30分鐘學(xué)完canvas動(dòng)畫|游戲基礎(chǔ)(4):邊界與碰撞

    摘要:越界是常見的場景,一般會(huì)有兩種場景的越界一是整個(gè)物體移出區(qū)域,二是物體接觸到區(qū)域邊界。基本思路檢查物體是否越過任意邊界如果發(fā)生越界,立即將物體置回邊界反轉(zhuǎn)物體的速度向量的方向。核心代碼如下完整示例兩圓基于距離的碰撞演示 前言 本系列前幾篇中常出現(xiàn)物體跑到畫布外的情況,本篇就是為了解決這個(gè)問題。 閱讀本篇前請先打好前面的基礎(chǔ)。 本人能力有限,歡迎牛人共同討論,批評指正。 越界檢測 假...

    岳光 評論0 收藏0

發(fā)表評論

0條評論

Dr_Noooo

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<