pirs
pirs

Reputation: 2463

How can I simulate gravity correctly in a bounded area?

I'm trying to do a container with balls inside, attracted to the floor like gravity. I'm close to doing it well but the balls eventually melt into each other then don't preserve their visibility.

See the demo here

I think the problem comes from the gravity function itself because the radius of each node isn't into account:

var gravity = function() {
    return function(d) {
        d.y += (d.cy - d.y);
        d.x += (d.cx - d.x);
    };
}

or from the bounding function in the simulation animation (tick), for the same problem above

d3.selectAll("circle.node")
  .attr("cx", function(d,i){ return Math.max(radius, Math.min(width - radius, d.x)); })
  .attr("cy", function(d,i){ return Math.max(radius, Math.min(height - radius, d.y)); });

How can I separate each ball distinctly in this case?

Edit: i found the solution i ll share it soon

Upvotes: 2

Views: 273

Answers (2)

pirs
pirs

Reputation: 2463

Ok, i finally read the docs and understood the problem !

See the demo here

All is about the collide between each node, to integrate it correctly in the forceSimulation, and the bound calculation in the tick function:

...


  // Change values below to modify the physic
  var simulation = d3.forceSimulation()
    .velocityDecay(0.3)
    .force("y", d3.forceY(height).strength(.035)) // gravity at bottom
    .force("collide", d3.forceCollide().radius(radius).strength(1.5).iterations(10))
    .nodes(nodes)
    .on('tick', tick);

  function tick() {
    // bound
    node.attr('cx', function(d) { return d.x = Math.max(radius, Math.min(width - radius, d.x)); })
        .attr('cy', function(d) { return d.y = Math.max(radius, Math.min(height - radius, d.y)); });
  }

Upvotes: 0

Felipe
Felipe

Reputation: 752

There's a library called planck.js. I know it has nothing to do with D3 but you can always check the code in order to get some inspiration.

Good luck!

Upvotes: 1

Related Questions