2017-09-27 70 views
3

由于某种原因,我的代码无法正常工作。它应该是一个碰撞模拟,但球只是粘在一起,我似乎无法弄清楚为什么。我一直在使用的公式从https://en.wikipedia.org/wiki/Elastic_collision#Two-dimensional_collision_with_two_moving_objects而据我可以看到我已经完全把它抄了,我甚至增加了支架,以确保操作的顺序是正确的,但仍然没有运气Javascript碰撞不起作用

这里是我的代码:

var canvas = document.getElementById("canvas"), 
 
    ctx = canvas.getContext("2d"); 
 

 
function Ball(){ 
 
    this.pos = { 
 
     "x": Math.random() * canvas.width, 
 
     "y": Math.random() * canvas.height 
 
    }; 
 
    this.vel = { 
 
     "x": Math.random() - 0.5, 
 
     "y": Math.random() - 0.5 
 
    }; 
 
    this.r = 16; 
 
    this.colliding = false; 
 
    this.m = 1; 
 
} 
 

 
function mag(v){ 
 
    return Math.sqrt((v.x * v.x) + (v.y * v.y)); 
 
} 
 

 
function dir(v){ 
 
    return Math.atan2(v.y, v.x); 
 
} 
 

 
function dist(a, b){ 
 
    var dx = b.x - a.x, 
 
     dy = b.y - a.y; 
 
    return Math.sqrt(dx * dx + dy * dy); 
 
} 
 

 
var balls = []; 
 
for(var i = 0; i < 10; i++){ 
 
    balls.push(new Ball()); 
 
} 
 

 
setInterval(function(){ 
 
    for(var i = 0; i < balls.length; i++){ 
 
     balls[i].pos.x += balls[i].vel.x; 
 
     balls[i].pos.y += balls[i].vel.y; 
 

 
     if(balls[i].pos.x + balls[i].r > canvas.width){ 
 
      balls[i].pos.x = canvas.width - balls[i].r; 
 
      balls[i].vel.x *= -1; 
 
     } 
 
     if(balls[i].pos.x < balls[i].r){ 
 
      balls[i].pos.x = balls[i].r; 
 
      balls[i].vel.x *= -1; 
 
     } 
 
     if(balls[i].pos.y + balls[i].r > canvas.height){ 
 
      balls[i].pos.y = canvas.height - balls[i].r; 
 
      balls[i].vel.y *= -1; 
 
     } 
 
     if(balls[i].pos.y < balls[i].r){ 
 
      balls[i].pos.y = balls[i].r; 
 
      balls[i].vel.y *= -1; 
 
     } 
 

 
     balls[i].colliding = false; 
 
    } 
 

 
    for(var i = 0; i < balls.length; i++){ 
 
     for(var j = i + 1; j < balls.length; j++){ 
 
      if(mag(balls[i].vel) < 0){ 
 
       break; 
 
      } 
 

 
      if(dist(balls[i].pos, balls[j].pos) < balls[i].r + balls[j].r){ 
 
       balls[i].colliding = true; 
 

 
       var contact = Math.atan2(balls[j].pos.y - balls[i].pos.y, balls[j].pos.x - balls[i].pos.x); 
 

 
       balls[i].vel.x = ((((mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact) * (balls[i].m - balls[j].m)) + (2 * balls[j].m * mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact)))/(balls[i].m + balls[j].m)) * Math.cos(contact)) + (mag(balls[i].vel) * Math.sin(dir(balls[i].vel) - contact) * Math.cos(contact + (Math.PI/2))); 
 
       balls[i].vel.y = ((((mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact) * (balls[i].m - balls[j].m)) + (2 * balls[j].m * mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact)))/(balls[i].m + balls[j].m)) * Math.sin(contact)) + (mag(balls[i].vel) * Math.sin(dir(balls[i].vel) - contact) * Math.sin(contact + (Math.PI/2))); 
 

 
       balls[j].vel.x = ((((mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact) * (balls[j].m - balls[i].m)) + (2 * balls[i].m * mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact)))/(balls[j].m + balls[i].m)) * Math.cos(contact)) + (mag(balls[j].vel) * Math.sin(dir(balls[j].vel) - contact) * Math.cos(contact + (Math.PI/2))); 
 
       balls[j].vel.y = ((((mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact) * (balls[j].m - balls[i].m)) + (2 * balls[i].m * mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact)))/(balls[j].m + balls[i].m)) * Math.sin(contact)) + (mag(balls[j].vel) * Math.sin(dir(balls[j].vel) - contact) * Math.sin(contact + (Math.PI/2))); 
 
      } 
 
     } 
 
    } 
 

 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 
    for(var i = 0; i < balls.length; i++){ 
 
     ctx.beginPath(); 
 

 
     if(balls[i].colliding){ 
 
      ctx.fillStyle = "#f00"; 
 
     }else{ 
 
      ctx.fillStyle = "#0f0"; 
 
     } 
 

 

 
     ctx.arc(balls[i].pos.x, balls[i].pos.y, balls[i].r, 0, 2 * Math.PI); 
 
     ctx.fill(); 
 
    } 
 
}, 16);
<!DOCTYPE html> 
 
<html lang="en"> 
 
    <head> 
 
     <meta charset="utf-8"> 
 
     <title></title> 
 
    </head> 
 
    <body> 
 
     <canvas id="canvas" width="640" height="480"></canvas> 
 
     <script src="main.js"></script> 
 
    </body> 
 
</html>

+0

@TJCrowder我一直在使用Math.sqrt也试过,都没有区别 –

+2

@TJCrowder添加片段(顺便说一句感谢,不知道我能做到这一点:)) –

回答

0

对于初学者来说,我倒了碰撞球j中的新velX和velY,和你的碰撞系统似乎工作得很好。然而,如果你仔细观察,你会注意到它们像你刚才提到的那样卡住了,这是因为这些球可以在每个嘀嗒声中行进超过一个像素,导致球在另一个内部传播,因此碰撞会一直反复,直到它们不在里面。为防止这种情况发生,如果距离小于组合半径,则需要调整velX和velY。

var canvas = document.getElementById("canvas"), 
 
    ctx = canvas.getContext("2d"); 
 

 
function Ball(){ 
 
    this.pos = { 
 
     "x": Math.random() * canvas.width, 
 
     "y": Math.random() * canvas.height 
 
    }; 
 
    this.vel = { 
 
     "x": Math.random() - 0.5, 
 
     "y": Math.random() - 0.5 
 
    }; 
 
    this.r = 16; 
 
    this.colliding = false; 
 
    this.m = 1; 
 
} 
 

 
function mag(v){ 
 
    return Math.sqrt((v.x * v.x) + (v.y * v.y)); 
 
} 
 

 
function dir(v){ 
 
    return Math.atan2(v.y, v.x); 
 
} 
 

 
function dist(a, b){ 
 
    var dx = b.x - a.x, 
 
     dy = b.y - a.y; 
 
    return Math.sqrt(dx * dx + dy * dy); 
 
} 
 

 
var balls = []; 
 
for(var i = 0; i < 10; i++){ 
 
    balls.push(new Ball()); 
 
} 
 

 
setInterval(function(){ 
 
    for(var i = 0; i < balls.length; i++){ 
 
     balls[i].pos.x += balls[i].vel.x; 
 
     balls[i].pos.y += balls[i].vel.y; 
 

 
     if(balls[i].pos.x + balls[i].r > canvas.width){ 
 
      balls[i].pos.x = canvas.width - balls[i].r; 
 
      balls[i].vel.x *= -1; 
 
     } 
 
     if(balls[i].pos.x < balls[i].r){ 
 
      balls[i].pos.x = balls[i].r; 
 
      balls[i].vel.x *= -1; 
 
     } 
 
     if(balls[i].pos.y + balls[i].r > canvas.height){ 
 
      balls[i].pos.y = canvas.height - balls[i].r; 
 
      balls[i].vel.y *= -1; 
 
     } 
 
     if(balls[i].pos.y < balls[i].r){ 
 
      balls[i].pos.y = balls[i].r; 
 
      balls[i].vel.y *= -1; 
 
     } 
 

 
     balls[i].colliding = false; 
 
    } 
 

 
    for(var i = 0; i < balls.length; i++){ 
 
     for(var j = i + 1; j < balls.length; j++){ 
 
      if(mag(balls[i].vel) < 0){ 
 
       break; 
 
      } 
 

 
      if(dist(balls[i].pos, balls[j].pos) < balls[i].r + balls[j].r){ 
 
       balls[i].colliding = true; 
 

 
       var contact = Math.atan2(balls[j].pos.y - balls[i].pos.y, balls[j].pos.x - balls[i].pos.x); 
 

 
       balls[i].vel.x = ((((mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact) * (balls[i].m - balls[j].m)) + (2 * balls[j].m * mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact)))/(balls[i].m + balls[j].m)) * Math.cos(contact)) + (mag(balls[i].vel) * Math.sin(dir(balls[i].vel) - contact) * Math.cos(contact + (Math.PI/2))); 
 
       balls[i].vel.y = ((((mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact) * (balls[i].m - balls[j].m)) + (2 * balls[j].m * mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact)))/(balls[i].m + balls[j].m)) * Math.sin(contact)) + (mag(balls[i].vel) * Math.sin(dir(balls[i].vel) - contact) * Math.sin(contact + (Math.PI/2))); 
 

 
       balls[j].vel.x = -((((mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact) * (balls[j].m - balls[i].m)) + (2 * balls[i].m * mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact)))/(balls[j].m + balls[i].m)) * Math.cos(contact)) + (mag(balls[j].vel) * Math.sin(dir(balls[j].vel) - contact) * Math.cos(contact + (Math.PI/2))); 
 
       balls[j].vel.y = -((((mag(balls[j].vel) * Math.cos(dir(balls[j].vel) - contact) * (balls[j].m - balls[i].m)) + (2 * balls[i].m * mag(balls[i].vel) * Math.cos(dir(balls[i].vel) - contact)))/(balls[j].m + balls[i].m)) * Math.sin(contact)) + (mag(balls[j].vel) * Math.sin(dir(balls[j].vel) - contact) * Math.sin(contact + (Math.PI/2))); 
 
      } 
 
     } 
 
    } 
 

 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 
    for(var i = 0; i < balls.length; i++){ 
 
     ctx.beginPath(); 
 

 
     if(balls[i].colliding){ 
 
      ctx.fillStyle = "#f00"; 
 
     }else{ 
 
      ctx.fillStyle = "#0f0"; 
 
     } 
 

 

 
     ctx.arc(balls[i].pos.x, balls[i].pos.y, balls[i].r, 0, 2 * Math.PI); 
 
     ctx.fill(); 
 
    } 
 
}, 16);
<!DOCTYPE html> 
 
<html lang="en"> 
 
    <head> 
 
     <meta charset="utf-8"> 
 
     <title></title> 
 
    </head> 
 
    <body> 
 
     <canvas id="canvas" width="640" height="480"></canvas> 
 
     <script src="main.js"></script> 
 
    </body> 
 
</html>

+0

性能也是,我建议你看看原型。如果你想要一些实际使用的例子,请查看这里的游戏来源 - asteroidio.bitballoon.com –