成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

【30分鐘學(xué)完】canvas動(dòng)畫|游戲基礎(chǔ)(4):邊界與碰撞

岳光 / 2426人閱讀

摘要:越界是常見的場(chǎng)景,一般會(huì)有兩種場(chǎng)景的越界一是整個(gè)物體移出區(qū)域,二是物體接觸到區(qū)域邊界?;舅悸窓z查物體是否越過任意邊界如果發(fā)生越界,立即將物體置回邊界反轉(zhuǎn)物體的速度向量的方向。核心代碼如下完整示例兩圓基于距離的碰撞演示

前言

本系列前幾篇中常出現(xiàn)物體跑到畫布外的情況,本篇就是為了解決這個(gè)問題。
閱讀本篇前請(qǐng)先打好前面的基礎(chǔ)。
本人能力有限,歡迎牛人共同討論,批評(píng)指正。

越界檢測(cè)

假定物體是個(gè)圓形,如圖其圓心坐標(biāo)即是物體的x軸和y軸坐標(biāo)。
越界是常見的場(chǎng)景,一般會(huì)有兩種場(chǎng)景的越界:一是整個(gè)物體移出區(qū)域,二是物體接觸到區(qū)域邊界。我們以畫布邊界為例進(jìn)行討論,示例中矩形邊界即是:

let top = 0;
let bottom = canvas.height;
let left = 0;
let right = canvas.width;

整個(gè)物體移出區(qū)域

要整個(gè)物體離開范圍才算越界,則可得越界條件如下,以下任何一項(xiàng)為true即可判定越界。

// 右側(cè)越界
object.x - object.width/2 > right
// 左側(cè)越界
object.x + object.width/2 < left
// 上部越界
object.y + object.height/2 < top
// 下部越界
object.y - object.height/2 > bottom
物體接觸到區(qū)域邊界

物體接觸到區(qū)域邊界就算越界,則可得越界條件如下,以下任何一項(xiàng)為true即可判定越界。

// 右側(cè)越界
object.x + object.width/2 > right
// 左側(cè)越界
object.x - object.width/2 < left
// 上部越界
object.y - object.height/2 < top
// 下部越界
object.y + object.height/2 > bottom
越界了該怎么辦

搞明白越界條件后,接下來(lái)討論越界之后的處理辦法,一般是一下四種。

將物體移除

這是最簡(jiǎn)單的處理辦法,屬于整個(gè)物體移出區(qū)域才算越界的情況。
下面的例子會(huì)先批量創(chuàng)建ball,保存在balls數(shù)組里,每次動(dòng)畫循環(huán)都會(huì)遍歷這個(gè)數(shù)組,依次輸入draw()函數(shù),改變ball的位置并檢測(cè)是否越界。下面只列出draw()函數(shù)的代碼。
完整示例:清除越界圓

function draw(ball, pos) {
  // 依據(jù)球的速度改變球的位置
  ball.x += ball.vx;
  ball.y += ball.vy;
  // 檢查是否越界
  if (ball.x - ball.radius > canvas.width || ball.x + ball.radius < 0 || ball.y - ball.radius > canvas.height || ball.y + ball.radius < 0) {
    // 在數(shù)組中清除越界的球
    balls.splice(pos, 1);
    // 打印提示
    if (balls.length > 0) {
      log.value += `Removed ${ball.id}
`;
      log.scrollTop = log.scrollHeight;
    } else {
      log.value += "All gone!
";
    }
  }
  // 畫球
  ball.draw(context);
}
將其物體置回邊界內(nèi)

屬于整個(gè)物體移出區(qū)域才算越界的情況。
下面的例子也是把創(chuàng)建的ball保存在balls數(shù)組里,但ball的初始位置都是畫布中間的下部,如果檢測(cè)到有ball越界,則會(huì)重置ball的位置。下面只列出draw()函數(shù)的代碼。
完整示例:彩色噴泉

function draw(ball) {
  // 依據(jù)球的速度改變球的位置,這里包含了偽重力
  ball.vy += gravity;
  ball.x += ball.vx;
  ball.y += ball.vy;
  // 檢測(cè)是否越界
  if (ball.x - ball.radius > canvas.width || ball.x + ball.radius < 0 || ball.y - ball.radius > canvas.height || ball.y + ball.radius < 0) {
    // 重置ball的位置
    ball.x = canvas.width / 2;
    ball.y = canvas.height;
    // 重置ball的速度
    ball.vx = Math.random() * 6 - 3;
    ball.vy = Math.random() * -10 - 10;
    // 打印提示
    log.value = `Reset ${ball.id}
`;
  }
  // 畫球
  ball.draw(context);
}
屏幕環(huán)繞

屬于整個(gè)物體移出區(qū)域才算越界的情況。
屏幕環(huán)繞就是讓同一個(gè)物體出現(xiàn)在邊界內(nèi)的另一個(gè)位置,如果一個(gè)物體從屏幕左側(cè)移出,它就會(huì)在屏幕右側(cè)再次出現(xiàn),反之亦然,上下也是同理。
這里比前面的要稍微復(fù)雜的判斷物體躍的是那邊的界,偽代碼如下:

if(object.x - object.width/2 > right){
    object.x = left - object.widht/2;
}else if(object.x + object.width/2 < left){
    object.x = right + object.width/2;
}
if(object.y - object.height/2 > bottom){
    object.y = top - object.height/2;
}else if(object.y + object.height/2 < top){
    obejct.y = bottom + object.height/2;
}
反彈(粗略版)

這是較復(fù)雜的一種情況,屬于物體接觸到區(qū)域邊界就算越界的情況?;舅悸罚?/p>

檢查物體是否越過任意邊界;

如果發(fā)生越界, 立即將物體置回邊界;

反轉(zhuǎn)物體的速度向量的方向。

下面的示例是一個(gè)ball在畫布內(nèi)移動(dòng),撞到邊界就反彈,反彈核心代碼如下。
完整示例:反彈球(粗略版)

if (ball.x + ball.radius > right) {
  ball.x = right - ball.radius;
  vx *= -1;
} else if (ball.x - ball.radius < left) {
  ball.x = left + ball.radius;
  vx *= -1;
}
if (ball.y + ball.radius > bottom) {
  ball.y = bottom - ball.radius;
  vy *= -1;
} else if (ball.y - ball.radius < top) {
  ball.y = top + ball.radius;
  vy *= -1;
}
反彈(完美版)

咋看似乎效果不錯(cuò),但仔細(xì)想想,我們這樣將物體置回邊界的做法是準(zhǔn)確的嗎?
答案是否定的,理想反彈與實(shí)際反彈是不同的,如下圖:

從圖中我們可以清除的知道,ball實(shí)際上是不太可能會(huì)在理想反彈點(diǎn)反彈的,因?yàn)槿绻俣冗^大,計(jì)算位置時(shí)ball已經(jīng)越過“理想反彈點(diǎn)”到達(dá)“實(shí)際反彈點(diǎn)”,而我們?nèi)绻皇菍all的x軸坐標(biāo)簡(jiǎn)單粗暴移到邊界上,那還是不可能是“理想反彈點(diǎn)”,也就是說(shuō)這種反彈方法不準(zhǔn)確。
那么,完美反彈的思路就明確了,我們需要找到“理想反彈點(diǎn)”,并將ball置到該點(diǎn)。如果是左右邊越界,則算出"理想反彈點(diǎn)"與“實(shí)際反彈點(diǎn)”在y軸上的距離;如果是上下邊越界,則算出"理想反彈點(diǎn)"與“實(shí)際反彈點(diǎn)”在x軸上的距離。如圖,思路以左右邊越界為例:

由速度可求得物體的方向弧度angle;

算出"實(shí)際反彈點(diǎn)"和“理想反彈點(diǎn)”在x軸上的距離;

依據(jù)正切求"實(shí)際反彈點(diǎn)"和“理想反彈點(diǎn)”在y軸上的距離;

“理想反彈點(diǎn)”的y軸坐標(biāo)即是"實(shí)際反彈點(diǎn)"加上這段距離。

改造后的核心代碼如下,至于有沒有必要多做這么多運(yùn)算,這就要權(quán)衡性能和精密性了。
完整示例:反彈球(完美版)

if (ball.x + ball.radius > right) {
  const dx = ball.x - (right - ball.radius);
  const dy = Math.tan(angle) * dx;
  ball.x = right - ball.radius;
  ball.y += dy;
  vx *= bounce;
} else if (ball.x - ball.radius < left) {
  const dx = ball.x - (left + ball.radius);
  const dy = Math.tan(angle) * dx;
  ball.x = left + ball.radius;
  ball.y += dy;
  vx *= bounce;
}
if (ball.y + ball.radius > bottom) {
  const dy = ball.y - (bottom - ball.radius);
  const dx = dy / Math.tan(angle);
  ball.y = bottom - ball.radius;
  ball.x += dx;
  vy *= bounce;
} else if (ball.y - ball.radius < top) {
  const dy = ball.y - (top + ball.radius);
  const dx = dy / Math.tan(angle);
  ball.y = top + ball.radius;
  ball.x += dx;
  vy *= bounce;
}
碰撞檢測(cè)

和越界檢查很像,我們擴(kuò)展到兩個(gè)物體間的碰撞檢測(cè),一般常用的有如下兩種辦法。

基于幾何圖形的碰撞檢測(cè)

一般是用在檢測(cè)矩形的碰撞,原理就是判斷一個(gè)物體是否和另一個(gè)物體有重疊。
下面直接給出兩個(gè)檢測(cè)的工具函數(shù)。完整示例:

兩個(gè)矩形碰撞檢測(cè)演示

矩形與點(diǎn)碰撞檢測(cè)演示

// 兩個(gè)矩形碰撞檢測(cè)
function intersects(rectA, rectB) {
  return !(rectA.x + rectA.width < rectB.x ||
    rectB.x + rectB.width < rectA.x ||
    rectA.y + rectA.height < rectB.y ||
    rectB.y + rectB.height < rectA.y);
};
// 矩形與點(diǎn)碰撞檢測(cè)
function containsPoint(rect, x, y) {
  return !(x < rect.x || x > rect.x + rect.width || y < rect.y || y > rect.y + rect.height);
};
基于距離的碰撞檢測(cè)

一般是用在檢測(cè)圓形的碰撞,原理就是判斷兩個(gè)物體是否足夠近到發(fā)生碰撞。
對(duì)于圓來(lái)說(shuō),只要兩個(gè)圓心距離小于兩圓半徑之和,那我們就可判定為碰撞。圓心距離可通過勾股定理求得。核心代碼如下:
完整示例:兩圓基于距離的碰撞演示

const dx = ballB.x - ballA.x;
const dy = ballB.y - ballA.y;
const dist = Math.sqrt(dx ** 2 + dy ** 2);

if (dist < ballA.radius + ballB.radius) {
  log.value = "Hit!";
} else {
  log.value = "";
}

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93735.html

相關(guān)文章

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

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

    寵來(lái)也 評(píng)論0 收藏0
  • 30分鐘學(xué)完canvas動(dòng)畫|游戲基礎(chǔ)(7):動(dòng)量守恒多物體碰撞

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

    Dr_Noooo 評(píng)論0 收藏0
  • 30分鐘學(xué)完canvas動(dòng)畫|游戲基礎(chǔ)(7):動(dòng)量守恒多物體碰撞

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

發(fā)表評(píng)論

0條評(píng)論

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