2017-09-27 133 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 –