A guess: perhaps you are not replicating what IParticle.push() does correctly.
You are looping through cells and allowing them to push other cells outside their perimeter. However, that act allows them to push cells into another cell perimeter. If your loop order is stable, that will create at least one winner but potentially many losers in the get-out-of-my-perimeter game – the cells that get checked last in their neighborhood win, everyone else (potentially) loses.
I haven’t examined your reference, but brainstorming a few approaches to handle that might include (?):
-
walk from the root node (which pushes anything) down to level level 2 – these can’t push the root, but they can push anything else. Then level 3 – these can’t push anything from level 2 or the root. Since only peers and leaf nodes are pushable, overlaps should propagate out. That makes sense assuming you have a root node heirarchy, of course – if you have a mandala it doesn’t work.
-
Rather than setting something outside the perimeter as a response to the overlap, move it proportionate to the overlap – e.g. move it 0.2 of the overlap distance. This means that strong overlaps will produce more displacement force than weak overlaps. You might want to combine that kind of approach with:
-
shuffle the cells array before checking for interactions. If there is no stable voting order, there aren’t permanently weak and strong cells that can get stuck in stable bad configurations, so solutions are more likely. Keep in mind, if your springs are too strong then some configurations do not have non-overlapping solutions. To avoid those, you might need to:
-
only create a new node in place if there is available non-overlapping space for it – which might involve displacing all nodes to the left or right by x in order to make space at the insertion point, then allowing the springs to snap them back. In essence, this is an already-valid-compactor, rather than a fix-the-invalid expander. On no frame will there be overlap.