2016-05-12 45 views
0

我目前正在使用HTML5 Canvas和JavaScript製作彈球遊戲。目前,我正在逐像素碰撞遇到困難,這是由於腳蹼造成的。像素逐像素碰撞檢測彈球

現在我包圍盒的碰撞似乎是工作

checkCollision(element) { 
    if (this.checkCollisionBoundingBox(element)) { 
     console.log("colision with the element bounding box"); 

     if (this.checkCollisionPixelByPixel(element)) { 
      return true; 
     } else { 
      return false; 
     } 
    } else { 
     return false; 
    } 
} 

checkCollisionBoundingBox(element) { 
    if (this.pos.x < element.pos.x + element.width && this.pos.x + this.width > element.pos.x && this.pos.y < element.pos.y + element.height && this.pos.y + this.height > element.pos.y) { 
      return true; 
    } else { 
      return false; 
     } 
    } 

我試圖通過像素之一,但由於某種原因,它不能很好地工作落實像素的幾種方法(在牆壁上的圖像,精靈等)。我把它們放在這兒:

checkCollisionPixelByPixel(element) { 
     var x_left = Math.floor(Math.max(this.pos.x, element.pos.x)); 
     var x_right = Math.floor(Math.min(this.pos.x + this.width, element.pos.x + element.width)); 
     var y_top = Math.floor(Math.max(this.pos.y, element.pos.y)); 
     var y_bottom = Math.floor(Math.min(this.pos.y + this.height, element.pos.y + element.height)); 

     for (var y = y_top; y < y_bottom; y++) { 
      for (var x = x_left; x < x_right; x++) { 
       var x_0 = Math.round(x - this.pos.x); 
       var y_0 = Math.round(y - this.pos.y); 
       var n_pix = y_0 * (this.width * this.total) + (this.width * (this.actual-1)) + x_0; //n pixel to check 
       var pix_op = this.imgData.data[4 * n_pix + 3]; //opacity (R G B A) 

       var element_x_0 = Math.round(x - element.pos.x); 
       var element_y_0 = Math.round(y - element.pos.y); 
       var element_n_pix = element_y_0 * (element.width * element.total) + (element.width * (element.actual-1)) + element_x_0; //n pixel to check 
       var element_pix_op = element.imgData.data[4 * element_n_pix + 3]; //opacity (R G B A) 
       console.log(element_pix_op); 
       if (pix_op == 255 && element_pix_op == 255) { 

        console.log("Colision pixel by pixel"); 
        /*Debug*/ 
        /*console.log("This -> (R:" + this.imgData.data[4 * n_pix] + ", G:" + this.imgData.data[4 * n_pix + 1] + ", B:" + this.imgData.data[4 * n_pix + 2] + ", A:" + pix_op + ")"); 
        console.log("Element -> (R:" + element.imgData.data[4 * element_n_pix] + ", G:" + element.imgData.data[4 * element_n_pix + 1] + ", B:" + element.imgData.data[4 * element_n_pix + 2] + ", A:" + element_pix_op + ")"); 
        console.log("Collision -> (x:" + x + ", y:" + y +")"); 
        console.log("This(Local) -> (x:" + x_0 + ", y:" + y_0+")"); 
        console.log("Element(Local) -> (x:" + element_x_0 + ", y:" + element_y_0+")");*/ 
        /*ball vector*/ 
        var vector = { 
         x: (x_0 - Math.floor(this.imgData.width/2)), 
         y: -(y_0 - Math.floor(this.imgData.height/2)) 
        }; 
        //console.log("ball vector -> ("+vector.x+", "+vector.y+") , Angulo: "+ Math.atan(vector.y/vector.x)* 180/Math.PI); 

        // THIS WAS THE FIRST TRY, IT DIDN'T WORK WHEN THE BALL WAS GOING NORTHEAST AND COLLIDED WITH A WALL. DIDN'T WORK AT ALL WITH SPRITES 
        //this.angle = (Math.atan2(vector.y, vector.x) - Math.PI) * (180/Math.PI); 


        // THIS WAS THE SECOND ATTEMPT, WORKS WORSE THAN THE FIRST ONE :/ 
        //normal vector 
        var normal = { 
         x: (x_0 - (this.imgData.width/2)), 
         y: -(y_0 - (this.imgData.height/2)) 
        }; 
        //Normalizar o vetor 
        var norm = Math.sqrt(normal.x * normal.x + normal.y * normal.y); 
        if (norm != 0) { 
         normal.x = normal.x/norm; 
         normal.y = normal.y/norm; 
        } 
        var n_rad = Math.atan2(normal.y, normal.x); 
        var n_deg = (n_rad + Math.PI) * 180/Math.PI; 
        console.log("Vetor Normal -> (" + normal.x + ", " + normal.y + ") , Angulo: " + n_deg); 
        //Vetor Velocidade 
        var velocity = { 
         x: Math.cos((this.angle * Math.PI/180) - Math.PI), 
         y: Math.sin((this.angle * Math.PI/180) - Math.PI) 
        }; 
        console.log("Vetor Velocidade -> (" + velocity.x + ", " + velocity.y + ") , Angulo: " + this.angle); 
        //Vetor Reflexao 
        var ndotv = normal.x * velocity.x + normal.y * velocity.y; 
        var reflection = { 
         x: -2 * ndotv * normal.x + velocity.x, 
         y: -2 * ndotv * normal.y + velocity.y 
        }; 
        var r_rad = Math.atan2(reflection.y, reflection.x); 
        var r_deg = (r_rad + Math.PI) * 180/Math.PI; 
        console.log("Vetor Reflexao -> (" + reflection.x + ", " + reflection.y + ") , Angulo: " + r_deg); 

        this.angle = r_deg; 


        return true; 
       } 
      } 
     } 
     return false; 
    } 
} 

class Ball extends Element { 
    constructor(img, pos, width, height, n, sound, angle, speed) { 
     super(img, pos, width, height, n, sound); 
     this.angle = angle; //direction [0:360[ 
     this.speed = speed; 
    } 
    move(ctx, cw, ch) { 
     var rads = this.angle * Math.PI/180 
     var vx = Math.cos(rads) * this.speed/60; 
     var vy = Math.sin(rads) * this.speed/60; 

     this.pos.x += vx; 
     this.pos.y -= vy; 

     ctx.clearRect(0, 0, cw, ch); 
     this.draw(ctx, 1); 
    } 
} 
+1

這個答案的http://計算器。 com/a/36026906/3877726有一個非常快速的方法,可以適應各種不規則的精靈形狀。它僅限於不會彎曲的形狀。它需要一些init代碼,但碰撞測試的速度比任何基於軟件的像素碰撞測試快很多,相當於性能上的圓圈/箱體碰撞 – Blindman67

回答

1

假設一個「腳蹼」由2個圓弧和2號線的球會快得多做碰撞檢測數學,而不是由更慢的像素測試方法。那麼你只需要4次數學碰撞測試。

即使你的腳蹼比弧線更復雜,數學命中測試也會「足夠好」 - 這意味着在快速移動的遊戲中,用戶無法直觀地注意到像素與像素的近似數學結果 - 完美的結果和兩種測試之間的差異不會影響遊戲性。但像素測試版本將需要更多的時間和資源來完成。 ;-)

前兩個圓圈VS圈碰撞測試:

function CirclesColliding(c1,c2){ 
    var dx=c2.x-c1.x; 
    var dy=c2.y-c1.y; 
    var rSum=c1.r+c2.r; 
    return(dx*dx+dy*dy<=rSum*rSum); 
} 

然後兩圈-VS線段碰撞測試:

// [x0,y0] to [x1,y1] define a line segment 
// [cx,cy] is circle centerpoint, cr is circle radius 
function isCircleSegmentColliding(x0,y0,x1,y1,cx,cy,cr){ 

    // calc delta distance: source point to line start 
    var dx=cx-x0; 
    var dy=cy-y0; 

    // calc delta distance: line start to end 
    var dxx=x1-x0; 
    var dyy=y1-y0; 

    // Calc position on line normalized between 0.00 & 1.00 
    // == dot product divided by delta line distances squared 
    var t=(dx*dxx+dy*dyy)/(dxx*dxx+dyy*dyy); 

    // calc nearest pt on line 
    var x=x0+dxx*t; 
    var y=y0+dyy*t; 

    // clamp results to being on the segment 
    if(t<0){x=x0;y=y0;} 
    if(t>1){x=x1;y=y1;} 

    return((cx-x)*(cx-x)+(cy-y)*(cy-y) < cr*cr); 
} 
+0

這是一個好主意,但不幸的是,其中一個要求是將像素這種方法適用於組成彈球機的所有類型的物體。對不起,我應該早點提到! –

+0

**最後一次嘗試...... **但不是所有的緩衝器等由線或弧組成。數學測試與像素測試一樣有效 - 可能更多考慮影響像素點擊測試的抗鋸齒。 – markE

+0

我如何適應這個精靈? –