Help Please: Sprite::SetPosition() does not seem to work in onContact callbacks for Chipmunk physics engine

Hi, I hope some one know the answer to this.

Does anyone have any idea why SetPosition for a sprite seems to be ignored in the Chipmonk physics engine collision callbacks, and how to change it’s position in the call backs?

I have a moving sprite.

When it is hit by a physics object (also a Sprite), I have callback listeners for onContactPreSolve, onContactBegin, and onContactSeparate. I can see Sprites colliding, and the callbacks get called.

However, in the callbacks I call SetPosition() for the sprite - but nothing happens, it keeps moving on its way with out going to the position. I have tried returning true and false from all the callbacks, just in case it made a difference.

I know the SetPosition() works in general, if I set it in my onMouseDown() callback it moves to the expected position when I click the mouse, and then continues on the vector of its travels (physic body’s velocity) just as expected.

In advance, thanks for any suggestions.

Follow-up:

I found a workaround, but it feels like a hack.
Instead of using SetPosition, I create a MoveTo action, with zero time.
This seems to do the job, but feels a bit cumbersome.

Example

auto action = cocos2d::MoveTo::create(0.0, cocos2d::Vec2(-Edge().getMinX(), 100));
_holes.at(0)->runAction(action);

Can you show any code for your first post? I use setPosition() but I am using the built-in physics engine.

Here you go @ slackmoehrle

Note interesting effect that IF SetPosition() is called using the MoveTo action also fails.

bool LairLichLordScene::onContactBegin(cocos2d::PhysicsContact& contact)
{
    cc::log("onContactBegin A:%i B:%i", contact.getShapeA()->getCategoryBitmask(), contact.getShapeB()->getCategoryBitmask());

    auto shapes = GetShapes(contact);

    if (ShapesAre(shapes, (int)EObjectFlag::hole, (int)EObjectFlag::player)) {
        PlayerFalling(true);
    }
    else if (ShapesAre(shapes, (int)EObjectFlag::edge, (int)EObjectFlag::hole)) {
        auto hole = static_cast<cc::Sprite*>(shapes.second->getBody()->getNode());
        auto pos = hole->getPosition();
        pos.x = Edge().getMinX();
        hole->setPosition(pos); // fails

        auto action = cocos2d::MoveTo::create(0.0, cocos2d::Vec2(pos)); // works, UNLESS setPosition() was also called in which case it fails (?)
        hole->runAction(action);     
    }

    return true;
}

Thanks. Let me ask engineering to have a look.

Hi, don’t set position on contact callback, try adding a delay. If the problem is still not solved, please provide a test project.

Why not set the postition of the body?

If there is a way (perhaps setPosition() or some pother position function) I am missing it
image

Which command are you suggesting I use for class Cocos2d::Physicsbody?

I guess I am somehow adding a delay doing it as an action, which is why that works

Is there some reason there has to be a delay?

EDIT: Solution: using an action rather than setting sprite position seems to work.

in contact process, physics engine lock the work status and ensuring the accuracy of physical calculations.

1 Like

Interesting, I did not know about locking. Thanks @huanxinyin.

I think that you already know how to solve it. You can use setPosition() in contact callbacks for other sprites that are not involved with physics in that moment. Just call a function outside the callback and do it inside this function

Yes, as I discovered a (workaround?) is to use an action to do it “outside” callback.
Marked issue as solved

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.