Organic cell-like motion with ofxBox2d?

hi all! trying to computationally understand my problem. i want to make this cell-like shape that shifts around organically, maybe something similar to metaballs?

right now, i’m using ofxbox2d and connecting ofxbox2d circles to each other with joints, and eventually connecting the last one to the first one to close the shape:

    for (unsigned int i = 0; i < circles.size(); i++)
    {
        auto joint = std::make_shared<ofxBox2dJoint>();
        
        if (i == 0)
        {
            joint.get()->setup(box2d.getWorld(), circles[circles.size()-1].get()->body, circles[i].get()->body);
        }
        else
        {
             joint.get()->setup(box2d.getWorld(), circles[i-1].get()->body, circles[i].get()->body);
        }
        
        joint.get()->setFrequency(4.0);
        joint.get()->setDamping(0.5);
        joint.get()->setLength(ofRandom(40, 74));
        joints.push_back(joint);
    }

this seems to work fine to me. i run into issues when trying to articulate the motion, however. i thought i’d be able to do it by adding a repulsive force to each circle that pushes it away from the circle that’s closest to it:

void ofApp::applyForce(std::vector<std::shared_ptr<ofxBox2dCircle> > circleVector)
{
    for (int i = 0; i < circles.size(); i++)
    {
        float minDistance = 50;
        int closestIndex;
        
        glm::vec2 currentPos;
        glm::vec2 closestPos;
        
        currentPos = glm::vec2(circles[i].get()->getPosition().x, circles[i].get()->getPosition().y);
        
        for (int j = 0; j < circleVector.size(); j++)
        {
            float distance;
            glm::vec2 otherPos;
            
            if (j != i)
            {
                otherPos = glm::vec2(circleVector[j].get()->getPosition().x, circleVector[j].get()->getPosition().y);
                
                distance = glm::distance(currentPos, otherPos);
                
                if (distance < minDistance)
                {
                    closestIndex = j;
                    minDistance = distance;
                }
            }
            
            // std::cout << minDistance << std::endl;
            float force = ofMap(minDistance, 0, 50, 0.5, 0.1);
            force = ofClamp(force, 0.1, 0.5);
            
            circles[i].get()->addRepulsionForce(otherPos, force);
        }
    }
    
}

but they all just push each other to the bounds and i end up with this:

i think intuitively i understand what’s happening – am also having trouble putting that into words – but i’m having a hard time figuring out how to translate the motion i want into code. would love to tap into everyone’s collective experience and help me navigate this issue :slight_smile:

I think it might be an issue with not having friction, or the ofClamp you’re using, it is limiting it to the lower bound of 0.1 which means it can’t roll of to zero.
(this is just from a quick glance over)

1 Like