1

Ich habe dieses Problem beim Versuch, Kollisionen zwischen zwei Kugeln zu erkennen, wenn einer (oder beide) eine sehr hohe Geschwindigkeit haben. Ich denke, das ist ein sehr häufiges Problem und ich verstehe, warum es passiert. Meine Vermutung ist, dass die Lösung mit Derivaten zu tun haben wird, ich habe bereits etwas entworfen, aber ich möchte das Rad nicht neu erfinden, wenn es eine bekannte Lösung gibt.Kollisionserkennung schlägt fehl, wenn Geschwindigkeit zu hoch ist

Alles, was meinen Weg beleuchten kann, wird gelehrt!

Ich habe dieses sehr einfache Beispiel. Wenn beide Bälle eine Geschwindigkeit von sagen wir 1,5 oder 3 haben, kollidieren sie. Wenn wir etwas sehr viel verwenden, wie 50, wird es fehlschlagen.

<html> 
<head> 
    <title>Collision test</title> 
</head> 
<body> 

    <canvas id="canvas"></canvas> 

    <script> 

    const canvas = document.getElementById("canvas"); 
    const ctx = canvas.getContext("2d"); 
    const width = window.innerWidth; 
    const height = window.innerHeight-4; 
    const center = { x: width/2, y: height/2 }; 

    canvas.width = width; 
    canvas.height = height; 

    // Ball Class Definition 
    class Ball { 
     constructor(x, y, mass, direction, speed, color) { 
      this.x = x; 
      this.y = y; 
      this.vx = (Math.cos(direction) * speed) || 0; 
      this.vy = (Math.sin(direction) * speed) || 0; 
      this.mass = mass || 1; 
      this.radius = mass * 3; 
      this.color = color || "#000000"; 
     } 

     update() { 
      this.x += this.vx; 
      this.y += this.vy; 
     } 
    } 

    let speedA = 1.5; 
    let speedB = 1; 

    // Create two balls that will collide 
    let ballA = new Ball(center.x - 300, center.y, 3, Math.PI*2, speedA, "green"); 
    let ballB = new Ball(center.x + 100, center.y, 2.2, Math.PI, speedB, "green"); 


    // Main update/draw function 
    function draw() { 
     window.requestAnimationFrame(draw); 

     ctx.clearRect(0,0, width, height); 

     ballA.update(); 
     ballB.update(); 


     handleCollisions(ballA, ballB); 

     // Draw Ball A 
     ctx.beginPath(); 
     ctx.arc(ballA.x, ballA.y, ballA.radius, 0, Math.PI * 2, false); 
     ctx.fillStyle = ballA.color; 
     ctx.fill(); 

     // Draw Ball B 
     ctx.beginPath(); 
     ctx.arc(ballB.x, ballB.y, ballB.radius, 0, Math.PI * 2, false); 
     ctx.fillStyle = ballB.color; 
     ctx.fill(); 
    } 

    // Detect and handle collision 
    function handleCollisions(p1, p2) { 
     let xDist, yDist; 
     xDist = p1.x - p2.x; 
     yDist = p1.y - p2.y; 

     let distSquared = xDist*xDist + yDist*yDist; 

     //Check the squared distances instead of the the distances, same result, but avoids a square root. 
     if(distSquared <= (p1.radius + p2.radius)*(p1.radius + p2.radius)){ 
      let xVelocity = p2.vx - p1.vx; 
      let yVelocity = p2.vy - p1.vy; 
      let dotProduct = xDist*xVelocity + yDist*yVelocity; 

      //Neat vector maths, used for checking if the objects moves towards one another. 
      if(dotProduct > 0){ 
       let collisionScale = dotProduct/distSquared; 
       let xCollision = xDist * collisionScale; 
       let yCollision = yDist * collisionScale; 

       //The Collision vector is the speed difference projected on the Dist vector, 
       //thus it is the component of the speed difference needed for the collision. 
       let combinedMass = p1.mass + p2.mass; 
       let collisionWeightA = 2 * p2.mass/combinedMass; 
       let collisionWeightB = 2 * p1.mass/combinedMass; 
       p1.vx += collisionWeightA * xCollision; 
       p1.vy += collisionWeightA * yCollision; 
       p2.vx -= collisionWeightB * xCollision; 
       p2.vy -= collisionWeightB * yCollision; 
      } 
     } 

    } 

    draw(); 

    </script> 
</body> 
</html> 

Ich habe diese code zu JSBin hinzugefügt.

Antwort

1

Das Problem ist, dass die Kollisionserkennung mit dem Abstand zwischen den Positionen der Kugeln erfolgt, aber wenn sie sich zu schnell bewegen, dann können sie über einander "hüpfen" und für eine Kollision nie nah genug sein erkannt werden.

Eine Lösung könnte sein, Punkte für jeden Ball auf diesem Hop und ihre jeweiligen Zeiten zu berechnen. Vergleichen Sie dann die Liste der Punkte für jeden Ball und sehen Sie, ob es einen Zeitpunkt gibt, an dem die Bälle nahe genug für eine Kollision sind. Mit anderen Worten, interpolieren Sie ihre Positionen zwischen den Bildern und prüfen Sie die Kollision an diesen interpolierten Positionen. Sie müssen jedoch vorsichtig sein, denn obwohl die Bälle einen Punkt passieren können, der nahe genug für eine Kollision ist, müssen sie dies ungefähr zur gleichen Zeit tun.

Ich bin sicher, dass es Javascript-Frameworks oder Bibliotheken speziell für Spiele und Physik gibt, wenn Sie das nicht selbst übernehmen wollen. Ich habe noch nie mit ihnen zu tun gehabt, aber Google sollte es wissen.

1

Sie scheinen das Problem zu verstehen: Die diskrete Abtastung Ihrer Szene lässt Projektile mit hoher Geschwindigkeit durchkommen oder vermisst Objekte, die sie treffen sollten.

Der naive Weg, dies zu lösen, ist, Ihre Bildrate zu erhöhen. Dies wird am Ende unmöglich, denn je schneller das Projektil ist, desto mehr Frames müssen gemacht werden. Nicht empfohlen. Was Sie brauchen, ist einige kontinuierliche Kollisionserkennung Methode. Zum Beispiel verwendet Bullet dies und erfährt nicht das Problem, das Sie haben.

Die einfachste Sache, die ich denken kann, ist, einen Zylinder von current_position zu last_position mit dem gleichen Radius wie der Ball zu erstellen. Dann würde ich nach Kollisionen mit diesen Zylindern suchen. Dies würde einfache Fälle lösen, in denen ein Projektil ein stationäres Ziel trifft. Um Ziele zu bewegen, könnten Sie mit dem gleichen wie oben beginnen (das heißt, Sie würden Zylinder mit Zylindern vergleichen). Im Falle einer Kollision müssen Sie die Position der Kollisionsobjekte zum Zeitpunkt der Kollision neu berechnen und dann sehen, ob sie tatsächlich getroffen haben oder nicht.

Verwandte Themen