在第二章《
用戶交互》中,介紹過(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)。
更多建議: