if(ball.x > canvas.width){
console.log('超出了右邊界');
}else if(ball.x < 0){
console.log('超出了左邊界');
};
if(ball.y > canvas.height){
console.log('超出了下邊界');
}else if(ball.y < 0){
console.log('超出了上邊界');
};
if( ball.x < x1 ){
console.log('物體超出了左邊界');
}else if( ball.x > x2){
console.log('物體超出了右邊界');
};
if( ball.y < y1 ){
console.log('物體超出了上邊界');
}else if( ball.y > y2){
console.log('物體超出了下邊界');
};
if( ball.x < (x1 - ball.radius)){
console.log('物體完全越出了左邊界');
};
大多數(shù)情況下,我們不是單純的檢測物體是否越界,而是為了在物體越界后進行某些操作,當(dāng)然,你也可以在物體越界后不做任何操作,不過這不是我們所推薦的。
當(dāng)物體越界時,一般我們會進行以下4中選擇操作:
1.2 移除物體
移除物體多用在多個物體在canvas上移動時,這時,我們一般將它們的引用保存到一個數(shù)組中,再通過遍歷整個數(shù)組的來移動它們(前面的例子,我都是采取這種方式),這樣,我們就可以使用 Array.splice 方法來移除數(shù)組中的某個物體了。
var balls = []; // 存放多個物體的數(shù)組
var ball = balls[i];
if(ball.x < x1 || ball.x > x2 || ball.y < y1 || ball.y > y2){
balls.splice(balls.indexof(ball),1);
i -= 1;
}
上面的檢測越界條件是和檢測在邊界內(nèi)的條件是不一樣的。
注意:當(dāng)你使用 Array.splice 方法在循環(huán)中移除元素后,需要加上 i -= 1,不然后續(xù)循環(huán)會出問題。當(dāng)然,你也可以使用反向遍歷,就不會存在這問題:
var i = balls.length;
while( i-- ){
if(ball.x < x1 || ball.x > x2 || ball.y < y1 || ball.y > y2){
balls.splice(balls.indexof(ball),1);
}
}
1.3 重置物體
重置物體其實就是重新設(shè)置物體的位置坐標。
在下面的例子,你會看到一個物體從上向下落下,當(dāng)它離開canvas后,又有一個物體在同一個位置開始從上向下落下,看起來是不同的物體,其實是同一個,只不過每次它離開canvas后,都將它的 ball.y 設(shè)置為原始值,在這里是0。
1.4 屏幕環(huán)繞
屏幕環(huán)繞的意思是當(dāng)物體從屏幕左邊移出,它就會在屏幕右邊再次出現(xiàn);當(dāng)物體從屏幕上方移出,它又會出現(xiàn)在屏幕下方,反之亦然。
屏幕環(huán)繞和重置物體類似,都遵循著同一個物體的原則,只不過屏幕環(huán)繞是讓其從一邊出再從相反的一邊進而已。
1.5 反彈
在讓物體反彈之前,你需要檢測物體何時離開屏幕,當(dāng)它剛要離開時,要保持它的位置不變而僅改變它的速度向量,也可以說是速度值取反。
在檢測何時反彈時,有一點需要注意,我們不能等到物體完全移出canvas才開始反彈,這顯然和現(xiàn)實不符合,不知道你有沒有玩過足球,當(dāng)你將足球踢向墻壁時,你會看到球在撞墻后,停在那里并很快反彈回來。
當(dāng)物體移到如下圖位置,物體就要開始反彈:
if( ball.x <= (x1 + ball.radius)){
ball.x = x1 + ball.width;
ball.speed.x *= -1;
}
在上面的代碼中,我們將 -1 作為反彈系數(shù),不過在現(xiàn)實中,反彈的速度總是會有所減小,這是因為能量損失,所以為了模擬更真實的動畫,你可以將 -1 乘以一個百分比來實現(xiàn)能量損耗的效果。
ball.speed.x *= -0.8;
反彈的步驟如下:
簡單例子:
2、摩擦力(friction)
摩擦力,又一物理概念,也可稱為阻力,指兩個互相接觸的物體,當(dāng)它們要發(fā)生或已經(jīng)發(fā)生相對運動時,就會在接觸面上產(chǎn)生一種阻礙相對運動的力。
上面是概念式的說法,簡單的講,摩擦力就是阻止你運動的力,它并不會改變你運動的方向,而只會讓你慢慢減速,直至速度為0。
如果想讓動畫更加真實,很多時候我們都需要考慮摩擦力,那如何用代碼實現(xiàn)呢?
(1)精確方法
上面也說到,摩擦力是阻止你運動的力,這就意味著,可以用速度向量減去摩擦力。更準確地說,只能沿著速度向量的方向減去與摩擦力相等的大小,而不能分別在x、y軸上減小速度向量,也可以這樣理解,摩擦力必須與合速度相減,然后再根據(jù)減后的合速度分別求出x、y軸上的最終速度。
如下方式:
var v = Math.sqrt( vx * vx + vy * vy );
var angle = Math.atan2(vy,vx);
if(v > f){
v -= f;
}else{
v = 0;
};
vx = Math.cos(angle) * v;
vy = Math.sin(angle) * v;
(2)約等方法
約等方法是指將x、y軸上的速度向量乘以一個百分數(shù),一個接近0.9的系數(shù)能很好的模擬出摩擦力的效果。
vx *= f;
vy *= f;
使用這種方法的好處就是不必去做條件判斷,但它只能無限接近于0,不過由于JavaScript的精度約束,最后的結(jié)果也會變?yōu)?。
在上面的反彈中,反彈系數(shù)也是用這種方法。
總結(jié)
附錄
重要公式:
(1)檢測是否越界
if( object.x - object.width / 2 > right ||
object.x + object.width / 2 < left ||
object.y - object.height / 2 > bottom ||
object.y + object.height / 2 < top){}
(2)摩擦力(精度方法)
var v = Math.sqrt( vx * vx + vy * vy );
var angle = Math.atan2(vy,vx);
if(v > f){
v -= f;
}else{
v = 0;
};
vx = Math.cos(angle) * v;
vy = Math.sin(angle) * v;
(3)摩擦力(約等方法)
vx *= friction;
vy *= friction;
下一章:移動物體
更多建議: