我试图理解如何将碰撞反应添加到我的粒子模拟器(从this fiddle开发)
我只想检测具有reactantA和reactantB粒子类的粒子之间的碰撞,当它们碰撞时,将类更改为productC。但我不知道从哪里开始以有效的方式做到这一点。
// Basic control variables
var gridSize = 600; // The square size in pixels of the 2-d world
var numParticles = 150;
var epochTarget = 10;
var epochActual = 0;
var counter = 0;
var pType = 'reactantA';
var rx = 0;
var pRadius = 0;
var getXSpeed = function() {
// Returns a number from -25 to -1 or 1 to 25
return ((Math.random() > 0.5) ? -1 : 1) * ((Math.random() * 24) + 1);
};
var getYSpeed = function() {
// Returns a number from 25-100
return ((Math.random() * 75) - 50);
};
/*
*/
var particles = [];
for (var i = 0; i < numParticles; i++) {
pType = "reactantA";
pRadius = 8;
rx = Math.floor((Math.random() * 10) + 1);
if (rx > 5) {
pType = "reactantB";
pRadius = 5;
}
console.log(i, pType);
particles.push({
x: Math.floor(Math.random() * gridSize),
y: Math.floor(Math.random() * gridSize),
r: pRadius,
key: counter++,
type: pType,
vx: getXSpeed(),
vy: getYSpeed()
});
}
// Create the initial structure of the game board (using SVG rectangles)
var svg = d3.select("#container").append("svg")
.attr("height", gridSize)
.attr("width", gridSize)
.append("g");
// Redraw function is responsible for updating the state of the dom
var redraw = function(elapsed) {
// Bind the data to the particles
var particle = svg.selectAll("circle").data(particles, function(d) {
return d.key;
});
// Update
particle
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
// Enter
particle.enter().append("circle")
.attr("class", function(d) {
return d.type;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", function(d) {
return d.r;
});
particle.exit().remove();
};
/*
*/
var update = function(elapsed) {
for (var j = 0; j < particles.length; j++) {
var particle = particles[j];
particle.x = particle.x + (elapsed / 1000) * particle.vx;
particle.y = particle.y + (elapsed / 1000) * particle.vy;
if (particle.y > gridSize - particle.r && particle.vy > 0) {
particle.vy = particle.vy * -1;
}
if (particle.y < particle.r && particle.vy < 0) {
particle.vy = particle.vy * -1;
}
if (particle.x > gridSize - particle.r && particle.vx > 0) {
particle.vx = particle.vx * -1;
}
if (particle.x < particle.r && particle.vx < 0) {
particle.vx = particle.vx * -1;
}
/* Particle is done, so recreate it
if((particle.y > gridSize - 1) || (particle.x > gridSize - 1) || (particle.y < 1) || (particle.x < 1) ) {
particle.x = Math.floor(Math.random() * gridSize);
particle.y = Math.floor(Math.random() * ridSize);
particle.key = counter++;
particle.vx = getXSpeed();
particle.vy = getYSpeed();
}*/
}
};
/*
/ This function will orchestrate the main game loop, incrementing the
/ current epoch, calling update and then calling redraw for each epoch.
*/
var doEpoch = function() {
var dtg = new Date();
var elapsed = dtg.getTime() - epochActual;
update(elapsed);
redraw(elapsed);
epochActual = dtg.getTime();
window.setTimeout(doEpoch, epochTarget);
};
// Add the click handler to the start button
d3.select("#start").on('click', function(d) {
d3.select("#start").text("Running...");
var dtg = new Date();
epochActual = dtg.getTime();
doEpoch();
});
答案 0 :(得分:1)
所以这是解决问题的天真方法:
var update = function(elapsed) {
for (var j = 0; j < particles.length; j++) {
var particle = particles[j];
particle.x = particle.x + (elapsed / 1000) * particle.vx;
particle.y = particle.y + (elapsed / 1000) * particle.vy;
if (particle.y > gridSize - particle.r && particle.vy > 0) {
particle.vy = particle.vy * -1;
}
if (particle.y < particle.r && particle.vy < 0) {
particle.vy = particle.vy * -1;
}
if (particle.x > gridSize - particle.r && particle.vx > 0) {
particle.vx = particle.vx * -1;
}
if (particle.x < particle.r && particle.vx < 0) {
particle.vx = particle.vx * -1;
}
// loop other particles
for (var k = 0; k < particles.length; k++){
var detP = particles[k];
// if the other is different, check collision
if (
(detP.type === "reactantA" && particle.type === "reactantB") ||
(particle.type === "reactantA" && detP.type === "reactantB")
){
// l is the distance between two particles
var x = particle.x - detP.x,
y = particle.y - detP.y,
l = Math.sqrt(x * x + y * y);
// if distance is less then radius, we have collision
if (l < particle.r) {
particle.type = "reactantC";
detP.type = "reactantC";
}
}
}
}
};
更新了fiddle。
现在,我称之为天真,因为它非常强力循环。这是一个双循环,随着粒子数量的增加,它会变慢。这是d3.quadtree旨在解决的问题。它划分空间以优化搜索。这是一个很棒的explanation。
我现在有点晚了,希望我明天会有一些时间,我会用d3.quadtree重新编码...