2011-11-05 15 views
6

Buduję grę w Javascript przy użyciu kanwy, która wymaga wykrycia kolizji, w tym przypadku, jeśli gracz sprite trafi w pudło, gracz nie może wejść przez to pole.Wykrywanie kolizji JavaScriptu na płótnie

Mam globalną tablicę o nazwie blockList, która przechowuje wszystkie pola, które są rysowane na płótnie. Wygląda to tak:

var blockList = [[50, 400, 100, 100]]; 

A oni są rysowane na płótnie tak:

c.fillRect(blockList[0][0], blockList[0][1], blockList[0][2], blockList[0][3]); 

Mam też przedmiot gracz, który posiada metodę aktualizacji oraz sposób rysowania. Aktualizacja ustala pozycję gracza na podstawie wejścia klawiatury itp., A rysowanie jest używane przez główną pętlę gry, aby narysować gracza na płótnie. Odtwarzacz jest przygotowywana tak:

this.draw = function(timestamp) { 
     if(this.state == "idle") { 
      c.drawImage(this.idleSprite, this.idleSprite.frameWidth * this.idleSprite.frameCount, 0, this.idleSprite.frameWidth, this.idleSprite.frameHeight, this.xpos, this.ypos, this.idleSprite.frameWidth, this.idleSprite.frameHeight); 
      if(timestamp - this.lastDraw > this.idleSprite.updateInterval) { 
       this.lastDraw = timestamp; 
       if(this.idleSprite.frameCount < this.idleSprite.frames - 1) { this.idleSprite.frameCount++; } else { this.idleSprite.frameCount = 0; } 
      } 
     } else if(this.state == "running") { 
      var height = 0; 
      if(this.facing == "left") { height = 37; } 
      c.drawImage(this.runningSprite, this.runningSprite.frameWidth * this.runningSprite.frameCount, height, this.runningSprite.frameWidth, this.runningSprite.frameHeight, this.xpos, this.ypos, this.runningSprite.frameWidth, this.runningSprite.frameHeight); 
      if(timestamp - this.lastDraw > this.runningSprite.updateInterval) { 
       this.lastDraw = timestamp; 
       if(this.runningSprite.frameCount < this.runningSprite.frames - 1) { this.runningSprite.frameCount++; } else { this.runningSprite.frameCount = 0; } 
      } 
     } 
    } 

Teraz, gracz ma pewne właściwości, będące player.xposplayer.ypos, player.width, player.height. Te same właściwości istnieją dla bloków. Więc mam wszystko, czego potrzebuję, aby wprowadzić wykrywanie kolizji, po prostu nie mam pojęcia, jak to zrobić. Próbowałem robić takie rzeczy jak:

if(player.x > blockList[0][0] && player.y > blockList[0][1]) 

, ale daleki od ideału lub grywalnej.

Czy ktoś zna prostą metodę lub funkcję, aby móc zwrócić wartość true lub false na podstawie tego, czy dwa obiekty kolidują ze sobą?

Odpowiedz

8

użyć następującą funkcję wykrywania kolizji pomiędzy dwoma prostokątami:

rect_collision = function(x1, y1, size1, x2, y2, size2) { 
    var bottom1, bottom2, left1, left2, right1, right2, top1, top2; 
    left1 = x1 - size1; 
    right1 = x1 + size1; 
    top1 = y1 - size1; 
    bottom1 = y1 + size1; 
    left2 = x2 - size2; 
    right2 = x2 + size2; 
    top2 = y2 - size2; 
    bottom2 = y2 + size2; 
    return !(left1 > right2 || left2 > right1 || top1 > bottom2 || top2 > bottom1); 
}; 

ten określa, czy dwa kwadraty, wyśrodkowane (x1, y1) i (x2, y2), o boku długości 2*size1 i 2*size2 odpowiednio pokrywają się. Zmiana definicji definicji prostokąta, a nie tylko kwadratów i użycie innego formatu danych, powinna być łatwa.

szczególności left1 jest lewa strona pierwszego kwadratu, right1 prawej itp Należy zauważyć, że w swoim układzie współrzędnych, oś y jest odwrócony (top1 < bottom1).

2

Chcesz się tylko dowiedzieć, czy dwa prostokąty zachodzą na siebie?

Oto kuloodporny funkcja dla Ciebie:

// returns true if there is any overlap 
// params: x,y,w,h of two rectangles 
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) { 
    if (w2 !== Infinity && w1 !== Infinity) { 
    w2 += x2; 
    w1 += x1; 
    if (isNaN(w1) || isNaN(w2) || x2 > w1 || x1 > w2) return false; 
    } 
    if (y2 !== Infinity && h1 !== Infinity) { 
    h2 += y2; 
    h1 += y1; 
    if (isNaN(h1) || isNaN(y2) || y2 > h1 || y1 > h2) return false; 
    } 
    return true; 
} 

Jeśli program może być pewien, że numery zawsze będzie skończony można użyć prostszej wersji:

// returns true if there is any overlap 
// params: x,y,w,h of two rectangles 
function intersects(x1, y1, w1, h1, x2, y2, w2, h2) { 
    w2 += x2; 
    w1 += x1; 
    if (x2 > w1 || x1 > w2) return false; 
    h2 += y2; 
    h1 += y1; 
    if (y2 > h1 || y1 > h2) return false; 
    return true; 
} 

Co jej działanie jest znajdując miejsce po prawej i dolnej stronie dwóch prostokątów, wtedy widzi, czy drugi zaczyna się poza pierwszym, czy też pierwszy zaczyna się poza drugim.

Jeśli prostokąt zaczyna się po zakończeniu drugiego, oznacza to, że nie ma kolizji. W przeciwnym razie musi nastąpić kolizja.

0

Moim zdaniem nie jestem fanem funkcji, które wymagają wielu parametrów.

Oto jak zrobiłbym to:

function collisionCheckRectRect(rectOne, rectTwo){ 

    var x1=rectOne.x, y1 = rectOne.y, height1 = rectOne.height, width1 = rectOne.width; 
    var x2=rectTwo.x, y2 = rectTwo.y, height2 = rectTwo.height, width2 = rectTwo.width; 

    return x1 < x2+width2 && x2 < x1+width1 && y1 < y2+height2 && y2 < y1+height1; 
} 
Powiązane problemy