Javascript 反弹粒子意外地重叠

Javascript 反弹粒子意外地重叠,javascript,d3.js,Javascript,D3.js,我已经在D3中生成了一组弹跳球。我已设法使系统按照以下规则工作: 球体应该慢慢地四处漂移 考虑到质量和动量,球体应该相互反弹 球体不应该离开SVG区域,因此应该从边缘反弹 我已经设法找到了一个问题,但是我不知道是什么导致了它,球体似乎不时地被卡住-一个节点会被另一个节点卡住,跟随它,而不是反弹离开,有时会落在另一个球体的下面或上面,我认为这是不可能的 重叠逻辑相当简单,如果两个球体中心之间的距离小于它们需要反弹的组合半径: // Calculate the distance between

我已经在D3中生成了一组弹跳球。我已设法使系统按照以下规则工作:

  • 球体应该慢慢地四处漂移
  • 考虑到质量和动量,球体应该相互反弹
  • 球体不应该离开SVG区域,因此应该从边缘反弹
我已经设法找到了一个问题,但是我不知道是什么导致了它,球体似乎不时地被卡住-一个节点会被另一个节点卡住,跟随它,而不是反弹离开,有时会落在另一个球体的下面或上面,我认为这是不可能的

重叠逻辑相当简单,如果两个球体中心之间的距离小于它们需要反弹的组合半径:

// Calculate the distance between the centres of 
// two nodes, we don't have take the square root
// as we don't need it, and it's an expensive operation
var x = d.x - quad.point.x;
var y = d.y - quad.point.y;
var distance = x * x + y * y;

// Calculate the radius of each to determine how
// close they need to be to be considered touching
var radii = getSize(d) + getSize(quad.point);

// If the nodes appear to be touching then we need to move the points
if (distance < (radii * radii)) {
    // Overlapping
}
//向字符串原型添加一个附加函数
if(!String.prototype.format){
String.prototype.format=函数(){
var args=参数;
返回此。替换(/{(\d+)}/g,函数(匹配,编号){
返回参数的类型[编号]!=“未定义”
?args[编号]
:匹配
;
});
};
}
d3.Orbs=函数(){
var宽度=500;
var高度=500;
var maxSpeed=10;
varα=0.026;
变量节点=[
{id:1,名称:“软件”,大小:5,儿童:[
{id:4,名称:“Bug”},
{id:5,名称:“Feature”},
{id:6,名称:“Build”}]
},
{id:2,名称:“Scrum”,大小:8,儿童:[
{id:7,名称:“Sprint”},
{id:8,名字:“故事”},
{id:9,名称:“故事点”}]
},
{id:3,名称:“资源”,大小:12,子项:[
{id:10,名称:“Location”},
{id:11,姓名:“团队”},
{id:12,姓名:“成员”}]
},
{id:13,名称:“A”,大小:12},
{id:14,名称:“B”,大小:9},
{id:15,名称:“C”,大小:3}
];
/**
*初始化数据集中的每个节点以确保
*数据中存在所需的位置和速度
*用于避免碰撞和应用重力
*@param{array}原始数据中的节点集合
*@param{object}用于限制节点放置位置的边框
*/
函数初始化_节点(节点、边界){
//确保每个节点都有一个随机的开始位置和速度
nodes.forEach(函数(d){
d、 x=Math.random()*bounds.right;
d、 y=Math.random()*bounds.bottom;
d、 speedX=(Math.random()-0.5)*2*maxSpeed;
d、 speedY=(Math.random()-0.5)*2*maxSpeed;
});
/*节点[0].x=100;
节点[0],y=100;
节点[0]。speedX=10;
节点[0]。速度=-10;
节点[0],大小=10;
节点[0]。填充='red';
节点[1],x=200;
节点[1],y=400;
节点[1]。speedX=-10;
节点[1],速度=40;
节点[1],大小=20;
节点[1]。填充='steelblue'*/
};
//现在初始化节点
初始化_节点(节点,{left:0,top:0,bottom:height,right:width});
var-force=d3.layout.force()
.阿尔法(阿尔法)
.重力(0)
.收费(0)
.节点(节点)
.尺寸([宽度、高度])
.在(“滴答”,滴答)上;
var svg=d3.选择(“主体”)
.append(“svg”)
.attr(“宽度”,500)
.attr(“高度”,500);
var node=svg.selectAll(“.node”)
.数据(节点)
.输入()
.附加(“圆圈”)
.attr(“类”、“节点”)
.style('fill',函数(d){return d.fill;})
.attr(“cx”,函数(d){return d.x;})
.attr(“cy”,函数(d){返回d.y;})
.attr(“r”,函数(d){return getSize(d);});
函数getSize(节点){
返回5*node.size;
}
/**
*返回将重力应用于单个节点的函数
*@param{number}系统中当前的α或动能
*@返回{function}将重力应用于每个节点的函数
*/
函数重力(α){
/**
*根据节点的当前位置更新节点的位置和速度
*@param{Object}正在移动的数据节点
*/
返回函数(d){
var半径=getSize(d);
//如果节点试图移出屏幕,则反转速度
//在那个轴上把它带回到范围内
如果((d.x-半径)<0)d.speedX=数学abs(d.speedX);
如果((d.x+半径)>宽度)d.speedX=-1*Math.abs(d.speedX);
如果((d.y-半径)<0)d.speedY=-1*Math.abs(d.speedY);
如果((d.y+半径)>高度)d.speedY=数学abs(d.speedY);
//设置节点的当前位置
d、 x=d.x+(d.x*alpha);
d、 y=d.y+(-1*d.y*alpha);
//应用一些额外的保护-如果节点已移出屏幕
//然后再把它拿回来,而不是等待它的速度
d、 x=数学最小值(数学最大值(d.x,0+半径),宽度-半径);
d、 y=数学最小值(数学最大值(直径,0+半径),高度-半径);
};
}
/**
*每当收到滴答声通知时,更新节点的位置
*从部队布局算法
*@param{object}D3勾选事件参数
*/
功能勾号(e){
//确保Alpha永远不会下降到0
//请注意,在移动设备上,这可能是一个大的电池消耗
力α(α);
//通过应用重力函数更新每个节点的位置
//以及防止节点发生任何冲突
每个节点(重力(.51*e.alpha))
.each(函数(d){d.color='#2B301C';})
.each(函数(d){d.bounced=d.bounced | |【】})
.每个(解决碰撞(0.5))
.attr(“cx”,函数(d){return d.x;})
.attr(“cy”,函数(d){返回d.y;})
.style(“笔划”,函数(d){return d.color | |'#2B301C'
function bounce_vectors(d1, d2) {

    // Calculate the angle at which the balls collide
    var dx = d1.x - d2.x;
    var dy = (d1.y - d2.y) * -1;
    var collisionAngle = Math.atan2(dy, dx);

    // Calculate the speed of d1/d2
    var speed1 = Math.sqrt((d1.speedX * d1.speedX) + (d1.speedY * d1.speedY));
    var speed2 = Math.sqrt((d2.speedX * d2.speedX) + (d2.speedY * d2.speedY));

    // Get angles (in radians) for each ball, given current velocities
    var direction1 = Math.atan2(d1.speedY, d1.speedX);
    var direction2 = Math.atan2(d2.speedY, d2.speedX);

    // Rotate velocity vectors so we can plug into equation for conservation of momentum
    var rotatedVelocityX1 = speed1 * Math.cos(direction1 - collisionAngle);
    var rotatedVelocityY1 = speed1 * Math.sin(direction1 - collisionAngle);
    var rotatedVelocityX2 = speed2 * Math.cos(direction2 - collisionAngle);
    var rotatedVelocityY2 = speed2 * Math.sin(direction2 - collisionAngle);        

  // Update actual velocities using conservation of momentum
    var finalVelocityX1 = ((d1.size - d2.size) * rotatedVelocityX1 + (d2.size + d2.size) * rotatedVelocityX2) / (d1.size + d2.size);
    var finalVelocityX2 = ((d1.size + d1.size) * rotatedVelocityX1 + (d2.size - d1.size) * rotatedVelocityX2) / (d1.size + d2.size);

    // Y velocities remain constant
    var finalVelocityY1 = rotatedVelocityY1;
    var finalVelocityY2 = rotatedVelocityY2;

    // Rotate angles back again so the collision angle is preserved
    d1.speedX = Math.cos(collisionAngle) * finalVelocityX1 + Math.cos(collisionAngle + Math.PI/2) * finalVelocityY1;
    d1.speedY = Math.sin(collisionAngle) * finalVelocityX1 + Math.sin(collisionAngle + Math.PI/2) * finalVelocityY1;
    d2.speedX = Math.cos(collisionAngle) * finalVelocityX2 + Math.cos(collisionAngle + Math.PI/2) * finalVelocityY2;
    d2.speedY = Math.sin(collisionAngle) * finalVelocityX2 + Math.sin(collisionAngle + Math.PI/2) * finalVelocityY2;
};