1

我正在用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每次迭代執行以下步驟:

  1. 我計算磚的最下排的電平(brick.height *行); 和每次我移動球(我簡單地通過ball.x +=ball.xVelocity; ball.y+=ball.yVelocity;順便說一句),我檢查球的'y'座標是否小於這個bricksLevel。 - >
  2. 如果檢查步驟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++; 
    } 
    
  3. 內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當談到磚的頂部邊緣?上方有什麼特別的?請給我一些提示,可能是什麼。我在這裏死去。

+0

'delta'似乎受'isPaused以不透明的方式。我的意思是,你暫停時不更新,但不停止時間?那會導致巨大的跳躍(通過牆?)! – Bergi

+0

我看不出它是如何與碰撞檢測相關的問題 – dKab

+0

第一個碰撞檢測算法更好,因爲它是影響球的方向的因素。 –

回答

-1
if (ball.yVelocity > 0 && !brick.above && !brick.isUpper() && ball.bottom >= brick.y && ball.x <= brick.right && ball.right >= brick.x) { 
    console.log('top ' + brick.color); 
    ball.yVelocity = -ball.yVelocity; 
    //ball.y -= brick.y-ball.bottom; 
    //ball.y = Math.max(ball.x,0); 
    ball.y = brick.y - ball.height; 
    brick.collide(ball); 
    return true; 
} 
if (ball.yVelocity < 0 && !brick.below && ball.y <= brick.bottom && ball.center <= brick.right && ball.center >= brick.x) { 
    console.log('bot ' + brick.color); 

    ball.yVelocity = -ball.yVelocity; 
    //ball.y = brick.bottom + (brick.bottom - ball.y); 
    ball.y = brick.bottom; 
    brick.collide(ball); 
    return true; 
} 

爲什麼brick.x ball.center和brick.right在y collison中檢查?

+0

>爲什麼brick.x ball.center和brick.right在y collison中檢查? 要確保球實際上擊中了磚塊,但不僅碰巧處於相同的「y」級別。 – dKab

+0

第二個if語句是否在y方向檢查?爲什麼在它裏面有brick.x和brick.right –

+0

這4個if語句中的每一個都檢查球是否碰到了矩形的特定邊。第一個 - 頂部,第二個底部 – dKab

1

Heureka!我發現它在CollisionResolver.prototype.conduct

rowBot = Math.floor(ball.bottom/height) 

您需要圍捕爲rowBot:

rowBot = Math.ceil(ball.bottom/height) 

http://jsfiddle.net/78NJ6/8/

另外:

您需要重置球的x座標當它從牆上反彈或它可能會「卡」在牆上。 (發生這種情況是因爲它在撞擊牆時移動到牆上,x速度下降,因此它在下一步移動時不會再移出。)