2016-05-12 9 views
0

現在、私はピンボールゲームでHTML5キャンバスとJavaScriptを使用しています。今、私はフリッパーのために基本的な画素衝突によって、苦労しています。ピクセルごとの衝突検出ピンボール

今の私のバウンディングボックスの衝突は、私が1画素でピクセルを実現するためのいくつかの方法を試してみたが、何らかの理由でそれが画像に、壁に(完全には機能しません

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:// stackoverflowの。 com/a/36026906/3877726には、非常に高速で様々な不規則なスプライト形状に適応するメソッドがあります。それ自体で曲がらない形に限られています。少しの初期化コードが必要ですが、衝突テストはソフトウェアベースのピクセル衝突テストよりもずっと速く、パフォーマンスの円/ボックス衝突に匹敵します – Blindman67

答えて

1

が2つの円弧と2つのラインで構成され、むしろよりも、数学的に衝突検出を行うためにはるかに高速になりますはるかに遅いピクセルテスト方法です。それでは、4回の数学的衝突テストが必要です。

あなたのフリッパーがアーク+ラインよりも少し複雑であっても、数学ヒットテストは「十分に良い」と言えます。つまり、動きの速いゲームでは、ユーザーは視覚的におよその数学結果をピクセル2種類のテストの違いはゲームプレイにはまったく影響しません。しかし、ピクセルテスト版は、達成するために、より多くの時間とリソースを要するだろう。 ;-)

第2の円-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); 
} 

次に、2つの円-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

これは良いアイデアですが、残念なことに要件の1つはピクセルピンボールマシンを構成するすべてのタイプのオブジェクトで動作するピクセル単位の衝突アプローチです。申し訳ありません、私はそれを以前言及すべきでした! –

+0

**もう一度やり直してください** **しかし、すべてのバンパーなどが線や円弧で構成されているわけではありません。数学テストは、ピクセルテストと同じくらい効果的です。ピクセルヒットテストに影響を与えるアンチエイリアスをさらに考慮する必要があります。 – markE

+0

これをスプライトにどのように適応させることができますか? @PedroCaseiro。 –