2016-05-12 16 views
0

Ich arbeite gerade an einem Pinball Spiel mit HTML5 Canvas und JavaScript. Momentan fällt mir die Pixel-zu-Pixel-Kollision schwer, die wegen der Flipper grundlegend ist.Pixel für Pixel Kollisionserkennung Flipper

Gerade jetzt meine Bounding Box Kollision Arbeits

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

ich für Pixel ein, aber aus irgendeinem Grund, die Pixel der Umsetzung mehrere Möglichkeiten haben versucht, zu sein scheint es nicht perfekt funktioniert (an Wänden, auf Bilder, auf Sprites etc). Ich werde sie hier verlassen:

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

Der Ball Klasse

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

Diese Antwort http: // Stackoverflow. com/a/36026906/3877726 hat eine Methode, die sehr schnell ist und sich an verschiedene unregelmäßige Spriteformen anpasst. Es ist auf Formen beschränkt, die sich nicht selbst umbiegen. Es erfordert ein wenig Init-Code, aber der Kollisionstest ist viel schneller als jeder softwarebasierte Pixel-Kollisionstest, vergleichbar mit einer Kreis-Box-Kollision in der Performance – Blindman67

Antwort

1

einen „Flipper“ Unter der Annahme von zwei Bögen zusammengesetzt ist und 2 Linien wäre es viel schneller sein Kollisionserkennung zu tun, mathematisch und nicht durch die viel langsamere Pixel-Test-Methode. Dann brauchen Sie nur 4 mathematische Kollisionstests.

Auch wenn Ihre Flossen ein wenig komplizierter sind als Bögen + Linien, wären die Mathe-Hits "gut genug" - was bedeutet, dass Sie in Ihrem schnelllebigen Spiel die ungefähren mathematischen Ergebnisse im Vergleich zum Pixel nicht sehen können - Perfekte Ergebnisse und der Unterschied zwischen den beiden Arten von Tests wird das Gameplay überhaupt nicht beeinflussen. Aber die Pixel-Test-Version wird Größenordnungen mehr Zeit und Ressourcen benötigen, um zu erreichen. ;-)

ersten beiden Kreis-vs-Kreis Kollisionsprüfungen:

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

Dann zwei Kreis-vs-line-Segment Kollisionsprüfungen:

// [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

Dies ist eine gute Idee, aber leider ist eine der Anforderungen, ein Pixel zu machen -Kollisions-Ansatz, der mit allen Arten von Objekten zusammenarbeitet, aus denen der Pinball-Computer besteht. Tut mir leid, ich hätte das früher erwähnen sollen! –

+0

** Noch einmal versuchen ... ** Aber sind nicht alle Stoßfänger usw. aus Linien oder Bögen zusammengesetzt. Die Mathe-Tests sind genauso effektiv wie Pixel-Tests - vielleicht sogar noch mehr unter Berücksichtigung von Anti-Aliasing, das Pixel-Hit-Tests beeinflusst. – markE

+0

Wie kann ich das an ein Sprite anpassen? –