canvas動(dòng)畫包教不包會(huì):移動(dòng)物體

2018-06-19 15:23 更新
      在第二章《用戶交互》中,介紹過(guò)鼠標(biāo)事件和觸摸事件,可是到目前為止,我們用到鼠標(biāo)事件和觸摸事件還比較少,在本章中,我們將真正的進(jìn)入交互動(dòng)畫中,主要介紹下面的內(nèi)容:
  • 如何判斷鼠標(biāo)是否落在某一個(gè)物體上
  • 拖曳物體
  • 投擲物體

1、鼠標(biāo)事件和觸摸事件
在介紹三種交互動(dòng)畫前,我們先來(lái)回顧一下鼠標(biāo)事件和觸摸事件。

1.1 鼠標(biāo)事件
要觸發(fā)鼠標(biāo)事件,當(dāng)然得有觸發(fā)它的設(shè)備,不能光用眼睛盯著屏幕, 而觸發(fā)鼠標(biāo)事件的設(shè)備當(dāng)然是鼠標(biāo),它會(huì)檢測(cè)自身的移動(dòng)以及按鈕是否單擊,隨后計(jì)算機(jī)會(huì)觸發(fā)一系列的事情:追蹤鼠標(biāo)指針的位置,確定鼠標(biāo)按鈕被按下時(shí)指針的位置,計(jì)算鼠標(biāo)的移動(dòng)速度以及確定何時(shí)發(fā)生雙擊事件等等。

簡(jiǎn)單的來(lái)說(shuō),鼠標(biāo)要做的事就是 單擊 移動(dòng) 。

單擊事件又可分解為兩個(gè)事件: 鼠標(biāo)鍵按下 的事件及 按鍵彈起 的事件,大多數(shù)情況下,這兩個(gè)事件是同時(shí)發(fā)生的,但鼠標(biāo)要做的例外一個(gè)事 移動(dòng) 時(shí),在這兩個(gè)事件之間還會(huì)多了一個(gè)事件: 按下、移動(dòng)、再釋放

在《用戶交互》這一章曾經(jīng)說(shuō)過(guò),我們無(wú)法捕捉到canvas上的任何繪制圖形、線等,所以我們只能將事件綁定到canvas元素上,然后通過(guò)計(jì)算鼠標(biāo)相對(duì)于canvas元素的坐標(biāo)來(lái)判斷鼠標(biāo)落在哪個(gè)繪制到canvas上的物體上。

下面我們就來(lái)講解一下如何判斷鼠標(biāo)是否落在某一個(gè)物體(比如前面我們多次繪制的ball)上。
還是用圖來(lái)分析:


如上圖所示,一般情況下,當(dāng)要檢測(cè)鼠標(biāo)是否落在物體上時(shí),我們會(huì)將物體放置在一個(gè)矩形區(qū)域(圖中的紅框)內(nèi),該矩形區(qū)域也稱為物體的邊界,然后通過(guò)獲取鼠標(biāo)位置,判斷是否落在矩形區(qū)域內(nèi)即可。

當(dāng)然,你要捕捉的物體必須有x、y、width與height屬性(不管是直接獲取還是計(jì)算得出),前面我們已經(jīng)知道如何獲取鼠標(biāo)相對(duì)canvas的坐標(biāo)了,接下來(lái)往tool對(duì)象中添加一個(gè)方法 containsPoint() ,該函數(shù)接受三個(gè)參數(shù),第一個(gè)是物體(body)對(duì)象(包括x、y、width與height屬性),第二個(gè)和第三個(gè)參數(shù)則分別代表鼠標(biāo)位置,返回值為true或false,判斷一個(gè)指定的坐標(biāo)位置是否位于矩形邊界內(nèi)。

tool.containsPoint = function(body, x, y){

  return !(x < body.x || x > (body.x + body.width) 

         || y < body.y || y > (body.y + body.height));

};

containsPoint()方法返回false表示不在矩形邊界內(nèi),否則在矩形邊界內(nèi)。

將物體包裹在一個(gè)矩形之內(nèi),這是我們大多數(shù)情況下采取的方法,如果你想更加精確,那就要進(jìn)行更加精確的計(jì)算了,比如:物體是圓形,那你就要使用三角函數(shù)來(lái)計(jì)算鼠標(biāo)位置和圓心的距離:

dx = point.x -body.x; dy = point.y - body.y; dist = Math.sqrt(dx*dx + dy*dy) if(dist < body.radius){  

    console.log('鼠標(biāo)移到物體上');

 }


實(shí)例:


1.2 觸摸事件
捕獲觸摸事件與捕獲鼠標(biāo)事件并沒(méi)有太大的區(qū)別,在tool.captureMT()方法中,我已經(jīng)將觸摸事件和鼠標(biāo)事件封裝在了一起。

與鼠標(biāo)事件不同的是,要觸發(fā)觸摸事件的不是鼠標(biāo),而是手指、觸摸筆等等,而且鼠標(biāo)會(huì)一直都在,而手指卻不是一直處在觸摸狀態(tài),所以添加一個(gè)isPressed屬性,用于判斷屏幕上是否有手指在觸摸。

var isPressed = false;

function touchstart(event){

  isPressed = true;   //

};

function touchend(event){

  isPressed = false;

};


2、移動(dòng)物體
2.1. 拖曳物體
拖曳物體其實(shí)就是通過(guò)不斷更新物體的坐標(biāo)位置使其追隨鼠標(biāo)指針的位置。

拖曳圓球看看:


關(guān)鍵代碼:

ball.x = event.point.x;   

ball.y = event.point.y;


2.2 投擲物體
投擲物體就是用鼠標(biāo)選中一個(gè)物體,拖曳著它向某個(gè)方向移動(dòng),松開(kāi)鼠標(biāo)后,物體沿著拖曳的方向繼續(xù)移動(dòng)。

在投擲物體時(shí),必須在拖曳物體的過(guò)程中計(jì)算物體的速度向量,并在釋放物體時(shí)將這速度向量賦給物體。比如,如果你以每幀10個(gè)像素的速度向左拖曳小球,那么在你釋放球時(shí),它的速度向量應(yīng)該是vx = -10。

那么如何計(jì)算出物體被拖曳時(shí)的速度向量,只需按照如下計(jì)算:

速度向量 = 新的位置 - 舊的位置。

在動(dòng)畫中,我們以幀為單位,所以時(shí)間也可以說(shuō)是幀數(shù)。在拖曳物體時(shí),它會(huì)在每一幀擁有一個(gè)新的位置,用當(dāng)前幀的位置減去上一幀的位置,就可以計(jì)算出這一幀所移動(dòng)的距離,這也就是每幀移動(dòng)像素的速度向量值。

實(shí)例:
拖曳物體,然后松開(kāi)鼠標(biāo)看看效果:


關(guān)鍵代碼:

ball.speed.x = ball.x - oldX;   

ball.speed.y = ball.y - oldY;   

oldX = ball.x;   

oldY = ball.y;

用小球當(dāng)前的x、y軸坐標(biāo)分別減去oldX與oldY,從而獲得小球當(dāng)前的速度向量,并將它們保存在球的速度中,最后將oldX與oldY變量更新為小球當(dāng)前的位置。

總結(jié)
在這一章中,我們進(jìn)一步了解了動(dòng)畫中的交互行為。掌握上面這些內(nèi)容,你就可以在動(dòng)畫中實(shí)現(xiàn)對(duì)物體的拖曳、釋放以及投資。

到目前為止,《canvas動(dòng)畫包教不包會(huì)》系列已經(jīng)進(jìn)行了七章,分別介紹了用戶交互、三角函數(shù)、速度與加速度、邊界和摩擦力、移動(dòng)物體,這些是動(dòng)畫的基礎(chǔ)知識(shí),要想輕松的實(shí)現(xiàn)豐富的動(dòng)畫,就必須好好掌握這些。

從下一章開(kāi)始,將進(jìn)入高級(jí)動(dòng)畫,緩動(dòng)和彈動(dòng)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)