Как я могу добавить обнаружение столкновений в мой симулятор частиц d3js

#javascript #d3.js

#javascript #d3.js

Вопрос:

Я пытаюсь понять, как я мог бы добавить определение столкновения в мой симулятор частиц (разработанный на основе этой скрипки)

Смотрите мою текущую скрипку здесь

Я хотел бы обнаруживать только столкновение между частицами с классами reactantA и reactantB particles, и когда они сталкиваются, измените class на 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 amp;amp; particle.vy > 0) {
      particle.vy = particle.vy * -1;
    }
    if (particle.y < particle.r amp;amp; particle.vy < 0) {
      particle.vy = particle.vy * -1;
    }
    if (particle.x > gridSize - particle.r amp;amp; particle.vx > 0) {
      particle.vx = particle.vx * -1;
    }
    if (particle.x < particle.r amp;amp; 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();
});  

Комментарии:

1. Вы видели этот пример ?

2. Да, я видел это, но изо всех сил пытаюсь понять, как это реализовать. Есть какие-нибудь подсказки?

Ответ №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 amp;amp; particle.vy > 0) {
      particle.vy = particle.vy * -1;
    }
    if (particle.y < particle.r amp;amp; particle.vy < 0) {
      particle.vy = particle.vy * -1;
    }
    if (particle.x > gridSize - particle.r amp;amp; particle.vx > 0) {
      particle.vx = particle.vx * -1;
    }
    if (particle.x < particle.r amp;amp; 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" amp;amp; particle.type === "reactantB") ||
        (particle.type === "reactantA" amp;amp; 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";
        }
      }
    }
  }
};
  

Обновлена скрипка.

Теперь я называю это наивным, потому что в нем очень много перебора. Это двойной цикл, и он будет медленным по мере увеличения количества частиц. Это проблема, которую d3.quadtree стремится решить. Он разделяет пространство для оптимизации поиска. Вот отличное объяснение.

Там, где я нахожусь, уже немного поздно, надеюсь, завтра у меня будет немного времени, и я перекодирую это, используя d3.quadtree…

Комментарии:

1. Это потрясающе, это отлично подходит для моих целей. Я обновил свое моделирование, используя предложенный вами алгоритм столкновения: fiddle.jshell.net/mephisto73/Lw6589xf/7