2011-11-05 2 views
6

Sto costruendo un gioco in Javascript usando la tela che richiede il rilevamento delle collisioni, in questo caso se il giocatore sprite colpisce una scatola, il giocatore non deve essere autorizzato a entrare nella scatola.Rilevazione collisione canvas JavaScript

Ho un array globale chiamato blockList che contiene tutte le caselle che vengono disegnate nell'area di disegno. Ecco come si presenta:

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

e sono in fase di elaborazione sulla tela come questo:

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

Ho anche un oggetto giocatore, che ha un metodo di aggiornamento e un metodo draw. L'aggiornamento imposta la posizione del giocatore in base all'input della tastiera, ecc. E draw viene utilizzato dal ciclo di gioco principale per disegnare il giocatore sulla tela. Il giocatore è in corso di elaborazione in questo modo:

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; } 
      } 
     } 
    } 

Ora, il giocatore ha alcune proprietà che sono player.xpos, player.ypos, player.width, player.height. Le stesse proprietà esistono per i blocchi. Quindi ho tutto ciò di cui ho bisogno per impiantare il rilevamento delle collisioni, non ho proprio idea di come farlo. Ho provato a fare cose del tipo:

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

ma è tutt'altro che perfetto o giocabile.

Qualcuno sa di un semplice metodo o funzione per essere in grado di restituire vero o falso in base a se due oggetti sono in collisione?

risposta

8

Io uso la seguente funzione di rilevamento di collisione tra due rettangoli:

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); 
}; 

Questo determina se due piazze, centrati (x1, y1) e (x2, y2), con il lato lunghezze 2*size1 e 2*size2, rispettivamente, sono sovrapposte. Dovrebbe essere abbastanza semplice modificare le definizioni di left1, right1, ecc. Per trattare i rettangoli generali anziché solo i quadrati e utilizzare un formato di dati diverso.

particolare, left1 è il lato sinistro del primo quadrato, right1 destra, ecc Si noti che, nel mio sistema di coordinate, l'asse y è invertito (top1 < bottom1).

2

Vuoi solo sapere se due rettangoli si sovrappongono?

Ecco una funzione a prova di proiettile per voi:

// 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; 
} 

Se il programma può essere certi che i numeri saranno sempre finito è possibile utilizzare una versione più semplice:

// 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; 
} 

Che il suo fare è trovando dove sono il lato destro e il lato inferiore dei due rettangoli, allora vede se il secondo inizia al di fuori del primo o se il primo inizia al di fuori del secondo.

Se uno dei due rettangoli inizia dopo che l'altro è terminato, non c'è collisione. Altrimenti ci deve essere una collisione.

0

A mio parere, non sono un fan delle funzioni che richiedono molti parametri.

Ecco come lo farei:

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; 
}