0
\$\begingroup\$

I just learned cocos2dx v3.3 integrated chipmunk physics engine.

Here ,as you see, I create a simple circle with physic as:

auto sprite = Sprite::create("circle.png");
auto body = PhysicsBody::createCircle(sprite->getContentSize().width / 2);
body->setContactTestBitmask(-1); //active collisions event 
sprite->setPhysicsBody(body);
sprite->setPosition(...);
this->addChild(sprite);

When I toggle this circle static/dynamic in normal situation everything work fine and when circle become static it stop in its position (as we expect gravity don't move it longer). here is a toggle code which works fine:

body->setDynamic(false);
scheduleOnce([=](float dt){body->setDynamic(true);},3,"Back to Dynamic Mode Timer");

PROBLEM BEGINS

But I want when the circle collide with something else ( in my case screen edge with is not important part of scenario), it become static then. so I use below code:

auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = [=](PhysicsContact &contact) -> bool 
{
    return true;
};
contactListener->onContactPostSolve = [=](PhysicsContact& contact, const PhysicsContactPostSolve& solve)
{
    contact.getShapeA()->getBody()->setDynamic(false); // ==> Cause Abort() !
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

But I just face a abort() message and game exit.

The call stack ( God bless it) show that the error is comming from line 300 in CCPhysicsBody.cpp:

if (_world != nullptr)
{
    cpSpaceRemoveBody(_world->_info->getSpace(), _info->getBody());
}
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I wonder if chopmunk allows the object to be made static inside a callback issued from the guts of the physics engine. What if you set a flag on the object and after updating physics you set things static? It would be worth checking the documentation on cpSpaceRemoveBody.

I looked into the source code for chipmunk, and here's the relevant function:

void
cpSpaceRemoveBody(cpSpace *space, cpBody *body)
{
        cpAssertWarn(cpSpaceContainsBody(space, body),
                "Cannot remove a body that was not added to the space. (Removed twice maybe?)");
        cpAssertSpaceUnlocked(space);

        cpBodyActivate(body);
        cpSpaceFilterArbiters(space, body, NULL);
        cpArrayDeleteObj(space->bodies, body);
        body->space = NULL;
}

From https://code.google.com/p/chipmunk-physics/source/browse/trunk/src/cpSpace.c

My guess is that it is dying because the space is not 'Unlocked'. You will have to queue it somehow to be changed from dynamic to static when it isn't locked.

I do not know if chipmunk has this facility. If not, just put the object in a list and right after the physics is stepped for the frame, run your list and change objects to static.

Update

In response to your feedback, I could not find a place where Chipmunk's addPostStepBlock is exposed to the library. I assume you have seen this page, and want to reproduce it's behavior:

https://www.makegameswith.us/gamernews/367/make-a-dynamic-body-static-in-cocos2d-30-with-chi

However, I did look at their wrapper class, and I wonder if you could do the following.

On contact, remove the object from the world. Set it to Static, and add it back. There are a series of functions that wait until the update is finished:

Internally, PhysicsWorld::AddBody() calls PhysicsWorld::addBodyOrDelay(). I wonder what would happen if you called PhysicsWorld::RemoveBody(), set it static, and then PhysicsWorld::AddBody(). Likely it will still blow up, but you can try.

Alternatively, since Cocos2dx is open source you could add methods to get access to the addPostStepBlock call inside chipmunk, but I can't help with that as I have never done it before.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for your answer and description. I vote it up because you helped me. But cant accept it as answer since my problem still exist. I temporary use your idea about converting static after some time, but it is not a stable solution and may cause problem in some case. \$\endgroup\$
    – Emadpres
    Commented Nov 19, 2014 at 8:11
  • \$\begingroup\$ Can you describe the stability problem you have? You can never fix the original issue; it is a limitation of the physics engine. \$\endgroup\$
    – Steven
    Commented Nov 19, 2014 at 15:57
  • \$\begingroup\$ I'm sorry but here there is a solution by using addPostStepBlock which is for cocso2d-iphone. I'm looking for something similar in cocos2dx \$\endgroup\$
    – Emadpres
    Commented Nov 19, 2014 at 16:20
0
\$\begingroup\$

If you only want to change the physicsBody to static, you can do this using cocos2d-x scheduleOnce with delay = 0.0f.

You might have to manually schedule the physics step but it should work in any case.

For instance, let's say you want to make shapeA static when a collision is detected:

bool HelloWorldScene::onContactBegin(PhysicsContact& contact)
{

    scheduleOnce([&](float dt)
    {
        contact->.getShapeA()->getBody()->setDynamic(false);
    }, 0.0f, "YourTag");
    return true;
}

And that's it.

\$\endgroup\$
1
  • \$\begingroup\$ thank you for your answer. the project is off now. but I will check your answer as the project continues. \$\endgroup\$
    – Emadpres
    Commented Apr 6, 2015 at 7:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .