我正在用javaScript寫一個Arkanoid克隆,並且遇到了球/磚碰撞的問題。這是我做的如何渲染(這可能是重要的,我不知道):爲什麼球通過磚塊飛行?
function Game() {
//...
this.fps = 60;
//...
}
Game.prototype.gameloop = function() {
var current = new Date().getTime(),
delta = current - this.lastRender;
if (delta >= this.delay && !this.paused) {
this.updateAll();
if (this.paused)
return;
this.drawAll();
this.lastRender = new Date().getTime();
}
this.loop = requestAnimationFrame(Game.prototype.gameloop.bind(this));
};
而且我通過簡單地調用this.gameloop();
開始這個循環在遊戲中構造。
我的碰撞檢測算法,該算法在我的gameloop每次迭代執行以下步驟:
- 我計算磚的最下排的電平(brick.height *行); 和每次我移動球(我簡單地通過
ball.x +=ball.xVelocity; ball.y+=ball.yVelocity;
順便說一句),我檢查球的'y'座標是否小於這個bricksLevel。 - > 如果檢查步驟1中返回 '真' 我找最接近的磚:
VAR嫌疑= bricks.slice:
var rowTop = Math.floor(ball.y/height), rowBot = Math.floor(ball.bottom/height), colLeft = Math.floor(ball.x/width), colRight = Math.floor(ball.right/width);
,如果他們從BricksCollection對象存在我得到這些磚([rowTop,rowBot], cols:[colLeft,colRight] }); 併爲他們每個人我申請我的球/磚碰撞檢測算法,直到它返回true(這意味着發生碰撞):
var i = 0; while ( suspects[i] && !this.detectBrickCollision(ball, suspects[i]) && i < suspects.length) { i++; }
內detectBrickCollision生活的代碼,實際確定是否發生與否,如果碰撞與塊的側面做。起初,我提出了比數學更合乎邏輯的方法。在連續四次
if
塊中,我檢查了矩形的每一邊是否有碰撞。這樣的:if (ball.yVelocity < 0 && !brick.below && ball.y <= brick.bottom && ball.center.x <= brick.right && ball.center.x >= brick.x) { ball.yVelocity = -ball.yVelocity; ball.y = brick.bottom; brick.collide(ball); return true; } if (//similar checks for other sides) //...
這就是它是如何工作的:http://jsfiddle.net/78NJ6/ 注意,球碰撞與磚的底側完全正常,並與左,右兩側合理的罰款,但糟糕的是頂級的一面,雖然各方面的邏輯幾乎一樣!例如這裏是頂級的側面碰撞校驗碼:
if (ball.yVelocity > 0 && !brick.above && !brick.isUpper() && ball.bottom >= brick.y && (ball.x <= brick.right || ball.right >= brick.x)) { ball.yVelocity = -ball.yVelocity; ball.y = brick.y - ball.height; brick.collide(ball); return true; }
現在,如果你嘗試了從你上面的小提琴可能已經注意到,在頂部碰撞的情況下,球遠遠低於上緣磚。有時它甚至會像底邊一樣發展。顯然,這不夠好。我看着其他方式來檢測碰撞,最終我碰到這個解決方案來:https://stackoverflow.com/a/1879223/3149635
我更換detectBrickCollision函數內部的代碼如下:
var intersects = this.intersects(ball, brick);
if (intersects) {
switch (intersects) {
case "top":
ball.y = brick.y-ball.height;
ball.yVelocity = - ball.yVelocity;
break;
case 'bottom':
ball.y=brick.bottom;
ball.yVelocity = -ball.yVelocity;
break;
case 'left':
ball.x = brick.x-ball.width;
ball.xVelocity = - ball.xVelocity;
break;
case 'right':
ball.x = brick.right;
ball.xVelocity = -ball.xVelocity;
break;
}
brick.collide(ball);
return true;
}
return false;
};
所有我放在函數的數學相交。我會在這裏顯示出它completenes,但它基本上是我在上面這個答案已經看到:
CollisionResolver.prototype.intersects = function(ball, brick) {
//find closest point on the rectangle's perimeter
var closestX = this.clamp(ball.center.x, brick.x, brick.right),
closestY = this.clamp(ball.center.y, brick.y, brick.bottom);
//calculate the distance between this closest point and circle's center
var dx = ball.center.x - closestX,
dy = ball.center.y - closestY;
//if the distance is less than circle's radius, an intersection occurs
var d = Math.sqrt((dx * dx) + (dy * dy));
if (d < ball.radius) {
//determin which side of rectangle collided
var side;
if (closestX === brick.x)
side = "left";
else if (closestX === brick.right)
side = 'right';
else if (closestY === brick.y)
side = 'top';
else if (closestY === brick.bottom)
side = 'bottom';
return side;
}
return false;
};
而且,儘管這被認爲是更精確利落,結果還是沒有那麼大。現在球仍然從底部反映出真實的情況,並且從正確的或者左邊的反應正常。頂級碰撞變得更糟。有時候,如果它來自上面,它會通過磚塊飛過。新版本:http://jsfiddle.net/X4MuW/
我很絕望。我無法得到它 - 爲什麼這兩種方法容易處理底部,右側,左側碰撞,但SUCK當談到磚的頂部邊緣?上方有什麼特別的?請給我一些提示,可能是什麼。我在這裏死去。
'delta'似乎受'isPaused以不透明的方式。我的意思是,你暫停時不更新,但不停止時間?那會導致巨大的跳躍(通過牆?)! – Bergi
我看不出它是如何與碰撞檢測相關的問題 – dKab
第一個碰撞檢測算法更好,因爲它是影響球的方向的因素。 –